3220e4e5e3
We need to add OpenFlow10 to the required protocols to support backwards compatibility with neutron's destroy_patch_ports. Closes-Bug: #1892491 Change-Id: I6865787f4d0b0459ac2eb91c0f1da9c08b36dd8d
268 lines
8.3 KiB
Python
268 lines
8.3 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright 2020 Red Hat, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
__metaclass__ = type
|
|
|
|
import glob
|
|
import re
|
|
|
|
from ansible.module_utils._text import to_native
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
ANSIBLE_METADATA = {
|
|
'metadata_version': '1.1',
|
|
'status': ['preview'],
|
|
'supported_by': 'community'
|
|
}
|
|
|
|
DOCUMENTATION = """
|
|
---
|
|
module: tripleo_ovs_update
|
|
author:
|
|
- Sofer Athlan-Guyot <sathlang@redhat.com>
|
|
version_added: '2.8'
|
|
short_description: Handle special ovs update.
|
|
notes: []
|
|
description:
|
|
- This module check if ovs need a special treatment during update of the
|
|
package.
|
|
options:
|
|
debug:
|
|
description:
|
|
- Whether or not debug is enabled.
|
|
default: False
|
|
required: False
|
|
type: bool
|
|
"""
|
|
|
|
EXAMPLES = """
|
|
- name: Special treatment for ovs upgrade.
|
|
tripleo_ovs_upgrade:
|
|
"""
|
|
|
|
RETURN = """
|
|
msg:
|
|
description: Descrption of the action taken.
|
|
returned: always
|
|
type: str
|
|
changed:
|
|
description: Was the ovs package update or not.
|
|
returned: always
|
|
type: bool
|
|
"""
|
|
|
|
|
|
def pkg_manager(module, downloader=False):
|
|
dnf = module.get_bin_path('dnf')
|
|
if dnf:
|
|
module.debug("Using dnf as package manager")
|
|
if not downloader:
|
|
return dnf
|
|
else:
|
|
return ['dnf', 'download']
|
|
if not downloader:
|
|
return module.get_bin_path('yum')
|
|
else:
|
|
return ['yumdownloader']
|
|
|
|
|
|
# Get current OpenvSwitch package name
|
|
# return stuff like openvswitch2.11 in original yaml.
|
|
def get_current_ovs_pkg_name(module):
|
|
cmd = ['rpm', '-qa']
|
|
_, output, _ = module.run_command(cmd, check_rc=True)
|
|
ovs_re = re.compile(r"""
|
|
^(openvswitch[0-9]+\.[0-9]+-[0-9]+\.[0-9]+\.[0-9]+ # layered
|
|
| # or
|
|
openvswitch-2) # non-layered
|
|
""", re.X)
|
|
for pkg in output.split("\n"):
|
|
ovs = re.search(ovs_re, pkg)
|
|
if ovs:
|
|
return ovs.group(0)
|
|
return None
|
|
|
|
|
|
# Process rhosp-openvswitch layered package for new version number
|
|
# return stuff like ["2.11"] in original module
|
|
def get_version(module, pkg, new=True):
|
|
if new:
|
|
cmd = [pkg_manager(module), 'info', '-q', pkg]
|
|
else:
|
|
cmd = ['rpm', '-qi', pkg]
|
|
# This may fail if the package is not around for non-lp product.
|
|
_, output, _ = module.run_command(cmd, check_rc=False)
|
|
versions = re.findall(r'Version[^:]*:[^0-9]*([0-9.]+)', output)
|
|
found = []
|
|
for version in versions:
|
|
if version:
|
|
# we are only interested in major/minor number here.
|
|
if new:
|
|
# We can have several version here
|
|
found.append(version.split('.')[:2])
|
|
else:
|
|
found = version.split('.')[:2]
|
|
return found
|
|
|
|
|
|
def flatten_version(versions, join_str=''):
|
|
flatten_str = ""
|
|
if not isinstance(versions, list):
|
|
versions = [versions]
|
|
if isinstance(versions[0], list):
|
|
for version in versions:
|
|
flatten_str += join_str.join(version)
|
|
else:
|
|
flatten_str += join_str.join(versions)
|
|
return flatten_str
|
|
|
|
|
|
def get_current_ovs_pkg_names(module, pkg):
|
|
cmd = ['rpm', '-qa', pkg]
|
|
_, output, _ = module.run_command(cmd, check_rc=True)
|
|
# Make sure we remove empty element.
|
|
return [pkg for pkg in output.split("\n") if pkg]
|
|
|
|
|
|
def remove_package_noaction(module, pkgs, excludes=[]):
|
|
cmd = ['rpm', '-e', '--noscripts', '--nopreun',
|
|
'--nopostun', '--notriggers', '--nodeps']
|
|
pkgs_to_remove = []
|
|
for pkg in pkgs:
|
|
for exclude in excludes:
|
|
if not re.match(r'{}'.format(exclude), pkg):
|
|
pkgs_to_remove.append(pkg)
|
|
_, output, _ = module.run_command(cmd + pkgs_to_remove, check_rc=True)
|
|
return output
|
|
|
|
|
|
def upgrade_pkg(module, pkg):
|
|
cmd = [pkg_manager(module), 'upgrade', '-y', pkg]
|
|
_, output, _ = module.run_command(cmd, check_rc=True)
|
|
return output
|
|
|
|
|
|
def set_openflow_version_on_bridges(module, bridges=None):
|
|
if bridges is None:
|
|
bridges = ['br-int']
|
|
for bridge in bridges:
|
|
cmd = ['ovs-vsctl', 'set', 'bridge', bridge,
|
|
'protocols=OpenFlow10,OpenFlow13,OpenFlow15']
|
|
rc, out, err = module.run_command(cmd)
|
|
if rc != 0:
|
|
module.warn('Cannot set new OpenFlow protocols on a bridge: '
|
|
'%s: %s.' %
|
|
(bridge, to_native(err)))
|
|
|
|
|
|
def layer_product_upgrade(module, result, ovs_pkg, lp_ovs_current_version):
|
|
lp_ovs_coming_versions = get_version(module, 'rhosp-openvswitch')
|
|
ovs_current_version = get_version(module, ovs_pkg, new=False)
|
|
|
|
pkg_suffix = ''
|
|
if int(ovs_current_version[0]) >= 3 or int(ovs_current_version[1]) >= 10:
|
|
pkg_suffix = '.'.join(ovs_current_version)
|
|
|
|
pkg_base_name = 'openvswitch{}*'.format(pkg_suffix)
|
|
|
|
if flatten_version(lp_ovs_coming_versions) \
|
|
!= flatten_version(ovs_current_version):
|
|
# NOTE(mjozefcz): Workaround for bz1863024.
|
|
if '2.11' == flatten_version(ovs_current_version, join_str='.'):
|
|
set_openflow_version_on_bridges(module)
|
|
ovs_pkgs = get_current_ovs_pkg_names(module, pkg_base_name)
|
|
remove_package_noaction(module, ovs_pkgs,
|
|
excludes=['selinux'])
|
|
upgraded = upgrade_pkg(module, 'rhosp-openvswitch')
|
|
result['msg'] += \
|
|
""" Layer product update workaround applied for {} \
|
|
Upgraded:'{}'""".format(ovs_pkgs, upgraded)
|
|
result['changed'] = True
|
|
else:
|
|
result['msg'] += " No need to upgrade ovs."
|
|
|
|
|
|
def pkg_has_restart(module):
|
|
cmd = """rpm -q --scripts openvswitch | \\
|
|
awk '/postuninstall/,/*/' | \\
|
|
grep -q 'systemctl.*try-restart'"""
|
|
rc, _, _ = module.run_command(cmd, check_rc=False,
|
|
use_unsafe_shell=True)
|
|
|
|
return rc == 0
|
|
|
|
|
|
def upgrade_non_layered_ovs(module, result):
|
|
tmp_dir = '/root/OVS_UPGRADE'
|
|
cmds = [
|
|
['rm', '-rf', tmp_dir],
|
|
['install', '-d', '-o', 'root', '-g', 'root', '-m', '0750', tmp_dir],
|
|
[pkg_manager(module), 'makecache'],
|
|
pkg_manager(module, downloader=True)
|
|
+ ['--destdir', tmp_dir, '--resolve', 'openvswitch']]
|
|
for cmd in cmds:
|
|
module.run_command(cmd, check_rc=True)
|
|
|
|
for pkg in glob.glob(tmp_dir + '/*.rpm'):
|
|
cmd = ['rpm', '-U',
|
|
'--replacepkgs',
|
|
'--notriggerun',
|
|
'--nopostun',
|
|
pkg]
|
|
module.run_command(cmd, check_rc=True)
|
|
result['msg'] += " {} handled".format(pkg)
|
|
result['changed'] = True
|
|
|
|
|
|
def non_layered_ovs_upgrade(module, result):
|
|
if not pkg_has_restart(module):
|
|
result['msg'] += 'Nothing to be done for non layered ovs upgrade, ' \
|
|
"post-script doesn't have restart."
|
|
else:
|
|
result['msg'] += "OVS upgrade special handling."
|
|
upgrade_non_layered_ovs(module, result)
|
|
|
|
|
|
def main():
|
|
module = AnsibleModule(argument_spec={}, supports_check_mode=False)
|
|
|
|
result = dict(
|
|
changed=False,
|
|
msg=''
|
|
)
|
|
|
|
ovs_current_pkg = get_current_ovs_pkg_name(module)
|
|
if ovs_current_pkg:
|
|
# We found a ovs package, let's dive in.
|
|
ovs_current_version = get_version(module,
|
|
'rhosp-openvswitch',
|
|
new=False)
|
|
if ovs_current_version:
|
|
result['msg'] += "Found a layered product ovs. "
|
|
layer_product_upgrade(module, result,
|
|
ovs_current_pkg, ovs_current_version)
|
|
else:
|
|
result['msg'] += "Found ovs. "
|
|
non_layered_ovs_upgrade(module, result)
|
|
else:
|
|
result['msg'] += "No ovs installed, nothing to do."
|
|
|
|
module.exit_json(**result)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|