diff options
Diffstat (limited to 'roles')
| -rw-r--r-- | roles/lib_openshift/src/sources.yml | 7 | ||||
| -rwxr-xr-x | roles/lib_openshift/src/test/unit/oc_secret.py | 2 | ||||
| -rw-r--r-- | roles/lib_utils/library/repoquery.py | 607 | ||||
| -rw-r--r-- | roles/lib_utils/library/yedit.py | 19 | ||||
| -rw-r--r-- | roles/lib_utils/src/ansible/repoquery.py | 35 | ||||
| -rw-r--r-- | roles/lib_utils/src/class/import.py | 11 | ||||
| -rw-r--r-- | roles/lib_utils/src/class/repoquery.py | 156 | ||||
| -rw-r--r-- | roles/lib_utils/src/doc/repoquery | 275 | ||||
| -rw-r--r-- | roles/lib_utils/src/lib/import.py | 14 | ||||
| -rw-r--r-- | roles/lib_utils/src/lib/repoquery.py | 92 | ||||
| -rw-r--r-- | roles/lib_utils/src/sources.yml | 11 | ||||
| -rwxr-xr-x | roles/lib_utils/src/test/integration/repoquery.yml | 136 | ||||
| -rwxr-xr-x | roles/lib_utils/src/test/unit/repoquery.py | 87 | 
13 files changed, 1431 insertions, 21 deletions
| diff --git a/roles/lib_openshift/src/sources.yml b/roles/lib_openshift/src/sources.yml index 8a825a402..28929c02a 100644 --- a/roles/lib_openshift/src/sources.yml +++ b/roles/lib_openshift/src/sources.yml @@ -8,6 +8,7 @@ oadm_manage_node.py:  - lib/base.py  - class/oadm_manage_node.py  - ansible/oadm_manage_node.py +  oc_edit.py:  - doc/generated  - doc/license @@ -17,6 +18,7 @@ oc_edit.py:  - lib/base.py  - class/oc_edit.py  - ansible/oc_edit.py +  oc_obj.py:  - doc/generated  - doc/license @@ -26,6 +28,7 @@ oc_obj.py:  - lib/base.py  - class/oc_obj.py  - ansible/oc_obj.py +  oc_route.py:  - doc/generated  - doc/license @@ -36,6 +39,7 @@ oc_route.py:  - lib/route.py  - class/oc_route.py  - ansible/oc_route.py +  oc_secret.py:  - doc/generated  - doc/license @@ -46,6 +50,7 @@ oc_secret.py:  - lib/secret.py  - class/oc_secret.py  - ansible/oc_secret.py +  oc_scale.py:  - doc/generated  - doc/license @@ -57,6 +62,7 @@ oc_scale.py:  - lib/replicationcontroller.py  - class/oc_scale.py  - ansible/oc_scale.py +  oc_version.py:  - doc/generated  - doc/license @@ -66,6 +72,7 @@ oc_version.py:  - lib/base.py  - class/oc_version.py  - ansible/oc_version.py +  oc_serviceaccount.py:  - doc/generated  - doc/license diff --git a/roles/lib_openshift/src/test/unit/oc_secret.py b/roles/lib_openshift/src/test/unit/oc_secret.py index 221f00ed6..835918b95 100755 --- a/roles/lib_openshift/src/test/unit/oc_secret.py +++ b/roles/lib_openshift/src/test/unit/oc_secret.py @@ -81,7 +81,7 @@ class OCSecretTest(unittest.TestCase):          # Making sure our mock was called as we expected          mock_openshift_cmd.assert_has_calls([ -            mock.call(['get', 'secrets', '-o', 'json', 'secretname'], output=True), +            mock.call(['get', 'secrets', 'secretname', '-o', 'json'], output=True),              mock.call(['secrets', 'new', 'secretname', 'somesecret.json=/tmp/somesecret.json']),          ]) diff --git a/roles/lib_utils/library/repoquery.py b/roles/lib_utils/library/repoquery.py new file mode 100644 index 000000000..7f0105290 --- /dev/null +++ b/roles/lib_utils/library/repoquery.py @@ -0,0 +1,607 @@ +#!/usr/bin/env python +# pylint: disable=missing-docstring +#     ___ ___ _  _ ___ ___    _ _____ ___ ___ +#    / __| __| \| | __| _ \  /_\_   _| __|   \ +#   | (_ | _|| .` | _||   / / _ \| | | _|| |) | +#    \___|___|_|\_|___|_|_\/_/_\_\_|_|___|___/_ _____ +#   |   \ / _ \  | \| |/ _ \_   _| | __|   \_ _|_   _| +#   | |) | (_) | | .` | (_) || |   | _|| |) | |  | | +#   |___/ \___/  |_|\_|\___/ |_|   |___|___/___| |_| +# +# Copyright 2016 Red Hat, Inc. and/or its affiliates +# and other contributors as indicated by the @author tags. +# +# 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. +# + +# -*- -*- -*- Begin included fragment: lib/import.py -*- -*- -*- + +# pylint: disable=wrong-import-order,wrong-import-position,unused-import + +from __future__ import print_function  # noqa: F401 +import json  # noqa: F401 +import os  # noqa: F401 +import re  # noqa: F401 +# pylint: disable=import-error +import ruamel.yaml as yaml  # noqa: F401 +import shutil  # noqa: F401 + +from ansible.module_utils.basic import AnsibleModule + +# -*- -*- -*- End included fragment: lib/import.py -*- -*- -*- + +# -*- -*- -*- Begin included fragment: doc/repoquery -*- -*- -*- + +DOCUMENTATION = ''' +--- +module: repoquery +short_description: Query package information from Yum repositories +description: +  - Query package information from Yum repositories. +options: +  state: +    description: +    - The expected state. Currently only supports list. +    required: false +    default: list +    choices: ["list"] +    aliases: [] +  name: +    description: +    - The name of the package to query +    required: true +    default: None +    aliases: [] +  query_type: +    description: +    - Narrows the packages queried based off of this value. +    - If repos, it narrows the query to repositories defined on the machine. +    - If installed, it narrows the query to only packages installed on the machine. +    - If available, it narrows the query to packages that are available to be installed. +    - If recent, it narrows the query to only recently edited packages. +    - If updates, it narrows the query to only packages that are updates to existing installed packages. +    - If extras, it narrows the query to packages that are not present in any of the available repositories. +    - If all, it queries all of the above. +    required: false +    default: repos +    aliases: [] +  verbose: +    description: +    - Shows more detail for the requested query. +    required: false +    default: false +    aliases: [] +  show_duplicates: +    description: +    - Shows multiple versions of a package. +    required: false +    default: false +    aliases: [] +  match_version: +    description: +    - Match the specific version given to the package. +    required: false +    default: None +    aliases: [] +author: +- "Matt Woodson <mwoodson@redhat.com>" +extends_documentation_fragment: [] +''' + +EXAMPLES = ''' +# Example 1: Get bash versions +  - name: Get bash version +    repoquery: +      name: bash +      show_duplicates: True +    register: bash_out + +# Results: +#    ok: [localhost] => { +#        "bash_out": { +#            "changed": false, +#            "results": { +#                "cmd": "/usr/bin/repoquery --quiet --pkgnarrow=repos --queryformat=%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release} --show-duplicates bash", +#                "package_found": true, +#                "package_name": "bash", +#                "returncode": 0, +#                "versions": { +#                    "available_versions": [ +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46" +#                    ], +#                    "available_versions_full": [ +#                        "4.2.45-5.el7", +#                        "4.2.45-5.el7_0.2", +#                        "4.2.45-5.el7_0.4", +#                        "4.2.46-12.el7", +#                        "4.2.46-19.el7", +#                        "4.2.46-20.el7_2", +#                        "4.2.46-21.el7_3" +#                    ], +#                    "latest": "4.2.46", +#                    "latest_full": "4.2.46-21.el7_3" +#                } +#            }, +#            "state": "present" +#        } +#    } + + + +# Example 2: Get bash versions verbosely +  - name: Get bash versions verbosely +    repoquery: +      name: bash +      show_duplicates: True +      verbose: True +    register: bash_out + +# Results: +#    ok: [localhost] => { +#        "bash_out": { +#            "changed": false, +#            "results": { +#                "cmd": "/usr/bin/repoquery --quiet --pkgnarrow=repos --queryformat=%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release} --show-duplicates bash", +#                "package_found": true, +#                "package_name": "bash", +#                "raw_versions": { +#                    "4.2.45-5.el7": { +#                        "arch": "x86_64", +#                        "release": "5.el7", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.45", +#                        "version_release": "4.2.45-5.el7" +#                    }, +#                    "4.2.45-5.el7_0.2": { +#                        "arch": "x86_64", +#                        "release": "5.el7_0.2", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.45", +#                        "version_release": "4.2.45-5.el7_0.2" +#                    }, +#                    "4.2.45-5.el7_0.4": { +#                        "arch": "x86_64", +#                        "release": "5.el7_0.4", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.45", +#                        "version_release": "4.2.45-5.el7_0.4" +#                    }, +#                    "4.2.46-12.el7": { +#                        "arch": "x86_64", +#                        "release": "12.el7", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-12.el7" +#                    }, +#                    "4.2.46-19.el7": { +#                        "arch": "x86_64", +#                        "release": "19.el7", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-19.el7" +#                    }, +#                    "4.2.46-20.el7_2": { +#                        "arch": "x86_64", +#                        "release": "20.el7_2", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-20.el7_2" +#                    }, +#                    "4.2.46-21.el7_3": { +#                        "arch": "x86_64", +#                        "release": "21.el7_3", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-21.el7_3" +#                    } +#                }, +#                "results": "4.2.45|5.el7|x86_64|rhel-7-server-rpms|4.2.45-5.el7\n4.2.45|5.el7_0.2|x86_64|rhel-7-server-rpms|4.2.45-5.el7_0.2\n4.2.45|5.el7_0.4|x86_64|rhel-7-server-rpms|4.2.45-5.el7_0.4\n4.2.46|12.el7|x86_64|rhel-7-server-rpms|4.2.46-12.el7\n4.2.46|19.el7|x86_64|rhel-7-server-rpms|4.2.46-19.el7\n4.2.46|20.el7_2|x86_64|rhel-7-server-rpms|4.2.46-20.el7_2\n4.2.46|21.el7_3|x86_64|rhel-7-server-rpms|4.2.46-21.el7_3\n", +#                "returncode": 0, +#                "versions": { +#                    "available_versions": [ +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46" +#                    ], +#                    "available_versions_full": [ +#                        "4.2.45-5.el7", +#                        "4.2.45-5.el7_0.2", +#                        "4.2.45-5.el7_0.4", +#                        "4.2.46-12.el7", +#                        "4.2.46-19.el7", +#                        "4.2.46-20.el7_2", +#                        "4.2.46-21.el7_3" +#                    ], +#                    "latest": "4.2.46", +#                    "latest_full": "4.2.46-21.el7_3" +#                } +#            }, +#            "state": "present" +#        } +#    } + +# Example 3: Match a specific version +  - name: matched versions repoquery test +    repoquery: +      name: atomic-openshift +      show_duplicates: True +      match_version: 3.3 +    register: openshift_out + +# Result: + +#    ok: [localhost] => { +#        "openshift_out": { +#            "changed": false, +#            "results": { +#                "cmd": "/usr/bin/repoquery --quiet --pkgnarrow=repos --queryformat=%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release} --show-duplicates atomic-openshift", +#                "package_found": true, +#                "package_name": "atomic-openshift", +#                "returncode": 0, +#                "versions": { +#                    "available_versions": [ +#                        "3.2.0.43", +#                        "3.2.1.23", +#                        "3.3.0.32", +#                        "3.3.0.34", +#                        "3.3.0.35", +#                        "3.3.1.3", +#                        "3.3.1.4", +#                        "3.3.1.5", +#                        "3.3.1.7", +#                        "3.4.0.39" +#                    ], +#                    "available_versions_full": [ +#                        "3.2.0.43-1.git.0.672599f.el7", +#                        "3.2.1.23-1.git.0.88a7a1d.el7", +#                        "3.3.0.32-1.git.0.37bd7ea.el7", +#                        "3.3.0.34-1.git.0.83f306f.el7", +#                        "3.3.0.35-1.git.0.d7bd9b6.el7", +#                        "3.3.1.3-1.git.0.86dc49a.el7", +#                        "3.3.1.4-1.git.0.7c8657c.el7", +#                        "3.3.1.5-1.git.0.62700af.el7", +#                        "3.3.1.7-1.git.0.0988966.el7", +#                        "3.4.0.39-1.git.0.5f32f06.el7" +#                    ], +#                    "latest": "3.4.0.39", +#                    "latest_full": "3.4.0.39-1.git.0.5f32f06.el7", +#                    "matched_version_found": true, +#                    "matched_version_full_latest": "3.3.1.7-1.git.0.0988966.el7", +#                    "matched_version_latest": "3.3.1.7", +#                    "matched_versions": [ +#                        "3.3.0.32", +#                        "3.3.0.34", +#                        "3.3.0.35", +#                        "3.3.1.3", +#                        "3.3.1.4", +#                        "3.3.1.5", +#                        "3.3.1.7" +#                    ], +#                    "matched_versions_full": [ +#                        "3.3.0.32-1.git.0.37bd7ea.el7", +#                        "3.3.0.34-1.git.0.83f306f.el7", +#                        "3.3.0.35-1.git.0.d7bd9b6.el7", +#                        "3.3.1.3-1.git.0.86dc49a.el7", +#                        "3.3.1.4-1.git.0.7c8657c.el7", +#                        "3.3.1.5-1.git.0.62700af.el7", +#                        "3.3.1.7-1.git.0.0988966.el7" +#                    ], +#                    "requested_match_version": "3.3" +#                } +#            }, +#            "state": "present" +#        } +#    } + +''' + +# -*- -*- -*- End included fragment: doc/repoquery -*- -*- -*- + +# -*- -*- -*- Begin included fragment: lib/repoquery.py -*- -*- -*- + +''' +   class that wraps the repoquery commands in a subprocess +''' + +# pylint: disable=too-many-lines,wrong-import-position,wrong-import-order + +from collections import defaultdict  # noqa: E402 + + +# pylint: disable=no-name-in-module,import-error +# Reason: pylint errors with "No name 'version' in module 'distutils'". +#         This is a bug: https://github.com/PyCQA/pylint/issues/73 +from distutils.version import LooseVersion  # noqa: E402 + +import subprocess  # noqa: E402 + + +class RepoqueryCLIError(Exception): +    '''Exception class for repoquerycli''' +    pass + + +def _run(cmds): +    ''' Actually executes the command. This makes mocking easier. ''' +    proc = subprocess.Popen(cmds, +                            stdin=subprocess.PIPE, +                            stdout=subprocess.PIPE, +                            stderr=subprocess.PIPE) + +    stdout, stderr = proc.communicate() + +    return proc.returncode, stdout, stderr + + +# pylint: disable=too-few-public-methods +class RepoqueryCLI(object): +    ''' Class to wrap the command line tools ''' +    def __init__(self, +                 verbose=False): +        ''' Constructor for RepoqueryCLI ''' +        self.verbose = verbose +        self.verbose = True + +    def _repoquery_cmd(self, cmd, output=False, output_type='json'): +        '''Base command for repoquery ''' +        cmds = ['/usr/bin/repoquery', '--plugins', '--quiet'] + +        cmds.extend(cmd) + +        rval = {} +        results = '' +        err = None + +        if self.verbose: +            print(' '.join(cmds)) + +        returncode, stdout, stderr = _run(cmds) + +        rval = { +            "returncode": returncode, +            "results": results, +            "cmd": ' '.join(cmds), +        } + +        if returncode == 0: +            if output: +                if output_type == 'raw': +                    rval['results'] = stdout + +            if self.verbose: +                print(stdout) +                print(stderr) + +            if err: +                rval.update({ +                    "err": err, +                    "stderr": stderr, +                    "stdout": stdout, +                    "cmd": cmds +                }) + +        else: +            rval.update({ +                "stderr": stderr, +                "stdout": stdout, +                "results": {}, +            }) + +        return rval + +# -*- -*- -*- End included fragment: lib/repoquery.py -*- -*- -*- + +# -*- -*- -*- Begin included fragment: class/repoquery.py -*- -*- -*- + + +class Repoquery(RepoqueryCLI): +    ''' Class to wrap the repoquery +    ''' +    # pylint: disable=too-many-arguments +    def __init__(self, name, query_type, show_duplicates, +                 match_version, verbose): +        ''' Constructor for YumList ''' +        super(Repoquery, self).__init__(None) +        self.name = name +        self.query_type = query_type +        self.show_duplicates = show_duplicates +        self.match_version = match_version +        self.verbose = verbose + +        if self.match_version: +            self.show_duplicates = True + +        self.query_format = "%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release}" + +    def build_cmd(self): +        ''' build the repoquery cmd options ''' + +        repo_cmd = [] + +        repo_cmd.append("--pkgnarrow=" + self.query_type) +        repo_cmd.append("--queryformat=" + self.query_format) + +        if self.show_duplicates: +            repo_cmd.append('--show-duplicates') + +        repo_cmd.append(self.name) + +        return repo_cmd + +    @staticmethod +    def process_versions(query_output): +        ''' format the package data into something that can be presented ''' + +        version_dict = defaultdict(dict) + +        for version in query_output.split('\n'): +            pkg_info = version.split("|") + +            pkg_version = {} +            pkg_version['version'] = pkg_info[0] +            pkg_version['release'] = pkg_info[1] +            pkg_version['arch'] = pkg_info[2] +            pkg_version['repo'] = pkg_info[3] +            pkg_version['version_release'] = pkg_info[4] + +            version_dict[pkg_info[4]] = pkg_version + +        return version_dict + +    def format_versions(self, formatted_versions): +        ''' Gather and present the versions of each package ''' + +        versions_dict = {} +        versions_dict['available_versions_full'] = formatted_versions.keys() + +        # set the match version, if called +        if self.match_version: +            versions_dict['matched_versions_full'] = [] +            versions_dict['requested_match_version'] = self.match_version +            versions_dict['matched_versions'] = [] + +        # get the "full version (version - release) +        versions_dict['available_versions_full'].sort(key=LooseVersion) +        versions_dict['latest_full'] = versions_dict['available_versions_full'][-1] + +        # get the "short version (version) +        versions_dict['available_versions'] = [] +        for version in versions_dict['available_versions_full']: +            versions_dict['available_versions'].append(formatted_versions[version]['version']) + +            if self.match_version: +                if version.startswith(self.match_version): +                    versions_dict['matched_versions_full'].append(version) +                    versions_dict['matched_versions'].append(formatted_versions[version]['version']) + +        versions_dict['available_versions'].sort(key=LooseVersion) +        versions_dict['latest'] = versions_dict['available_versions'][-1] + +        # finish up the matched version +        if self.match_version: +            if versions_dict['matched_versions_full']: +                versions_dict['matched_version_found'] = True +                versions_dict['matched_versions'].sort(key=LooseVersion) +                versions_dict['matched_version_latest'] = versions_dict['matched_versions'][-1] +                versions_dict['matched_version_full_latest'] = versions_dict['matched_versions_full'][-1] +            else: +                versions_dict['matched_version_found'] = False +                versions_dict['matched_versions'] = [] +                versions_dict['matched_version_latest'] = "" +                versions_dict['matched_version_full_latest'] = "" + +        return versions_dict + +    def repoquery(self): +        '''perform a repoquery ''' + +        repoquery_cmd = self.build_cmd() + +        rval = self._repoquery_cmd(repoquery_cmd, True, 'raw') + +        # check to see if there are actual results +        if rval['results']: +            processed_versions = Repoquery.process_versions(rval['results'].strip()) +            formatted_versions = self.format_versions(processed_versions) + +            rval['package_found'] = True +            rval['versions'] = formatted_versions +            rval['package_name'] = self.name + +            if self.verbose: +                rval['raw_versions'] = processed_versions +            else: +                del rval['results'] + +        # No packages found +        else: +            rval['package_found'] = False + +        return rval + +    @staticmethod +    def run_ansible(params, check_mode): +        '''run the ansible idempotent code''' + +        repoquery = Repoquery( +            params['name'], +            params['query_type'], +            params['show_duplicates'], +            params['match_version'], +            params['verbose'], +        ) + +        state = params['state'] + +        if state == 'list': +            results = repoquery.repoquery() + +            if results['returncode'] != 0: +                return {'failed': True, +                        'msg': results} + +            return {'changed': False, 'results': results, 'state': 'list', 'check_mode': check_mode} + +        return {'failed': True, +                'changed': False, +                'msg': 'Unknown state passed. %s' % state, +                'state': 'unknown'} + +# -*- -*- -*- End included fragment: class/repoquery.py -*- -*- -*- + +# -*- -*- -*- Begin included fragment: ansible/repoquery.py -*- -*- -*- + + +def main(): +    ''' +    ansible repoquery module +    ''' +    module = AnsibleModule( +        argument_spec=dict( +            state=dict(default='list', type='str', choices=['list']), +            name=dict(default=None, required=True, type='str'), +            query_type=dict(default='repos', required=False, type='str', +                            choices=[ +                                'installed', 'available', 'recent', +                                'updates', 'extras', 'all', 'repos' +                            ]), +            verbose=dict(default=False, required=False, type='bool'), +            show_duplicates=dict(default=False, required=False, type='bool'), +            match_version=dict(default=None, required=False, type='str'), +        ), +        supports_check_mode=False, +        required_if=[('show_duplicates', True, ['name'])], +    ) + +    rval = Repoquery.run_ansible(module.params, module.check_mode) + +    if 'failed' in rval: +        module.fail_json(**rval) + +    module.exit_json(**rval) + + +if __name__ == "__main__": +    main() + +# -*- -*- -*- End included fragment: ansible/repoquery.py -*- -*- -*- diff --git a/roles/lib_utils/library/yedit.py b/roles/lib_utils/library/yedit.py index 8a2bd92f9..7ad2b7181 100644 --- a/roles/lib_utils/library/yedit.py +++ b/roles/lib_utils/library/yedit.py @@ -24,18 +24,21 @@  # limitations under the License.  # -# -*- -*- -*- Begin included fragment: class/import.py -*- -*- -*- +# -*- -*- -*- Begin included fragment: lib/import.py -*- -*- -*- -# pylint: disable=wrong-import-order -import json -import os -import re +# pylint: disable=wrong-import-order,wrong-import-position,unused-import + +from __future__ import print_function  # noqa: F401 +import json  # noqa: F401 +import os  # noqa: F401 +import re  # noqa: F401  # pylint: disable=import-error -import ruamel.yaml as yaml -import shutil +import ruamel.yaml as yaml  # noqa: F401 +import shutil  # noqa: F401 +  from ansible.module_utils.basic import AnsibleModule -# -*- -*- -*- End included fragment: class/import.py -*- -*- -*- +# -*- -*- -*- End included fragment: lib/import.py -*- -*- -*-  # -*- -*- -*- Begin included fragment: doc/yedit -*- -*- -*- diff --git a/roles/lib_utils/src/ansible/repoquery.py b/roles/lib_utils/src/ansible/repoquery.py new file mode 100644 index 000000000..cb4efa6c1 --- /dev/null +++ b/roles/lib_utils/src/ansible/repoquery.py @@ -0,0 +1,35 @@ +# pylint: skip-file +# flake8: noqa + + +def main(): +    ''' +    ansible repoquery module +    ''' +    module = AnsibleModule( +        argument_spec=dict( +            state=dict(default='list', type='str', choices=['list']), +            name=dict(default=None, required=True, type='str'), +            query_type=dict(default='repos', required=False, type='str', +                            choices=[ +                                'installed', 'available', 'recent', +                                'updates', 'extras', 'all', 'repos' +                            ]), +            verbose=dict(default=False, required=False, type='bool'), +            show_duplicates=dict(default=False, required=False, type='bool'), +            match_version=dict(default=None, required=False, type='str'), +        ), +        supports_check_mode=False, +        required_if=[('show_duplicates', True, ['name'])], +    ) + +    rval = Repoquery.run_ansible(module.params, module.check_mode) + +    if 'failed' in rval: +        module.fail_json(**rval) + +    module.exit_json(**rval) + + +if __name__ == "__main__": +    main() diff --git a/roles/lib_utils/src/class/import.py b/roles/lib_utils/src/class/import.py deleted file mode 100644 index 249e07228..000000000 --- a/roles/lib_utils/src/class/import.py +++ /dev/null @@ -1,11 +0,0 @@ -# flake8: noqa -# pylint: skip-file - -# pylint: disable=wrong-import-order -import json -import os -import re -# pylint: disable=import-error -import ruamel.yaml as yaml -import shutil -from ansible.module_utils.basic import AnsibleModule diff --git a/roles/lib_utils/src/class/repoquery.py b/roles/lib_utils/src/class/repoquery.py new file mode 100644 index 000000000..2447719e2 --- /dev/null +++ b/roles/lib_utils/src/class/repoquery.py @@ -0,0 +1,156 @@ +# pylint: skip-file +# flake8: noqa + + +class Repoquery(RepoqueryCLI): +    ''' Class to wrap the repoquery +    ''' +    # pylint: disable=too-many-arguments +    def __init__(self, name, query_type, show_duplicates, +                 match_version, verbose): +        ''' Constructor for YumList ''' +        super(Repoquery, self).__init__(None) +        self.name = name +        self.query_type = query_type +        self.show_duplicates = show_duplicates +        self.match_version = match_version +        self.verbose = verbose + +        if self.match_version: +            self.show_duplicates = True + +        self.query_format = "%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release}" + +    def build_cmd(self): +        ''' build the repoquery cmd options ''' + +        repo_cmd = [] + +        repo_cmd.append("--pkgnarrow=" + self.query_type) +        repo_cmd.append("--queryformat=" + self.query_format) + +        if self.show_duplicates: +            repo_cmd.append('--show-duplicates') + +        repo_cmd.append(self.name) + +        return repo_cmd + +    @staticmethod +    def process_versions(query_output): +        ''' format the package data into something that can be presented ''' + +        version_dict = defaultdict(dict) + +        for version in query_output.split('\n'): +            pkg_info = version.split("|") + +            pkg_version = {} +            pkg_version['version'] = pkg_info[0] +            pkg_version['release'] = pkg_info[1] +            pkg_version['arch'] = pkg_info[2] +            pkg_version['repo'] = pkg_info[3] +            pkg_version['version_release'] = pkg_info[4] + +            version_dict[pkg_info[4]] = pkg_version + +        return version_dict + +    def format_versions(self, formatted_versions): +        ''' Gather and present the versions of each package ''' + +        versions_dict = {} +        versions_dict['available_versions_full'] = formatted_versions.keys() + +        # set the match version, if called +        if self.match_version: +            versions_dict['matched_versions_full'] = [] +            versions_dict['requested_match_version'] = self.match_version +            versions_dict['matched_versions'] = [] + +        # get the "full version (version - release) +        versions_dict['available_versions_full'].sort(key=LooseVersion) +        versions_dict['latest_full'] = versions_dict['available_versions_full'][-1] + +        # get the "short version (version) +        versions_dict['available_versions'] = [] +        for version in versions_dict['available_versions_full']: +            versions_dict['available_versions'].append(formatted_versions[version]['version']) + +            if self.match_version: +                if version.startswith(self.match_version): +                    versions_dict['matched_versions_full'].append(version) +                    versions_dict['matched_versions'].append(formatted_versions[version]['version']) + +        versions_dict['available_versions'].sort(key=LooseVersion) +        versions_dict['latest'] = versions_dict['available_versions'][-1] + +        # finish up the matched version +        if self.match_version: +            if versions_dict['matched_versions_full']: +                versions_dict['matched_version_found'] = True +                versions_dict['matched_versions'].sort(key=LooseVersion) +                versions_dict['matched_version_latest'] = versions_dict['matched_versions'][-1] +                versions_dict['matched_version_full_latest'] = versions_dict['matched_versions_full'][-1] +            else: +                versions_dict['matched_version_found'] = False +                versions_dict['matched_versions'] = [] +                versions_dict['matched_version_latest'] = "" +                versions_dict['matched_version_full_latest'] = "" + +        return versions_dict + +    def repoquery(self): +        '''perform a repoquery ''' + +        repoquery_cmd = self.build_cmd() + +        rval = self._repoquery_cmd(repoquery_cmd, True, 'raw') + +        # check to see if there are actual results +        if rval['results']: +            processed_versions = Repoquery.process_versions(rval['results'].strip()) +            formatted_versions = self.format_versions(processed_versions) + +            rval['package_found'] = True +            rval['versions'] = formatted_versions +            rval['package_name'] = self.name + +            if self.verbose: +                rval['raw_versions'] = processed_versions +            else: +                del rval['results'] + +        # No packages found +        else: +            rval['package_found'] = False + +        return rval + +    @staticmethod +    def run_ansible(params, check_mode): +        '''run the ansible idempotent code''' + +        repoquery = Repoquery( +            params['name'], +            params['query_type'], +            params['show_duplicates'], +            params['match_version'], +            params['verbose'], +        ) + +        state = params['state'] + +        if state == 'list': +            results = repoquery.repoquery() + +            if results['returncode'] != 0: +                return {'failed': True, +                        'msg': results} + +            return {'changed': False, 'results': results, 'state': 'list', 'check_mode': check_mode} + +        return {'failed': True, +                'changed': False, +                'msg': 'Unknown state passed. %s' % state, +                'state': 'unknown'} diff --git a/roles/lib_utils/src/doc/repoquery b/roles/lib_utils/src/doc/repoquery new file mode 100644 index 000000000..82e273a42 --- /dev/null +++ b/roles/lib_utils/src/doc/repoquery @@ -0,0 +1,275 @@ +# flake8: noqa +# pylint: skip-file + +DOCUMENTATION = ''' +--- +module: repoquery +short_description: Query package information from Yum repositories +description: +  - Query package information from Yum repositories. +options: +  state: +    description: +    - The expected state. Currently only supports list. +    required: false +    default: list +    choices: ["list"] +    aliases: [] +  name: +    description: +    - The name of the package to query +    required: true +    default: None +    aliases: [] +  query_type: +    description: +    - Narrows the packages queried based off of this value. +    - If repos, it narrows the query to repositories defined on the machine. +    - If installed, it narrows the query to only packages installed on the machine. +    - If available, it narrows the query to packages that are available to be installed. +    - If recent, it narrows the query to only recently edited packages. +    - If updates, it narrows the query to only packages that are updates to existing installed packages. +    - If extras, it narrows the query to packages that are not present in any of the available repositories. +    - If all, it queries all of the above. +    required: false +    default: repos +    aliases: [] +  verbose: +    description: +    - Shows more detail for the requested query. +    required: false +    default: false +    aliases: [] +  show_duplicates: +    description: +    - Shows multiple versions of a package. +    required: false +    default: false +    aliases: [] +  match_version: +    description: +    - Match the specific version given to the package. +    required: false +    default: None +    aliases: [] +author: +- "Matt Woodson <mwoodson@redhat.com>" +extends_documentation_fragment: [] +''' + +EXAMPLES = ''' +# Example 1: Get bash versions +  - name: Get bash version +    repoquery: +      name: bash +      show_duplicates: True +    register: bash_out + +# Results: +#    ok: [localhost] => { +#        "bash_out": { +#            "changed": false, +#            "results": { +#                "cmd": "/usr/bin/repoquery --quiet --pkgnarrow=repos --queryformat=%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release} --show-duplicates bash", +#                "package_found": true, +#                "package_name": "bash", +#                "returncode": 0, +#                "versions": { +#                    "available_versions": [ +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46" +#                    ], +#                    "available_versions_full": [ +#                        "4.2.45-5.el7", +#                        "4.2.45-5.el7_0.2", +#                        "4.2.45-5.el7_0.4", +#                        "4.2.46-12.el7", +#                        "4.2.46-19.el7", +#                        "4.2.46-20.el7_2", +#                        "4.2.46-21.el7_3" +#                    ], +#                    "latest": "4.2.46", +#                    "latest_full": "4.2.46-21.el7_3" +#                } +#            }, +#            "state": "present" +#        } +#    } + + + +# Example 2: Get bash versions verbosely +  - name: Get bash versions verbosely +    repoquery: +      name: bash +      show_duplicates: True +      verbose: True +    register: bash_out + +# Results: +#    ok: [localhost] => { +#        "bash_out": { +#            "changed": false, +#            "results": { +#                "cmd": "/usr/bin/repoquery --quiet --pkgnarrow=repos --queryformat=%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release} --show-duplicates bash", +#                "package_found": true, +#                "package_name": "bash", +#                "raw_versions": { +#                    "4.2.45-5.el7": { +#                        "arch": "x86_64", +#                        "release": "5.el7", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.45", +#                        "version_release": "4.2.45-5.el7" +#                    }, +#                    "4.2.45-5.el7_0.2": { +#                        "arch": "x86_64", +#                        "release": "5.el7_0.2", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.45", +#                        "version_release": "4.2.45-5.el7_0.2" +#                    }, +#                    "4.2.45-5.el7_0.4": { +#                        "arch": "x86_64", +#                        "release": "5.el7_0.4", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.45", +#                        "version_release": "4.2.45-5.el7_0.4" +#                    }, +#                    "4.2.46-12.el7": { +#                        "arch": "x86_64", +#                        "release": "12.el7", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-12.el7" +#                    }, +#                    "4.2.46-19.el7": { +#                        "arch": "x86_64", +#                        "release": "19.el7", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-19.el7" +#                    }, +#                    "4.2.46-20.el7_2": { +#                        "arch": "x86_64", +#                        "release": "20.el7_2", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-20.el7_2" +#                    }, +#                    "4.2.46-21.el7_3": { +#                        "arch": "x86_64", +#                        "release": "21.el7_3", +#                        "repo": "rhel-7-server-rpms", +#                        "version": "4.2.46", +#                        "version_release": "4.2.46-21.el7_3" +#                    } +#                }, +#                "results": "4.2.45|5.el7|x86_64|rhel-7-server-rpms|4.2.45-5.el7\n4.2.45|5.el7_0.2|x86_64|rhel-7-server-rpms|4.2.45-5.el7_0.2\n4.2.45|5.el7_0.4|x86_64|rhel-7-server-rpms|4.2.45-5.el7_0.4\n4.2.46|12.el7|x86_64|rhel-7-server-rpms|4.2.46-12.el7\n4.2.46|19.el7|x86_64|rhel-7-server-rpms|4.2.46-19.el7\n4.2.46|20.el7_2|x86_64|rhel-7-server-rpms|4.2.46-20.el7_2\n4.2.46|21.el7_3|x86_64|rhel-7-server-rpms|4.2.46-21.el7_3\n", +#                "returncode": 0, +#                "versions": { +#                    "available_versions": [ +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.45", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46", +#                        "4.2.46" +#                    ], +#                    "available_versions_full": [ +#                        "4.2.45-5.el7", +#                        "4.2.45-5.el7_0.2", +#                        "4.2.45-5.el7_0.4", +#                        "4.2.46-12.el7", +#                        "4.2.46-19.el7", +#                        "4.2.46-20.el7_2", +#                        "4.2.46-21.el7_3" +#                    ], +#                    "latest": "4.2.46", +#                    "latest_full": "4.2.46-21.el7_3" +#                } +#            }, +#            "state": "present" +#        } +#    } + +# Example 3: Match a specific version +  - name: matched versions repoquery test +    repoquery: +      name: atomic-openshift +      show_duplicates: True +      match_version: 3.3 +    register: openshift_out + +# Result: + +#    ok: [localhost] => { +#        "openshift_out": { +#            "changed": false, +#            "results": { +#                "cmd": "/usr/bin/repoquery --quiet --pkgnarrow=repos --queryformat=%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release} --show-duplicates atomic-openshift", +#                "package_found": true, +#                "package_name": "atomic-openshift", +#                "returncode": 0, +#                "versions": { +#                    "available_versions": [ +#                        "3.2.0.43", +#                        "3.2.1.23", +#                        "3.3.0.32", +#                        "3.3.0.34", +#                        "3.3.0.35", +#                        "3.3.1.3", +#                        "3.3.1.4", +#                        "3.3.1.5", +#                        "3.3.1.7", +#                        "3.4.0.39" +#                    ], +#                    "available_versions_full": [ +#                        "3.2.0.43-1.git.0.672599f.el7", +#                        "3.2.1.23-1.git.0.88a7a1d.el7", +#                        "3.3.0.32-1.git.0.37bd7ea.el7", +#                        "3.3.0.34-1.git.0.83f306f.el7", +#                        "3.3.0.35-1.git.0.d7bd9b6.el7", +#                        "3.3.1.3-1.git.0.86dc49a.el7", +#                        "3.3.1.4-1.git.0.7c8657c.el7", +#                        "3.3.1.5-1.git.0.62700af.el7", +#                        "3.3.1.7-1.git.0.0988966.el7", +#                        "3.4.0.39-1.git.0.5f32f06.el7" +#                    ], +#                    "latest": "3.4.0.39", +#                    "latest_full": "3.4.0.39-1.git.0.5f32f06.el7", +#                    "matched_version_found": true, +#                    "matched_version_full_latest": "3.3.1.7-1.git.0.0988966.el7", +#                    "matched_version_latest": "3.3.1.7", +#                    "matched_versions": [ +#                        "3.3.0.32", +#                        "3.3.0.34", +#                        "3.3.0.35", +#                        "3.3.1.3", +#                        "3.3.1.4", +#                        "3.3.1.5", +#                        "3.3.1.7" +#                    ], +#                    "matched_versions_full": [ +#                        "3.3.0.32-1.git.0.37bd7ea.el7", +#                        "3.3.0.34-1.git.0.83f306f.el7", +#                        "3.3.0.35-1.git.0.d7bd9b6.el7", +#                        "3.3.1.3-1.git.0.86dc49a.el7", +#                        "3.3.1.4-1.git.0.7c8657c.el7", +#                        "3.3.1.5-1.git.0.62700af.el7", +#                        "3.3.1.7-1.git.0.0988966.el7" +#                    ], +#                    "requested_match_version": "3.3" +#                } +#            }, +#            "state": "present" +#        } +#    } + +''' diff --git a/roles/lib_utils/src/lib/import.py b/roles/lib_utils/src/lib/import.py new file mode 100644 index 000000000..d892353a1 --- /dev/null +++ b/roles/lib_utils/src/lib/import.py @@ -0,0 +1,14 @@ +# flake8: noqa +# pylint: skip-file + +# pylint: disable=wrong-import-order,wrong-import-position,unused-import + +from __future__ import print_function  # noqa: F401 +import json  # noqa: F401 +import os  # noqa: F401 +import re  # noqa: F401 +# pylint: disable=import-error +import ruamel.yaml as yaml  # noqa: F401 +import shutil  # noqa: F401 + +from ansible.module_utils.basic import AnsibleModule diff --git a/roles/lib_utils/src/lib/repoquery.py b/roles/lib_utils/src/lib/repoquery.py new file mode 100644 index 000000000..91ccd9815 --- /dev/null +++ b/roles/lib_utils/src/lib/repoquery.py @@ -0,0 +1,92 @@ +# pylint: skip-file +# flake8: noqa + +''' +   class that wraps the repoquery commands in a subprocess +''' + +# pylint: disable=too-many-lines,wrong-import-position,wrong-import-order + +from collections import defaultdict  # noqa: E402 + + +# pylint: disable=no-name-in-module,import-error +# Reason: pylint errors with "No name 'version' in module 'distutils'". +#         This is a bug: https://github.com/PyCQA/pylint/issues/73 +from distutils.version import LooseVersion  # noqa: E402 + +import subprocess  # noqa: E402 + + +class RepoqueryCLIError(Exception): +    '''Exception class for repoquerycli''' +    pass + + +def _run(cmds): +    ''' Actually executes the command. This makes mocking easier. ''' +    proc = subprocess.Popen(cmds, +                            stdin=subprocess.PIPE, +                            stdout=subprocess.PIPE, +                            stderr=subprocess.PIPE) + +    stdout, stderr = proc.communicate() + +    return proc.returncode, stdout, stderr + + +# pylint: disable=too-few-public-methods +class RepoqueryCLI(object): +    ''' Class to wrap the command line tools ''' +    def __init__(self, +                 verbose=False): +        ''' Constructor for RepoqueryCLI ''' +        self.verbose = verbose +        self.verbose = True + +    def _repoquery_cmd(self, cmd, output=False, output_type='json'): +        '''Base command for repoquery ''' +        cmds = ['/usr/bin/repoquery', '--plugins', '--quiet'] + +        cmds.extend(cmd) + +        rval = {} +        results = '' +        err = None + +        if self.verbose: +            print(' '.join(cmds)) + +        returncode, stdout, stderr = _run(cmds) + +        rval = { +            "returncode": returncode, +            "results": results, +            "cmd": ' '.join(cmds), +        } + +        if returncode == 0: +            if output: +                if output_type == 'raw': +                    rval['results'] = stdout + +            if self.verbose: +                print(stdout) +                print(stderr) + +            if err: +                rval.update({ +                    "err": err, +                    "stderr": stderr, +                    "stdout": stdout, +                    "cmd": cmds +                }) + +        else: +            rval.update({ +                "stderr": stderr, +                "stdout": stdout, +                "results": {}, +            }) + +        return rval diff --git a/roles/lib_utils/src/sources.yml b/roles/lib_utils/src/sources.yml index 9cf3a0981..053b59f77 100644 --- a/roles/lib_utils/src/sources.yml +++ b/roles/lib_utils/src/sources.yml @@ -2,7 +2,16 @@  yedit.py:  - doc/generated  - doc/license -- class/import.py +- lib/import.py  - doc/yedit  - class/yedit.py  - ansible/yedit.py + +repoquery.py: +- doc/generated +- doc/license +- lib/import.py +- doc/repoquery +- lib/repoquery.py +- class/repoquery.py +- ansible/repoquery.py diff --git a/roles/lib_utils/src/test/integration/repoquery.yml b/roles/lib_utils/src/test/integration/repoquery.yml new file mode 100755 index 000000000..425324387 --- /dev/null +++ b/roles/lib_utils/src/test/integration/repoquery.yml @@ -0,0 +1,136 @@ +#!/usr/bin/ansible-playbook --module-path=../../../library/ +--- +- hosts: localhost +  gather_facts: no + +  tasks: +  - name: basic query test - Act +    repoquery: +      name: bash +    register: rq_out + +  - name: Set a real package version to be used later +    set_fact: +      latest_available_bash_version: "{{ rq_out.results.versions.latest }}" +      latest_available_full_bash_version: "{{ rq_out.results.versions.latest_full }}" + +  - name: basic query test - Assert +    assert: +      that: +      - "rq_out.state == 'list'" +      - "rq_out.changed == False" +      - "rq_out.results.returncode == 0" +      - "rq_out.results.package_found == True" +      - "rq_out.results.package_name == 'bash'" +      - "rq_out.results.versions.available_versions | length == 1" +      - "rq_out.results.versions.available_versions_full | length == 1" +      - "rq_out.results.versions.latest is defined" +      - "rq_out.results.versions.latest in rq_out.results.versions.available_versions" +      - "rq_out.results.versions.latest_full is defined" +      - "rq_out.results.versions.latest_full in rq_out.results.versions.available_versions_full" + +  - name: show_duplicates query test - Act +    repoquery: +      name: bash +      show_duplicates: True +    register: rq_out + +  - name: show_duplicates query test - Assert +    assert: +      that: +      - "rq_out.state == 'list'" +      - "rq_out.changed == False" +      - "rq_out.results.returncode == 0" +      - "rq_out.results.package_found == True" +      - "rq_out.results.package_name == 'bash'" +      - "rq_out.results.versions.available_versions | length >= 1" +      - "rq_out.results.versions.available_versions_full | length >= 1" +      - "rq_out.results.versions.latest is defined" +      - "rq_out.results.versions.latest in rq_out.results.versions.available_versions" +      - "rq_out.results.versions.latest_full is defined" +      - "rq_out.results.versions.latest_full in rq_out.results.versions.available_versions_full" + +  - name: show_duplicates verbose query test - Act +    repoquery: +      name: bash +      show_duplicates: True +      verbose: True +    register: rq_out + +  - name: show_duplicates verbose query test - Assert +    assert: +      that: +      - "rq_out.state == 'list'" +      - "rq_out.changed == False" +      - "rq_out.results.returncode == 0" +      - "rq_out.results.package_found == True" +      - "rq_out.results.package_name == 'bash'" +      - "rq_out.results.raw_versions | length > 0" +      - "rq_out.results.versions.available_versions | length > 0" +      - "rq_out.results.versions.available_versions_full | length > 0" +      - "rq_out.results.versions.latest is defined" +      - "rq_out.results.versions.latest in rq_out.results.versions.available_versions" +      - "rq_out.results.versions.latest_full is defined" +      - "rq_out.results.versions.latest_full in rq_out.results.versions.available_versions_full" + +  - name: query package does not exist query test - Act +    repoquery: +      name: somemadeuppackagenamethatwontmatch +      show_duplicates: True +    register: rq_out + +  - name: query package does not exist query test - Assert +    assert: +      that: +      - "rq_out.state == 'list'" +      - "rq_out.changed == False" +      - "rq_out.results.returncode == 0" +      - "rq_out.results.package_found == False" +      - "rq_out.results.results == ''" + + +  - name: query match_version does not exist query test - Act +    repoquery: +      name: bash +      show_duplicates: True +      match_version: somemadeupversionnotexist +    register: rq_out + +  - name: query match_version does not exist query test - Assert +    assert: +      that: +      - "rq_out.state == 'list'" +      - "rq_out.changed == False" +      - "rq_out.results.returncode == 0" +      - "rq_out.results.package_found == True" +      - "rq_out.results.package_name == 'bash'" +      - "rq_out.results.versions.matched_version_found == False" +      - "rq_out.results.versions.available_versions | length > 0" +      - "rq_out.results.versions.available_versions_full | length > 0" +      - "rq_out.results.versions.latest is defined" +      - "rq_out.results.versions.latest in rq_out.results.versions.available_versions" +      - "rq_out.results.versions.latest_full is defined" +      - "rq_out.results.versions.latest_full in rq_out.results.versions.available_versions_full" + +  - name: query match_version exists query test - Act +    repoquery: +      name: bash +      show_duplicates: True +      match_version: "{{ latest_available_bash_version }}" +    register: rq_out + +  - name: query match_version exists query test - Assert +    assert: +      that: +      - "rq_out.state == 'list'" +      - "rq_out.changed == False" +      - "rq_out.results.returncode == 0" +      - "rq_out.results.package_found == True" +      - "rq_out.results.package_name == 'bash'" +      - "rq_out.results.versions.matched_version_found == True" +      - "rq_out.results.versions.available_versions | length > 0" +      - "rq_out.results.versions.available_versions_full | length > 0" +      - "rq_out.results.versions.latest is defined" +      - "rq_out.results.versions.latest in rq_out.results.versions.available_versions" +      - "rq_out.results.versions.latest_full is defined" +      - "rq_out.results.versions.latest_full in rq_out.results.versions.available_versions_full" diff --git a/roles/lib_utils/src/test/unit/repoquery.py b/roles/lib_utils/src/test/unit/repoquery.py new file mode 100755 index 000000000..c487ab254 --- /dev/null +++ b/roles/lib_utils/src/test/unit/repoquery.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python2 +''' + Unit tests for repoquery +''' +# To run: +# ./repoquery.py +# +# . +# Ran 1 test in 0.002s +# +# OK + +import os +import sys +import unittest +import mock + +# Removing invalid variable names for tests so that I can +# keep them brief +# pylint: disable=invalid-name,no-name-in-module +# Disable import-error b/c our libraries aren't loaded in jenkins +# pylint: disable=import-error,wrong-import-position +# place class in our python path +module_path = os.path.join('/'.join(os.path.realpath(__file__).split('/')[:-4]), 'library')  # noqa: E501 +sys.path.insert(0, module_path) +from repoquery import Repoquery  # noqa: E402 + + +class RepoQueryTest(unittest.TestCase): +    ''' +     Test class for RepoQuery +    ''' + +    def setUp(self): +        ''' setup method for other tests ''' +        pass + +    @mock.patch('repoquery._run') +    def test_querying_a_package(self, mock_cmd): +        ''' Testing querying a package ''' + +        # Arrange + +        # run_ansible input parameters +        params = { +            'state': 'list', +            'name': 'bash', +            'query_type': 'repos', +            'verbose': False, +            'show_duplicates': False, +            'match_version': None, +        } + +        valid_stderr = '''Repo rhel-7-server-extras-rpms forced skip_if_unavailable=True due to: /etc/pki/entitlement/3268107132875399464-key.pem +        Repo rhel-7-server-rpms forced skip_if_unavailable=True due to: /etc/pki/entitlement/4128505182875899164-key.pem'''  # not real + +        # Return values of our mocked function call. These get returned once per call. +        mock_cmd.side_effect = [ +            (0, '4.2.46|21.el7_3|x86_64|rhel-7-server-rpms|4.2.46-21.el7_3', valid_stderr),  # first call to the mock +        ] + +        # Act +        results = Repoquery.run_ansible(params, False) + +        # Assert +        self.assertEqual(results['state'], 'list') +        self.assertFalse(results['changed']) +        self.assertTrue(results['results']['package_found']) +        self.assertEqual(results['results']['returncode'], 0) +        self.assertEqual(results['results']['package_name'], 'bash') +        self.assertEqual(results['results']['versions'], {'latest_full': '4.2.46-21.el7_3', +                                                          'available_versions': ['4.2.46'], +                                                          'available_versions_full': ['4.2.46-21.el7_3'], +                                                          'latest': '4.2.46'}) + +        # Making sure our mock was called as we expected +        mock_cmd.assert_has_calls([ +            mock.call(['/usr/bin/repoquery', '--plugins', '--quiet', '--pkgnarrow=repos', '--queryformat=%{version}|%{release}|%{arch}|%{repo}|%{version}-%{release}', 'bash']), +        ]) + +    def tearDown(self): +        '''TearDown method''' +        pass + + +if __name__ == "__main__": +    unittest.main() | 
