diff options
| author | Rodolfo Carvalho <rhcarvalho@gmail.com> | 2017-01-13 10:06:40 +0100 | 
|---|---|---|
| committer | Rodolfo Carvalho <rhcarvalho@gmail.com> | 2017-01-13 16:59:31 +0100 | 
| commit | 43b22a73c43d8975403994b5f085735e1d3786ba (patch) | |
| tree | 696337ac9b7f1ba7bbee4c47b7ec21b1d777f400 /roles/openshift_preflight/base | |
| parent | ac4db698d82d405f3b213f222ae22f62213af000 (diff) | |
Move Python modules into role
Allow reuse via role dependency.
Diffstat (limited to 'roles/openshift_preflight/base')
| -rwxr-xr-x | roles/openshift_preflight/base/library/aos_version.py | 100 | ||||
| -rwxr-xr-x | roles/openshift_preflight/base/library/check_yum_update.py | 116 | 
2 files changed, 216 insertions, 0 deletions
diff --git a/roles/openshift_preflight/base/library/aos_version.py b/roles/openshift_preflight/base/library/aos_version.py new file mode 100755 index 000000000..f7fcb6da5 --- /dev/null +++ b/roles/openshift_preflight/base/library/aos_version.py @@ -0,0 +1,100 @@ +#!/usr/bin/python +# vim: expandtab:tabstop=4:shiftwidth=4 +''' +An ansible module for determining if more than one minor version +of any atomic-openshift package is available, which would indicate +that multiple repos are enabled for different versions of the same +thing which may cause problems. + +Also, determine if the version requested is available down to the +precision requested. +''' + +# import os +# import sys +import yum  # pylint: disable=import-error +from ansible.module_utils.basic import AnsibleModule + + +def main():  # pylint: disable=missing-docstring +    module = AnsibleModule( +        argument_spec=dict( +            version=dict(required=True) +        ), +        supports_check_mode=True +    ) + +    # NOTE(rhcarvalho): sosiouxme added _unmute, but I couldn't find a case yet +    # for when it is actually necessary. Leaving it commented out for now, +    # though this comment and the commented out code related to _unmute should +    # be deleted later if not proven necessary. + +    # sys.stdout = os.devnull  # mute yum so it doesn't break our output +    # sys.stderr = os.devnull  # mute yum so it doesn't break our output + +    # def _unmute():  # pylint: disable=missing-docstring +    #     sys.stdout = sys.__stdout__ + +    def bail(error):  # pylint: disable=missing-docstring +        # _unmute() +        module.fail_json(msg=error) + +    yb = yum.YumBase()  # pylint: disable=invalid-name + +    # search for package versions available for aos pkgs +    expected_pkgs = [ +        'atomic-openshift', +        'atomic-openshift-master', +        'atomic-openshift-node', +    ] +    try: +        pkgs = yb.pkgSack.returnPackages(patterns=expected_pkgs) +    except yum.Errors.PackageSackError as e:  # pylint: disable=invalid-name +        # you only hit this if *none* of the packages are available +        bail('Unable to find any atomic-openshift packages. \nCheck your subscription and repo settings. \n%s' % e) + +    # determine what level of precision we're expecting for the version +    expected_version = module.params['version'] +    if expected_version.startswith('v'):  # v3.3 => 3.3 +        expected_version = expected_version[1:] +    num_dots = expected_version.count('.') + +    pkgs_by_name_version = {} +    pkgs_precise_version_found = {} +    for pkg in pkgs: +        # get expected version precision +        match_version = '.'.join(pkg.version.split('.')[:num_dots + 1]) +        if match_version == expected_version: +            pkgs_precise_version_found[pkg.name] = True +        # get x.y version precision +        minor_version = '.'.join(pkg.version.split('.')[:2]) +        if pkg.name not in pkgs_by_name_version: +            pkgs_by_name_version[pkg.name] = {} +        pkgs_by_name_version[pkg.name][minor_version] = True + +    # see if any packages couldn't be found at requested version +    # see if any packages are available in more than one minor version +    not_found = [] +    multi_found = [] +    for name in expected_pkgs: +        if name not in pkgs_precise_version_found: +            not_found.append(name) +        if name in pkgs_by_name_version and len(pkgs_by_name_version[name]) > 1: +            multi_found.append(name) +    if not_found: +        msg = 'Not all of the required packages are available at requested version %s:\n' % expected_version +        for name in not_found: +            msg += '  %s\n' % name +        bail(msg + 'Please check your subscriptions and enabled repositories.') +    if multi_found: +        msg = 'Multiple minor versions of these packages are available\n' +        for name in multi_found: +            msg += '  %s\n' % name +        bail(msg + "There should only be one OpenShift version's repository enabled at a time.") + +    # _unmute() +    module.exit_json(changed=False) + + +if __name__ == '__main__': +    main() diff --git a/roles/openshift_preflight/base/library/check_yum_update.py b/roles/openshift_preflight/base/library/check_yum_update.py new file mode 100755 index 000000000..296ebd44f --- /dev/null +++ b/roles/openshift_preflight/base/library/check_yum_update.py @@ -0,0 +1,116 @@ +#!/usr/bin/python +# vim: expandtab:tabstop=4:shiftwidth=4 +''' +Ansible module to test whether a yum update or install will succeed, +without actually performing it or running yum. +parameters: +  packages: (optional) A list of package names to install or update. +            If omitted, all installed RPMs are considered for updates. +''' + +# import os +import sys +import yum  # pylint: disable=import-error +from ansible.module_utils.basic import AnsibleModule + + +def main():  # pylint: disable=missing-docstring,too-many-branches +    module = AnsibleModule( +        argument_spec=dict( +            packages=dict(type='list', default=[]) +        ), +        supports_check_mode=True +    ) + +    # NOTE(rhcarvalho): sosiouxme added _unmute, but I couldn't find a case yet +    # for when it is actually necessary. Leaving it commented out for now, +    # though this comment and the commented out code related to _unmute should +    # be deleted later if not proven necessary. + +    # sys.stdout = os.devnull  # mute yum so it doesn't break our output + +    # def _unmute():  # pylint: disable=missing-docstring +    #     sys.stdout = sys.__stdout__ + +    def bail(error):  # pylint: disable=missing-docstring +        # _unmute() +        module.fail_json(msg=error) + +    yb = yum.YumBase()  # pylint: disable=invalid-name +    # determine if the existing yum configuration is valid +    try: +        yb.repos.populateSack(mdtype='metadata', cacheonly=1) +    # for error of type: +    #   1. can't reach the repo URL(s) +    except yum.Errors.NoMoreMirrorsRepoError as e:  # pylint: disable=invalid-name +        bail('Error getting data from at least one yum repository: %s' % e) +    #   2. invalid repo definition +    except yum.Errors.RepoError as e:  # pylint: disable=invalid-name +        bail('Error with yum repository configuration: %s' % e) +    #   3. other/unknown +    #    * just report the problem verbatim +    except:  # pylint: disable=bare-except; # noqa +        bail('Unexpected error with yum repository: %s' % sys.exc_info()[1]) + +    packages = module.params['packages'] +    no_such_pkg = [] +    for pkg in packages: +        try: +            yb.install(name=pkg) +        except yum.Errors.InstallError as e:  # pylint: disable=invalid-name +            no_such_pkg.append(pkg) +        except:  # pylint: disable=bare-except; # noqa +            bail('Unexpected error with yum install/update: %s' % +                 sys.exc_info()[1]) +    if not packages: +        # no packages requested means test a yum update of everything +        yb.update() +    elif no_such_pkg: +        # wanted specific packages to install but some aren't available +        user_msg = 'Cannot install all of the necessary packages. Unavailable:\n' +        for pkg in no_such_pkg: +            user_msg += '  %s\n' % pkg +        user_msg += 'You may need to enable one or more yum repositories to make this content available.' +        bail(user_msg) + +    try: +        txn_result, txn_msgs = yb.buildTransaction() +    except:  # pylint: disable=bare-except; # noqa +        bail('Unexpected error during dependency resolution for yum update: \n %s' % +             sys.exc_info()[1]) + +    # find out if there are any errors with the update/install +    if txn_result == 0:  # 'normal exit' meaning there's nothing to install/update +        pass +    elif txn_result == 1:  # error with transaction +        user_msg = 'Could not perform a yum update.\n' +        if len(txn_msgs) > 0: +            user_msg += 'Errors from dependency resolution:\n' +            for msg in txn_msgs: +                user_msg += '  %s\n' % msg +            user_msg += 'You should resolve these issues before proceeding with an install.\n' +            user_msg += 'You may need to remove or downgrade packages or enable/disable yum repositories.' +        bail(user_msg) +    # TODO: it would be nice depending on the problem: +    #   1. dependency for update not found +    #    * construct the dependency tree +    #    * find the installed package(s) that required the missing dep +    #    * determine if any of these packages matter to openshift +    #    * build helpful error output +    #   2. conflicts among packages in available content +    #    * analyze dependency tree and build helpful error output +    #   3. other/unknown +    #    * report the problem verbatim +    #    * add to this list as we come across problems we can clearly diagnose +    elif txn_result == 2:  # everything resolved fine +        pass +    else: +        bail('Unknown error(s) from dependency resolution. Exit Code: %d:\n%s' % +             (txn_result, txn_msgs)) + +    # _unmute() +    module.exit_json(changed=False) + + +if __name__ == '__main__': +    main()  | 
