diff options
-rw-r--r-- | roles/lib_openshift/src/ansible/oc_process.py | 33 | ||||
-rw-r--r-- | roles/lib_openshift/src/class/oc_process.py | 182 | ||||
-rw-r--r-- | roles/lib_openshift/src/doc/process | 81 | ||||
-rw-r--r-- | roles/lib_openshift/src/sources.yml | 10 |
4 files changed, 306 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..b01c6aa86 --- /dev/null +++ b/roles/lib_openshift/src/ansible/oc_process.py @@ -0,0 +1,33 @@ +# 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 = Process.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..7cc8ff082 --- /dev/null +++ b/roles/lib_openshift/src/class/oc_process.py @@ -0,0 +1,182 @@ +# pylint: skip-file + +# pylint: disable=too-many-instance-attributes +class Process(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(Process, 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 == 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 + + + @staticmethod + def run_ansible(params, check_mode): + '''run the ansible idempotent code''' + + ocprocess = Process(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 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} + + return {"changed": True, "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"} + + return {"failed": True, "changed": False, "results": 'Unknown state passed ({0}). '.format(state), "state": "unknown") diff --git a/roles/lib_openshift/src/doc/process b/roles/lib_openshift/src/doc/process new file mode 100644 index 000000000..46986f8de --- /dev/null +++ b/roles/lib_openshift/src/doc/process @@ -0,0 +1,81 @@ +# flake8: noqa +# pylint: skip-file + +DOCUMENTATION = ''' +--- +module: oc_process +short_description: Module to process openshift templates +description: + - Process openshift templates programmatically. +options: + state: + description: + - Currently present is only supported state. + required: true + 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 template that is being processed. + required: false + default: None + aliases: [] + namespace: + description: + - The namespace where the object lives. + required: false + default: str + aliases: [] + content: + description: + - Template content to 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.q oc process | oc create -f - + required: false + default: None + aliases: [] + reconcile: + description: + - Whether or not to attempt to determine if there are updates or changes in the incoming template. + required: false + 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 |