diff options
Diffstat (limited to 'roles/lib_openshift/src')
| -rw-r--r-- | roles/lib_openshift/src/ansible/oc_process.py | 32 | ||||
| -rw-r--r-- | roles/lib_openshift/src/class/oc_process.py | 188 | ||||
| -rw-r--r-- | roles/lib_openshift/src/doc/process | 84 | ||||
| -rw-r--r-- | roles/lib_openshift/src/sources.yml | 10 | ||||
| -rwxr-xr-x | roles/lib_openshift/src/test/integration/oc_process.yml | 83 | ||||
| -rwxr-xr-x | roles/lib_openshift/src/test/unit/oc_process.py | 483 | 
6 files changed, 880 insertions, 0 deletions
| diff --git a/roles/lib_openshift/src/ansible/oc_process.py b/roles/lib_openshift/src/ansible/oc_process.py new file mode 100644 index 000000000..17cf865b7 --- /dev/null +++ b/roles/lib_openshift/src/ansible/oc_process.py @@ -0,0 +1,32 @@ +# pylint: skip-file +# flake8: noqa + + +def main(): +    ''' +    ansible oc module for processing templates +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'), +            state=dict(default='present', type='str', choices=['present', 'list']), +            debug=dict(default=False, type='bool'), +            namespace=dict(default='default', type='str'), +            template_name=dict(default=None, type='str'), +            content=dict(default=None, type='str'), +            params=dict(default=None, type='dict'), +            create=dict(default=False, type='bool'), +            reconcile=dict(default=True, type='bool'), +        ), +        supports_check_mode=True, +    ) + +    rval = OCProcess.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_openshift/src/class/oc_process.py b/roles/lib_openshift/src/class/oc_process.py new file mode 100644 index 000000000..80d81448d --- /dev/null +++ b/roles/lib_openshift/src/class/oc_process.py @@ -0,0 +1,188 @@ +# pylint: skip-file +# flake8: noqa + + +# pylint: disable=too-many-instance-attributes +class OCProcess(OpenShiftCLI): +    ''' Class to wrap the oc command line tools ''' + +    # pylint allows 5. we need 6 +    # pylint: disable=too-many-arguments +    def __init__(self, +                 namespace, +                 tname=None, +                 params=None, +                 create=False, +                 kubeconfig='/etc/origin/master/admin.kubeconfig', +                 tdata=None, +                 verbose=False): +        ''' Constructor for OpenshiftOC ''' +        super(OCProcess, self).__init__(namespace, kubeconfig) +        self.namespace = namespace +        self.name = tname +        self.data = tdata +        self.params = params +        self.create = create +        self.kubeconfig = kubeconfig +        self.verbose = verbose +        self._template = None + +    @property +    def template(self): +        '''template property''' +        if self._template is None: +            results = self._process(self.name, False, self.params, self.data) +            if results['returncode'] != 0: +                raise OpenShiftCLIError('Error processing template [%s].' % self.name) +            self._template = results['results']['items'] + +        return self._template + +    def get(self): +        '''get the template''' +        results = self._get('template', self.name) +        if results['returncode'] != 0: +            # Does the template exist?? +            if 'not found' in results['stderr']: +                results['returncode'] = 0 +                results['exists'] = False +                results['results'] = [] + +        return results + +    def delete(self, obj): +        '''delete a resource''' +        return self._delete(obj['kind'], obj['metadata']['name']) + +    def create_obj(self, obj): +        '''create a resource''' +        return self._create_from_content(obj['metadata']['name'], obj) + +    def process(self, create=None): +        '''process a template''' +        do_create = False +        if create != None: +            do_create = create +        else: +            do_create = self.create + +        return self._process(self.name, do_create, self.params, self.data) + +    def exists(self): +        '''return whether the template exists''' +        # Always return true if we're being passed template data +        if self.data: +            return True +        t_results = self._get('template', self.name) + +        if t_results['returncode'] != 0: +            # Does the template exist?? +            if 'not found' in t_results['stderr']: +                return False +            else: +                raise OpenShiftCLIError('Something went wrong. %s' % t_results) + +        return True + +    def needs_update(self): +        '''attempt to process the template and return it for comparison with oc objects''' +        obj_results = [] +        for obj in self.template: + +            # build a list of types to skip +            skip = [] + +            if obj['kind'] == 'ServiceAccount': +                skip.extend(['secrets', 'imagePullSecrets']) +            if obj['kind'] == 'BuildConfig': +                skip.extend(['lastTriggeredImageID']) +            if obj['kind'] == 'ImageStream': +                skip.extend(['generation']) +            if obj['kind'] == 'DeploymentConfig': +                skip.extend(['lastTriggeredImage']) + +            # fetch the current object +            curr_obj_results = self._get(obj['kind'], obj['metadata']['name']) +            if curr_obj_results['returncode'] != 0: +                # Does the template exist?? +                if 'not found' in curr_obj_results['stderr']: +                    obj_results.append((obj, True)) +                    continue + +            # check the generated object against the existing object +            if not Utils.check_def_equal(obj, curr_obj_results['results'][0], skip_keys=skip): +                obj_results.append((obj, True)) +                continue + +            obj_results.append((obj, False)) + +        return obj_results + +    # pylint: disable=too-many-return-statements +    @staticmethod +    def run_ansible(params, check_mode): +        '''run the ansible idempotent code''' + +        ocprocess = OCProcess(params['namespace'], +                              params['template_name'], +                              params['params'], +                              params['create'], +                              kubeconfig=params['kubeconfig'], +                              tdata=params['content'], +                              verbose=params['debug']) + +        state = params['state'] + +        api_rval = ocprocess.get() + +        if state == 'list': +            if api_rval['returncode'] != 0: +                return {"failed": True, "msg" : api_rval} + +            return {"changed" : False, "results": api_rval, "state": "list"} + +        elif state == 'present': +            if check_mode and params['create']: +                return {"changed": True, 'msg': "CHECK_MODE: Would have processed template."} + +            if not ocprocess.exists() or not params['reconcile']: +            #FIXME: this code will never get run in a way that succeeds when +            #       module.params['reconcile'] is true. Because oc_process doesn't +            #       create the actual template, the check of ocprocess.exists() +            #       is meaningless. Either it's already here and this code +            #       won't be run, or this code will fail because there is no +            #       template available for oc process to use. Have we conflated +            #       the template's existence with the existence of the objects +            #       it describes? + +            # Create it here +                api_rval = ocprocess.process() +                if api_rval['returncode'] != 0: +                    return {"failed": True, "msg": api_rval} + +                if params['create']: +                    return {"changed": True, "results": api_rval, "state": "present"} + +                return {"changed": False, "results": api_rval, "state": "present"} + +        # verify results +        update = False +        rval = [] +        all_results = ocprocess.needs_update() +        for obj, status in all_results: +            if status: +                ocprocess.delete(obj) +                results = ocprocess.create_obj(obj) +                results['kind'] = obj['kind'] +                rval.append(results) +                update = True + +        if not update: +            return {"changed": update, "results": api_rval, "state": "present"} + +        for cmd in rval: +            if cmd['returncode'] != 0: +                return {"failed": True, "changed": update, "results": rval, "state": "present"} + +        return {"changed": update, "results": rval, "state": "present"} + diff --git a/roles/lib_openshift/src/doc/process b/roles/lib_openshift/src/doc/process new file mode 100644 index 000000000..86a854c07 --- /dev/null +++ b/roles/lib_openshift/src/doc/process @@ -0,0 +1,84 @@ +# flake8: noqa +# pylint: skip-file + +DOCUMENTATION = ''' +--- +module: oc_process +short_description: Module to process openshift templates +description: +  - Process openshift templates programmatically. +options: +  state: +    description: +    - State has a few different meanings when it comes to process. +    - state: present - This state runs an `oc process <template>`.  When used in +    - conjunction with 'create: True' the process will be piped to | oc create -f +    - state: absent - will remove a template +    - state: list - will perform an `oc get template <template_name>` +    default: present +    choices: ["present", "absent", "list"] +    aliases: [] +  kubeconfig: +    description: +    - The path for the kubeconfig file to use for authentication +    required: false +    default: /etc/origin/master/admin.kubeconfig +    aliases: [] +  debug: +    description: +    - Turn on debug output. +    required: false +    default: False +    aliases: [] +  template_name: +    description: +    - Name of the openshift template that is being processed. +    required: false +    default: None +    aliases: [] +  namespace: +    description: +    - The namespace where the template lives. +    required: false +    default: default +    aliases: [] +  content: +    description: +    - Template content that will be processed. +    required: false +    default: None +    aliases: [] +  params: +    description: +    - A list of parameters that will be inserted into the template. +    required: false +    default: None +    aliases: [] +  create: +    description: +    - Whether or not to create the template after being processed. e.g.  oc process | oc create -f - +    required: False +    default: False +    aliases: [] +  reconcile: +    description: +    - Whether or not to attempt to determine if there are updates or changes in the incoming template. +    default: true +    aliases: [] +author: +- "Kenny Woodson <kwoodson@redhat.com>" +extends_documentation_fragment: [] +''' + +EXAMPLES = ''' +- name: process the cloud volume provisioner template with variables +  oc_process: +    namespace: openshift-infra +    template_name: online-volume-provisioner +    create: True +    params: +      PLAT: rhel7 +  register: processout +  run_once: true +- debug: var=processout +''' diff --git a/roles/lib_openshift/src/sources.yml b/roles/lib_openshift/src/sources.yml index aa02ce120..e9056655d 100644 --- a/roles/lib_openshift/src/sources.yml +++ b/roles/lib_openshift/src/sources.yml @@ -39,6 +39,16 @@ oc_obj.py:  - class/oc_obj.py  - ansible/oc_obj.py +oc_process.py: +- doc/generated +- doc/license +- lib/import.py +- doc/process +- ../../lib_utils/src/class/yedit.py +- lib/base.py +- class/oc_process.py +- ansible/oc_process.py +  oc_route.py:  - doc/generated  - doc/license diff --git a/roles/lib_openshift/src/test/integration/oc_process.yml b/roles/lib_openshift/src/test/integration/oc_process.yml new file mode 100755 index 000000000..7ea4c6b99 --- /dev/null +++ b/roles/lib_openshift/src/test/integration/oc_process.yml @@ -0,0 +1,83 @@ +#!/usr/bin/ansible-playbook --module-path=../../../library/:../../../../lib_utils/library + +--- +- hosts: "{{ cli_master_test }}" +  gather_facts: no +  user: root +  vars: +    template_name: mysql-ephemeral +    ns_name: test + +  post_tasks: +  - name: get the mysql-ephemeral template +    oc_obj: +      name: mysql-ephemeral +      state: list +      namespace: openshift +      kind: template +    register: mysqltempl + +  - name: fix namespace +    yedit: +      src: /tmp/mysql-template +      key: metadata.namespace +      value: test +      backup: false +      content: "{{ mysqltempl.results.results[0] | to_yaml }}" + +  - name: create the test namespace +    oc_obj: +      name: test +      state: present +      namespace: test +      kind: namespace +      content: +        path: /tmp/ns_test +        data: +          apiVersion: v1 +          kind: Namespace +          metadata: +            name: test +          spec: +            finalizers: +            - openshift.io/origin +            - kubernetes +    register: mysqltempl + +  - name: create the mysql-ephemeral template +    oc_obj: +      name: mysql-ephemeral +      state: present +      namespace: test +      kind: template +      files: +      - /tmp/mysql-template +      delete_after: True +    register: mysqltempl + +  - name: process mysql-ephemeral +    oc_process: +      template_name: mysql-ephemeral +      namespace: test +      params: +        NAMESPACE: test +        DATABASE_SERVICE_NAME: testdb +      create: False +      reconcile: false +    register: procout + +  - assert: +      that: +      - not procout.changed +      - procout.results.results['items'][0]['metadata']['name'] == 'testdb' +      - procout.results.results['items'][0]['kind'] == 'Service' +      - procout.results.results['items'][1]['metadata']['name'] == 'testdb' +      - procout.results.results['items'][1]['kind'] == 'DeploymentConfig' +      msg: process failed on template + +  - name: remove namespace test +    oc_obj: +      kind: namespace +      name: test +      namespace: test +      state: absent diff --git a/roles/lib_openshift/src/test/unit/oc_process.py b/roles/lib_openshift/src/test/unit/oc_process.py new file mode 100755 index 000000000..450ff7071 --- /dev/null +++ b/roles/lib_openshift/src/test/unit/oc_process.py @@ -0,0 +1,483 @@ +#!/usr/bin/env python2 +''' + Unit tests for oc process +''' +# To run +# python -m unittest version +# +# . +# Ran 1 test in 0.597s +# +# 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 +# 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 oc_process import OCProcess  # noqa: E402 + + +# pylint: disable=too-many-public-methods +class OCProcessTest(unittest.TestCase): +    ''' +     Test class for OCProcess +    ''' +    mysql = '''{ +    "kind": "Template", +    "apiVersion": "v1", +    "metadata": { +        "name": "mysql-ephemeral", +        "namespace": "openshift", +        "selfLink": "/oapi/v1/namespaces/openshift/templates/mysql-ephemeral", +        "uid": "fb8b5f04-e3d3-11e6-a982-0e84250fc302", +        "resourceVersion": "480", +        "creationTimestamp": "2017-01-26T14:30:27Z", +        "annotations": { +            "iconClass": "icon-mysql-database", +            "openshift.io/display-name": "MySQL (Ephemeral)", +            "tags": "database,mysql" +        } +    }, +    "objects": [ +        { +            "apiVersion": "v1", +            "kind": "Service", +            "metadata": { +                "creationTimestamp": null, +                "name": "${DATABASE_SERVICE_NAME}" +            }, +            "spec": { +                "ports": [ +                    { +                        "name": "mysql", +                        "nodePort": 0, +                        "port": 3306, +                        "protocol": "TCP", +                        "targetPort": 3306 +                    } +                ], +                "selector": { +                    "name": "${DATABASE_SERVICE_NAME}" +                }, +                "sessionAffinity": "None", +                "type": "ClusterIP" +            }, +            "status": { +                "loadBalancer": {} +            } +        }, +        { +            "apiVersion": "v1", +            "kind": "DeploymentConfig", +            "metadata": { +                "creationTimestamp": null, +                "name": "${DATABASE_SERVICE_NAME}" +            }, +            "spec": { +                "replicas": 1, +                "selector": { +                    "name": "${DATABASE_SERVICE_NAME}" +                }, +                "strategy": { +                    "type": "Recreate" +                }, +                "template": { +                    "metadata": { +                        "creationTimestamp": null, +                        "labels": { +                            "name": "${DATABASE_SERVICE_NAME}" +                        } +                    }, +                    "spec": { +                        "containers": [ +                            { +                                "capabilities": {}, +                                "env": [ +                                    { +                                        "name": "MYSQL_USER", +                                        "value": "${MYSQL_USER}" +                                    }, +                                    { +                                        "name": "MYSQL_PASSWORD", +                                        "value": "${MYSQL_PASSWORD}" +                                    }, +                                    { +                                        "name": "MYSQL_DATABASE", +                                        "value": "${MYSQL_DATABASE}" +                                    } +                                ], +                                "image": " ", +                                "imagePullPolicy": "IfNotPresent", +                                "livenessProbe": { +                                    "initialDelaySeconds": 30, +                                    "tcpSocket": { +                                        "port": 3306 +                                    }, +                                    "timeoutSeconds": 1 +                                }, +                                "name": "mysql", +                                "ports": [ +                                    { +                                        "containerPort": 3306, +                                        "protocol": "TCP" +                                    } +                                ], +                                "readinessProbe": { +                                    "exec": { +                                        "command": [ +                                            "/bin/sh", +                                            "-i", +                                            "-c", +                                            "MYSQL_PWD=$MYSQL_PASSWORD mysql -h 127.0.0.1 -u $MYSQL_USER -D $MYSQL_DATABASE -e 'SELECT 1'" +                                        ] +                                    }, +                                    "initialDelaySeconds": 5, +                                    "timeoutSeconds": 1 +                                }, +                                "resources": { +                                    "limits": { +                                        "memory": "${MEMORY_LIMIT}" +                                    } +                                }, +                                "securityContext": { +                                    "capabilities": {}, +                                    "privileged": false +                                }, +                                "terminationMessagePath": "/dev/termination-log", +                                "volumeMounts": [ +                                    { +                                        "mountPath": "/var/lib/mysql/data", +                                        "name": "${DATABASE_SERVICE_NAME}-data" +                                    } +                                ] +                            } +                        ], +                        "dnsPolicy": "ClusterFirst", +                        "restartPolicy": "Always", +                        "volumes": [ +                            { +                                "emptyDir": { +                                    "medium": "" +                                }, +                                "name": "${DATABASE_SERVICE_NAME}-data" +                            } +                        ] +                    } +                }, +                "triggers": [ +                    { +                        "imageChangeParams": { +                            "automatic": true, +                            "containerNames": [ +                                "mysql" +                            ], +                            "from": { +                                "kind": "ImageStreamTag", +                                "name": "mysql:${MYSQL_VERSION}", +                                "namespace": "${NAMESPACE}" +                            }, +                            "lastTriggeredImage": "" +                        }, +                        "type": "ImageChange" +                    }, +                    { +                        "type": "ConfigChange" +                    } +                ] +            }, +            "status": {} +        } +    ], +    "parameters": [ +        { +            "name": "MEMORY_LIMIT", +            "displayName": "Memory Limit", +            "description": "Maximum amount of memory the container can use.", +            "value": "512Mi" +        }, +        { +            "name": "NAMESPACE", +            "displayName": "Namespace", +            "description": "The OpenShift Namespace where the ImageStream resides.", +            "value": "openshift" +        }, +        { +            "name": "DATABASE_SERVICE_NAME", +            "displayName": "Database Service Name", +            "description": "The name of the OpenShift Service exposed for the database.", +            "value": "mysql", +            "required": true +        }, +        { +            "name": "MYSQL_USER", +            "displayName": "MySQL Connection Username", +            "description": "Username for MySQL user that will be used for accessing the database.", +            "generate": "expression", +            "from": "user[A-Z0-9]{3}", +            "required": true +        }, +        { +            "name": "MYSQL_PASSWORD", +            "displayName": "MySQL Connection Password", +            "description": "Password for the MySQL connection user.", +            "generate": "expression", +            "from": "[a-zA-Z0-9]{16}", +            "required": true +        }, +        { +            "name": "MYSQL_DATABASE", +            "displayName": "MySQL Database Name", +            "description": "Name of the MySQL database accessed.", +            "value": "sampledb", +            "required": true +        }, +        { +            "name": "MYSQL_VERSION", +            "displayName": "Version of MySQL Image", +            "description": "Version of MySQL image to be used (5.5, 5.6 or latest).", +            "value": "5.6", +            "required": true +        } +    ], +    "labels": { +        "template": "mysql-ephemeral-template" +    } +}''' + +    def setUp(self): +        ''' setup method will set to known configuration ''' +        pass + +    @mock.patch('oc_process.Utils.create_tmpfile_copy') +    @mock.patch('oc_process.OCProcess._run') +    def test_state_list(self, mock_cmd, mock_tmpfile_copy): +        ''' Testing a get ''' +        params = {'template_name': 'mysql-ephermeral', +                  'namespace': 'test', +                  'content': None, +                  'state': 'list', +                  'reconcile': False, +                  'create': False, +                  'params': {'NAMESPACE': 'test', 'DATABASE_SERVICE_NAME': 'testdb'}, +                  'kubeconfig': '/etc/origin/master/admin.kubeconfig', +                  'debug': False} + +        mock_cmd.side_effect = [ +            (0, OCProcessTest.mysql, '') +        ] + +        mock_tmpfile_copy.side_effect = [ +            '/tmp/mock_kubeconfig', +        ] + +        results = OCProcess.run_ansible(params, False) + +        self.assertFalse(results['changed']) +        self.assertEqual(results['results']['results'][0]['metadata']['name'], 'mysql-ephemeral') + +    @mock.patch('oc_process.Utils.create_tmpfile_copy') +    @mock.patch('oc_process.OCProcess._run') +    def test_process_no_create(self, mock_cmd, mock_tmpfile_copy): +        ''' Testing a process with no create ''' +        params = {'template_name': 'mysql-ephermeral', +                  'namespace': 'test', +                  'content': None, +                  'state': 'present', +                  'reconcile': False, +                  'create': False, +                  'params': {'NAMESPACE': 'test', 'DATABASE_SERVICE_NAME': 'testdb'}, +                  'kubeconfig': '/etc/origin/master/admin.kubeconfig', +                  'debug': False} + +        mysqlproc = '''{ +    "kind": "List", +    "apiVersion": "v1", +    "metadata": {}, +    "items": [ +        { +            "apiVersion": "v1", +            "kind": "Service", +            "metadata": { +                "creationTimestamp": null, +                "labels": { +                    "template": "mysql-ephemeral-template" +                }, +                "name": "testdb" +            }, +            "spec": { +                "ports": [ +                    { +                        "name": "mysql", +                        "nodePort": 0, +                        "port": 3306, +                        "protocol": "TCP", +                        "targetPort": 3306 +                    } +                ], +                "selector": { +                    "name": "testdb" +                }, +                "sessionAffinity": "None", +                "type": "ClusterIP" +            }, +            "status": { +                "loadBalancer": {} +            } +        }, +        { +            "apiVersion": "v1", +            "kind": "DeploymentConfig", +            "metadata": { +                "creationTimestamp": null, +                "labels": { +                    "template": "mysql-ephemeral-template" +                }, +                "name": "testdb" +            }, +            "spec": { +                "replicas": 1, +                "selector": { +                    "name": "testdb" +                }, +                "strategy": { +                    "type": "Recreate" +                }, +                "template": { +                    "metadata": { +                        "creationTimestamp": null, +                        "labels": { +                            "name": "testdb" +                        } +                    }, +                    "spec": { +                        "containers": [ +                            { +                                "capabilities": {}, +                                "env": [ +                                    { +                                        "name": "MYSQL_USER", +                                        "value": "userHJJ" +                                    }, +                                    { +                                        "name": "MYSQL_PASSWORD", +                                        "value": "GITOAduAMaV6k688" +                                    }, +                                    { +                                        "name": "MYSQL_DATABASE", +                                        "value": "sampledb" +                                    } +                                ], +                                "image": " ", +                                "imagePullPolicy": "IfNotPresent", +                                "livenessProbe": { +                                    "initialDelaySeconds": 30, +                                    "tcpSocket": { +                                        "port": 3306 +                                    }, +                                    "timeoutSeconds": 1 +                                }, +                                "name": "mysql", +                                "ports": [ +                                    { +                                        "containerPort": 3306, +                                        "protocol": "TCP" +                                    } +                                ], +                                "readinessProbe": { +                                    "exec": { +                                        "command": [ +                                            "/bin/sh", +                                            "-i", +                                            "-c", +                                            "MYSQL_PWD=$MYSQL_PASSWORD mysql -h 127.0.0.1 -u $MYSQL_USER -D $MYSQL_DATABASE -e 'SELECT 1'" +                                        ] +                                    }, +                                    "initialDelaySeconds": 5, +                                    "timeoutSeconds": 1 +                                }, +                                "resources": { +                                    "limits": { +                                        "memory": "512Mi" +                                    } +                                }, +                                "securityContext": { +                                    "capabilities": {}, +                                    "privileged": false +                                }, +                                "terminationMessagePath": "/dev/termination-log", +                                "volumeMounts": [ +                                    { +                                        "mountPath": "/var/lib/mysql/data", +                                        "name": "testdb-data" +                                    } +                                ] +                            } +                        ], +                        "dnsPolicy": "ClusterFirst", +                        "restartPolicy": "Always", +                        "volumes": [ +                            { +                                "emptyDir": { +                                    "medium": "" +                                }, +                                "name": "testdb-data" +                            } +                        ] +                    } +                }, +                "triggers": [ +                    { +                        "imageChangeParams": { +                            "automatic": true, +                            "containerNames": [ +                                "mysql" +                            ], +                            "from": { +                                "kind": "ImageStreamTag", +                                "name": "mysql:5.6", +                                "namespace": "test" +                            }, +                            "lastTriggeredImage": "" +                        }, +                        "type": "ImageChange" +                    }, +                    { +                        "type": "ConfigChange" +                    } +                ] +            } +        } +    ] +}''' + +        mock_cmd.side_effect = [ +            (0, OCProcessTest.mysql, ''), +            (0, OCProcessTest.mysql, ''), +            (0, mysqlproc, ''), +        ] + +        mock_tmpfile_copy.side_effect = [ +            '/tmp/mock_kubeconfig', +        ] + +        results = OCProcess.run_ansible(params, False) + +        self.assertFalse(results['changed']) +        self.assertEqual(results['results']['results']['items'][0]['metadata']['name'], 'testdb') + +    def tearDown(self): +        '''TearDown method''' +        pass + + +if __name__ == "__main__": +    unittest.main() | 
