Merge "Add tripleo_ovs_upgrade module."
This commit is contained in:
commit
01b48fa753
|
@ -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()
|
Loading…
Reference in New Issue