diff options
| author | Kenny Woodson <kwoodson@redhat.com> | 2016-03-24 16:18:51 -0400 | 
|---|---|---|
| committer | Kenny Woodson <kwoodson@redhat.com> | 2016-03-24 16:18:51 -0400 | 
| commit | 9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9 (patch) | |
| tree | 8a8e1653684324fc4b9502542fdba509592e8ef6 /roles/lib_openshift_api | |
| parent | 7b0a4588a728a5eb5cbf7f80ff48f7f1d704238e (diff) | |
| parent | e25f7c86d6c31e325cb2c1790e8f6049d05332d0 (diff) | |
| download | openshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.tar.gz openshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.tar.bz2 openshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.tar.xz openshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.zip | |
Merge pull request #1664 from kwoodson/api_dc
Deployment config module
Diffstat (limited to 'roles/lib_openshift_api')
| -rw-r--r-- | roles/lib_openshift_api/library/oc_deploymentconfig.py | 377 | ||||
| -rw-r--r-- | roles/lib_openshift_api/library/oc_secret.py | 85 | ||||
| -rw-r--r-- | roles/lib_openshift_api/library/oc_service.py | 96 | 
3 files changed, 490 insertions, 68 deletions
| diff --git a/roles/lib_openshift_api/library/oc_deploymentconfig.py b/roles/lib_openshift_api/library/oc_deploymentconfig.py new file mode 100644 index 000000000..fbdaa8e9c --- /dev/null +++ b/roles/lib_openshift_api/library/oc_deploymentconfig.py @@ -0,0 +1,377 @@ +#!/usr/bin/env python +''' +  OpenShiftCLI class that wraps the oc commands in a subprocess +''' +import atexit +import json +import os +import shutil +import subprocess +import yaml + +class OpenShiftCLI(object): +    ''' Class to wrap the oc command line tools ''' +    def __init__(self, +                 namespace, +                 kubeconfig='/etc/origin/master/admin.kubeconfig', +                 verbose=False): +        ''' Constructor for OpenshiftOC ''' +        self.namespace = namespace +        self.verbose = verbose +        self.kubeconfig = kubeconfig + +    def replace(self, fname, force=False): +        '''return all pods ''' +        cmd = ['replace', '-f', fname] +        if force: +            cmd = ['replace', '--force', '-f', fname] +        return self.oc_cmd(cmd) + +    def create(self, fname): +        '''return all pods ''' +        return self.oc_cmd(['create', '-f', fname, '-n', self.namespace]) + +    def delete(self, resource, rname): +        '''return all pods ''' +        return self.oc_cmd(['delete', resource, rname, '-n', self.namespace]) + +    def get(self, resource, rname=None): +        '''return a secret by name ''' +        cmd = ['get', resource, '-o', 'json', '-n', self.namespace] +        if rname: +            cmd.append(rname) + +        rval = self.oc_cmd(cmd, output=True) + +        # Ensure results are retuned in an array +        if rval.has_key('items'): +            rval['results'] = rval['items'] +        elif not isinstance(rval['results'], list): +            rval['results'] = [rval['results']] + +        return rval + +    def oc_cmd(self, cmd, output=False): +        '''Base command for oc ''' +        #cmds = ['/usr/bin/oc', '--config', self.kubeconfig] +        cmds = ['/usr/bin/oc'] +        cmds.extend(cmd) + +        results = '' + +        if self.verbose: +            print ' '.join(cmds) + +        proc = subprocess.Popen(cmds, +                                stdout=subprocess.PIPE, +                                stderr=subprocess.PIPE, +                                env={'KUBECONFIG': self.kubeconfig}) +        proc.wait() +        if proc.returncode == 0: +            if output: +                try: +                    results = json.loads(proc.stdout.read()) +                except ValueError as err: +                    if "No JSON object could be decoded" in err.message: +                        results = err.message + +            if self.verbose: +                print proc.stderr.read() +                print results +                print + +            return {"returncode": proc.returncode, "results": results} + +        return {"returncode": proc.returncode, +                "stderr": proc.stderr.read(), +                "stdout": proc.stdout.read(), +                "results": {} +               } + +class Utils(object): +    ''' utilities for openshiftcli modules ''' +    @staticmethod +    def create_file(rname, data, ftype=None): +        ''' create a file in tmp with name and contents''' +        path = os.path.join('/tmp', rname) +        with open(path, 'w') as fds: +            if ftype == 'yaml': +                fds.write(yaml.dump(data, default_flow_style=False)) + +            elif ftype == 'json': +                fds.write(json.dumps(data)) +            else: +                fds.write(data) + +        # Register cleanup when module is done +        atexit.register(Utils.cleanup, [path]) +        return path + +    @staticmethod +    def create_files_from_contents(data): +        '''Turn an array of dict: filename, content into a files array''' +        files = [] + +        for sfile in data: +            path = Utils.create_file(sfile['path'], sfile['content']) +            files.append(path) + +        return files + +    @staticmethod +    def cleanup(files): +        '''Clean up on exit ''' +        for sfile in files: +            if os.path.exists(sfile): +                if os.path.isdir(sfile): +                    shutil.rmtree(sfile) +                elif os.path.isfile(sfile): +                    os.remove(sfile) + + +    @staticmethod +    def exists(results, _name): +        ''' Check to see if the results include the name ''' +        if not results: +            return False + + +        if Utils.find_result(results, _name): +            return True + +        return False + +    @staticmethod +    def find_result(results, _name): +        ''' Find the specified result by name''' +        rval = None +        for result in results: +            if result.has_key('metadata') and result['metadata']['name'] == _name: +                rval = result +                break + +        return rval + +    @staticmethod +    def get_resource_file(sfile, sfile_type='yaml'): +        ''' return the service file  ''' +        contents = None +        with open(sfile) as sfd: +            contents = sfd.read() + +        if sfile_type == 'yaml': +            contents = yaml.load(contents) +        elif sfile_type == 'json': +            contents = json.loads(contents) + +        return contents + +    # Disabling too-many-branches.  This is a yaml dictionary comparison function +    # pylint: disable=too-many-branches,too-many-return-statements +    @staticmethod +    def check_def_equal(user_def, result_def, debug=False): +        ''' Given a user defined definition, compare it with the results given back by our query.  ''' + +        # Currently these values are autogenerated and we do not need to check them +        skip = ['creationTimestamp', 'selfLink', 'resourceVersion', 'uid', 'namespace'] + +        for key, value in result_def.items(): +            if key in skip: +                continue + +            # Both are lists +            if isinstance(value, list): +                if not isinstance(user_def[key], list): +                    return False + +                # lists should be identical +                if value != user_def[key]: +                    return False + +            # recurse on a dictionary +            elif isinstance(value, dict): +                if not isinstance(user_def[key], dict): +                    if debug: +                        print "dict returned false not instance of dict" +                    return False + +                # before passing ensure keys match +                api_values = set(value.keys()) - set(skip) +                user_values = set(user_def[key].keys()) - set(skip) +                if api_values != user_values: +                    if debug: +                        print api_values +                        print user_values +                        print "keys are not equal in dict" +                    return False + +                result = Utils.check_def_equal(user_def[key], value, debug=debug) +                if not result: +                    if debug: +                        print "dict returned false" +                    return False + +            # Verify each key, value pair is the same +            else: +                if not user_def.has_key(key) or value != user_def[key]: +                    if debug: +                        print "value not equal; user_def does not have key" +                        print value +                        print user_def[key] +                    return False + +        return True + +class DeploymentConfig(OpenShiftCLI): +    ''' Class to wrap the oc command line tools +    ''' +    def __init__(self, +                 namespace, +                 dname=None, +                 kubeconfig='/etc/origin/master/admin.kubeconfig', +                 verbose=False): +        ''' Constructor for OpenshiftOC ''' +        super(DeploymentConfig, self).__init__(namespace, kubeconfig) +        self.namespace = namespace +        self.name = dname +        self.kubeconfig = kubeconfig +        self.verbose = verbose + +    def get_dc(self): +        '''return a deploymentconfig by name ''' +        return self.get('dc', self.name) + +    def delete_dc(self): +        '''return all pods ''' +        return self.delete('dc', self.name) + +    def new_dc(self, dfile): +        '''Create a deploymentconfig ''' +        return self.create(dfile) + +    def update_dc(self, dfile, force=False): +        '''run update dc + +           This receives a list of file names and takes the first filename and calls replace. +        ''' +        return self.replace(dfile, force) + + +# pylint: disable=too-many-branches +def main(): +    ''' +    ansible oc module for deploymentconfig +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'), +            state=dict(default='present', type='str', +                       choices=['present', 'absent', 'list']), +            debug=dict(default=False, type='bool'), +            namespace=dict(default='default', type='str'), +            name=dict(default=None, type='str'), +            deploymentconfig_file=dict(default=None, type='str'), +            input_type=dict(default='yaml', choices=['yaml', 'json'], type='str'), +            delete_after=dict(default=False, type='bool'), +            content=dict(default=None, type='dict'), +            force=dict(default=False, type='bool'), +        ), +        mutually_exclusive=[["contents", "deploymentconfig_file"]], + +        supports_check_mode=True, +    ) +    occmd = DeploymentConfig(module.params['namespace'], +                             dname=module.params['name'], +                             kubeconfig=module.params['kubeconfig'], +                             verbose=module.params['debug']) + +    state = module.params['state'] + +    api_rval = occmd.get_dc() + +    ##### +    # Get +    ##### +    if state == 'list': +        module.exit_json(changed=False, results=api_rval['results'], state="list") + +    if not module.params['name']: +        module.fail_json(msg='Please specify a name when state is absent|present.') +    ######## +    # Delete +    ######## +    if state == 'absent': +        if not Utils.exists(api_rval['results'], module.params['name']): +            module.exit_json(changed=False, state="absent") + +        if module.check_mode: +            module.exit_json(change=False, msg='Would have performed a delete.') + +        api_rval = occmd.delete_dc() +        module.exit_json(changed=True, results=api_rval, state="absent") + + +    if state == 'present': +        if module.params['deploymentconfig_file']: +            dfile = module.params['deploymentconfig_file'] +        elif module.params['content']: +            dfile = Utils.create_file('dc', module.params['content']) +        else: +            module.fail_json(msg="Please specify content or deploymentconfig file.") + +        ######## +        # Create +        ######## +        if not Utils.exists(api_rval['results'], module.params['name']): + +            if module.check_mode: +                module.exit_json(change=False, msg='Would have performed a create.') + +            api_rval = occmd.new_dc(dfile) + +            # Remove files +            if module.params['deploymentconfig_file'] and module.params['delete_after']: +                Utils.cleanup([dfile]) + +            if api_rval['returncode'] != 0: +                module.fail_json(msg=api_rval) + +            module.exit_json(changed=True, results=api_rval, state="present") + +        ######## +        # Update +        ######## +        if Utils.check_def_equal(Utils.get_resource_file(dfile), api_rval['results'][0]): + +            # Remove files +            if module.params['deploymentconfig_file'] and module.params['delete_after']: +                Utils.cleanup([dfile]) + +            module.exit_json(changed=False, results=api_rval['results'], state="present") + +        if module.check_mode: +            module.exit_json(change=False, msg='Would have performed an update.') + +        api_rval = occmd.update_dc(dfile, force=module.params['force']) + +        # Remove files +        if module.params['deploymentconfig_file'] and module.params['delete_after']: +            Utils.cleanup([dfile]) + +        if api_rval['returncode'] != 0: +            module.fail_json(msg=api_rval) + + +        module.exit_json(changed=True, results=api_rval, state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_openshift_api/library/oc_secret.py b/roles/lib_openshift_api/library/oc_secret.py index d69d490ac..96a0f1db1 100644 --- a/roles/lib_openshift_api/library/oc_secret.py +++ b/roles/lib_openshift_api/library/oc_secret.py @@ -9,9 +9,6 @@ import shutil  import subprocess  import yaml -# The base class is here to share methods. -# Currently there is only 1 but will grow in the future. -# pylint: disable=too-few-public-methods  class OpenShiftCLI(object):      ''' Class to wrap the oc command line tools '''      def __init__(self, @@ -23,6 +20,37 @@ class OpenShiftCLI(object):          self.verbose = verbose          self.kubeconfig = kubeconfig +    def replace(self, fname, force=False): +        '''return all pods ''' +        cmd = ['replace', '-f', fname] +        if force: +            cmd = ['replace', '--force', '-f', fname] +        return self.oc_cmd(cmd) + +    def create(self, fname): +        '''return all pods ''' +        return self.oc_cmd(['create', '-f', fname, '-n', self.namespace]) + +    def delete(self, resource, rname): +        '''return all pods ''' +        return self.oc_cmd(['delete', resource, rname, '-n', self.namespace]) + +    def get(self, resource, rname=None): +        '''return a secret by name ''' +        cmd = ['get', resource, '-o', 'json', '-n', self.namespace] +        if rname: +            cmd.append(rname) + +        rval = self.oc_cmd(cmd, output=True) + +        # Ensure results are retuned in an array +        if rval.has_key('items'): +            rval['results'] = rval['items'] +        elif not isinstance(rval['results'], list): +            rval['results'] = [rval['results']] + +        return rval +      def oc_cmd(self, cmd, output=False):          '''Base command for oc '''          #cmds = ['/usr/bin/oc', '--config', self.kubeconfig] @@ -63,21 +91,33 @@ class OpenShiftCLI(object):  class Utils(object):      ''' utilities for openshiftcli modules '''      @staticmethod +    def create_file(rname, data, ftype=None): +        ''' create a file in tmp with name and contents''' +        path = os.path.join('/tmp', rname) +        with open(path, 'w') as fds: +            if ftype == 'yaml': +                fds.write(yaml.dump(data, default_flow_style=False)) + +            elif ftype == 'json': +                fds.write(json.dumps(data)) +            else: +                fds.write(data) + +        # Register cleanup when module is done +        atexit.register(Utils.cleanup, [path]) +        return path + +    @staticmethod      def create_files_from_contents(data):          '''Turn an array of dict: filename, content into a files array'''          files = []          for sfile in data: -            path = os.path.join('/tmp', sfile['path']) -            with open(path, 'w') as fds: -                fds.write(sfile['content']) +            path = Utils.create_file(sfile['path'], sfile['content'])              files.append(path) -        # Register cleanup when module is done -        atexit.register(Utils.cleanup, files)          return files -      @staticmethod      def cleanup(files):          '''Clean up on exit ''' @@ -106,7 +146,6 @@ class Utils(object):          ''' Find the specified result by name'''          rval = None          for result in results: -            #print "%s == %s" % (result['metadata']['name'], name)              if result.has_key('metadata') and result['metadata']['name'] == _name:                  rval = result                  break @@ -166,7 +205,7 @@ class Utils(object):                          print "keys are not equal in dict"                      return False -                result = Utils.check_def_equal(user_def[key], value) +                result = Utils.check_def_equal(user_def[key], value, debug=debug)                  if not result:                      if debug:                          print "dict returned false" @@ -192,7 +231,7 @@ class Secret(OpenShiftCLI):                   kubeconfig='/etc/origin/master/admin.kubeconfig',                   verbose=False):          ''' Constructor for OpenshiftOC ''' -        super(Secret, OpenShiftCLI).__init__(namespace, kubeconfig) +        super(Secret, self).__init__(namespace, kubeconfig)          self.namespace = namespace          self.name = secret_name          self.kubeconfig = kubeconfig @@ -200,23 +239,11 @@ class Secret(OpenShiftCLI):      def get_secrets(self):          '''return a secret by name ''' -        cmd = ['get', 'secrets', '-o', 'json', '-n', self.namespace] -        if self.name: -            cmd.append(self.name) - -        rval = self.oc_cmd(cmd, output=True) - -        # Ensure results are retuned in an array -        if rval.has_key('items'): -            rval['results'] = rval['items'] -        elif not isinstance(rval['results'], list): -            rval['results'] = [rval['results']] - -        return rval +        return self.get('secrets', self.name)      def delete_secret(self):          '''return all pods ''' -        return self.oc_cmd(['delete', 'secrets', self.name, '-n', self.namespace]) +        return self.delete('secrets', self.name)      def secret_new(self, files=None, contents=None):          '''Create a secret with  all pods ''' @@ -243,13 +270,9 @@ class Secret(OpenShiftCLI):          with open(sfile_path, 'w') as sfd:              sfd.write(json.dumps(secret['results'])) -        cmd = ['replace', '-f', sfile_path] -        if force: -            cmd = ['replace', '--force', '-f', sfile_path] -          atexit.register(Utils.cleanup, [sfile_path]) -        return self.oc_cmd(cmd) +        return self.replace(sfile_path, force=force)      def prep_secret(self, files=None, contents=None):          ''' return what the secret would look like if created diff --git a/roles/lib_openshift_api/library/oc_service.py b/roles/lib_openshift_api/library/oc_service.py index 48281f254..e7bd2514e 100644 --- a/roles/lib_openshift_api/library/oc_service.py +++ b/roles/lib_openshift_api/library/oc_service.py @@ -9,9 +9,6 @@ import shutil  import subprocess  import yaml -# The base class is here to share methods. -# Currently there is only 1 but will grow in the future. -# pylint: disable=too-few-public-methods  class OpenShiftCLI(object):      ''' Class to wrap the oc command line tools '''      def __init__(self, @@ -23,6 +20,37 @@ class OpenShiftCLI(object):          self.verbose = verbose          self.kubeconfig = kubeconfig +    def replace(self, fname, force=False): +        '''return all pods ''' +        cmd = ['replace', '-f', fname] +        if force: +            cmd = ['replace', '--force', '-f', fname] +        return self.oc_cmd(cmd) + +    def create(self, fname): +        '''return all pods ''' +        return self.oc_cmd(['create', '-f', fname, '-n', self.namespace]) + +    def delete(self, resource, rname): +        '''return all pods ''' +        return self.oc_cmd(['delete', resource, rname, '-n', self.namespace]) + +    def get(self, resource, rname=None): +        '''return a secret by name ''' +        cmd = ['get', resource, '-o', 'json', '-n', self.namespace] +        if rname: +            cmd.append(rname) + +        rval = self.oc_cmd(cmd, output=True) + +        # Ensure results are retuned in an array +        if rval.has_key('items'): +            rval['results'] = rval['items'] +        elif not isinstance(rval['results'], list): +            rval['results'] = [rval['results']] + +        return rval +      def oc_cmd(self, cmd, output=False):          '''Base command for oc '''          #cmds = ['/usr/bin/oc', '--config', self.kubeconfig] @@ -63,21 +91,33 @@ class OpenShiftCLI(object):  class Utils(object):      ''' utilities for openshiftcli modules '''      @staticmethod +    def create_file(rname, data, ftype=None): +        ''' create a file in tmp with name and contents''' +        path = os.path.join('/tmp', rname) +        with open(path, 'w') as fds: +            if ftype == 'yaml': +                fds.write(yaml.dump(data, default_flow_style=False)) + +            elif ftype == 'json': +                fds.write(json.dumps(data)) +            else: +                fds.write(data) + +        # Register cleanup when module is done +        atexit.register(Utils.cleanup, [path]) +        return path + +    @staticmethod      def create_files_from_contents(data):          '''Turn an array of dict: filename, content into a files array'''          files = []          for sfile in data: -            path = os.path.join('/tmp', sfile['path']) -            with open(path, 'w') as fds: -                fds.write(sfile['content']) +            path = Utils.create_file(sfile['path'], sfile['content'])              files.append(path) -        # Register cleanup when module is done -        atexit.register(Utils.cleanup, files)          return files -      @staticmethod      def cleanup(files):          '''Clean up on exit ''' @@ -106,7 +146,6 @@ class Utils(object):          ''' Find the specified result by name'''          rval = None          for result in results: -            #print "%s == %s" % (result['metadata']['name'], name)              if result.has_key('metadata') and result['metadata']['name'] == _name:                  rval = result                  break @@ -166,7 +205,7 @@ class Utils(object):                          print "keys are not equal in dict"                      return False -                result = Utils.check_def_equal(user_def[key], value) +                result = Utils.check_def_equal(user_def[key], value, debug=debug)                  if not result:                      if debug:                          print "dict returned false" @@ -192,7 +231,7 @@ class Service(OpenShiftCLI):                   kubeconfig='/etc/origin/master/admin.kubeconfig',                   verbose=False):          ''' Constructor for OpenshiftOC ''' -        super(Service, OpenShiftCLI).__init__(namespace, kubeconfig) +        super(Service, self).__init__(namespace, kubeconfig)          self.namespace = namespace          self.name = service_name          self.verbose = verbose @@ -200,27 +239,15 @@ class Service(OpenShiftCLI):      def create_service(self, sfile):          ''' create the service ''' -        return self.oc_cmd(['create', '-f', sfile]) +        return self.create(sfile)      def get_services(self):          '''return a secret by name ''' -        cmd = ['get', 'services', '-o', 'json', '-n', self.namespace] -        if self.name: -            cmd.append(self.name) - -        rval = self.oc_cmd(cmd, output=True) - -        # Ensure results are retuned in an array -        if rval.has_key('items'): -            rval['results'] = rval['items'] -        elif not isinstance(rval['results'], list): -            rval['results'] = [rval['results']] - -        return rval +        return self.get('services', self.name)      def delete_service(self):          '''return all pods ''' -        return self.oc_cmd(['delete', 'service', self.name, '-n', self.namespace]) +        return self.delete('service', self.name)      def update_service(self, sfile, force=False):          '''run update service @@ -228,14 +255,7 @@ class Service(OpenShiftCLI):             This receives a list of file names and converts it into a secret.             The secret is then written to disk and passed into the `oc replace` command.          ''' - -        cmd = ['replace', '-f', sfile] -        if force: -            cmd = ['replace', '--force', '-f', sfile] - -        atexit.register(Utils.cleanup, [sfile]) - -        return self.oc_cmd(cmd) +        return self.replace(sfile, force=force)  # pylint: disable=too-many-branches @@ -253,7 +273,9 @@ def main():              namespace=dict(default='default', type='str'),              name=dict(default=None, type='str'),              service_file=dict(default=None, type='str'), -            service_file_type=dict(default=None, type='str'), +            input_type=dict(default='yaml', +                            choices=['json', 'yaml'], +                            type='str'),              delete_after=dict(default=False, type='bool'),              contents=dict(default=None, type='list'),              force=dict(default=False, type='bool'), @@ -320,7 +342,7 @@ def main():          ########          # Update          ######## -        sfile_contents = Utils.get_resource_file(sfile, module.params['service_file_type']) +        sfile_contents = Utils.get_resource_file(sfile, module.params['input_type'])          if Utils.check_def_equal(sfile_contents, api_rval['results'][0]):              # Remove files | 
