Merge "Add tripleo_ovs_upgrade module."

This commit is contained in:
Zuul 2020-07-29 19:27:38 +00:00 committed by Gerrit Code Review
commit 01b48fa753
1 changed files with 250 additions and 0 deletions

View File

@ -0,0 +1,250 @@
#!/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.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 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):
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()