From 3681ab5fb2a39ccb06024e6ad514ad50df21f9d2 Mon Sep 17 00:00:00 2001 From: Joel Diaz Date: Fri, 8 Apr 2016 13:48:13 -0400 Subject: cleanup roles after roles move to openshift-tools also removing inventory/multi_inventory* things left behind unchanged even though they were copied: playbooks/adhoc/* roles/dns roles/kube_nfs_volumes roles/os_update_latest --- roles/lib_openshift_api/library/oadm_router.py | 807 ------------------------- roles/lib_openshift_api/library/oc_edit.py | 646 -------------------- roles/lib_openshift_api/library/oc_obj.py | 730 ---------------------- roles/lib_openshift_api/library/oc_secret.py | 702 --------------------- 4 files changed, 2885 deletions(-) delete mode 100644 roles/lib_openshift_api/library/oadm_router.py delete mode 100644 roles/lib_openshift_api/library/oc_edit.py delete mode 100644 roles/lib_openshift_api/library/oc_obj.py delete mode 100644 roles/lib_openshift_api/library/oc_secret.py (limited to 'roles/lib_openshift_api/library') diff --git a/roles/lib_openshift_api/library/oadm_router.py b/roles/lib_openshift_api/library/oadm_router.py deleted file mode 100644 index c6b45c14e..000000000 --- a/roles/lib_openshift_api/library/oadm_router.py +++ /dev/null @@ -1,807 +0,0 @@ -#!/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 re - -import yaml -# This is here because of a bug that causes yaml -# to incorrectly handle timezone info on timestamps -def timestamp_constructor(_, node): - '''return timestamps as strings''' - return str(node.value) -yaml.add_constructor(u'tag:yaml.org,2002:timestamp', timestamp_constructor) - -# pylint: disable=too-few-public-methods -class OpenShiftCLI(object): - ''' Class to wrap the command line tools ''' - def __init__(self, - namespace, - kubeconfig='/etc/origin/master/admin.kubeconfig', - verbose=False): - ''' Constructor for OpenshiftCLI ''' - self.namespace = namespace - self.verbose = verbose - self.kubeconfig = kubeconfig - - # Pylint allows only 5 arguments to be passed. - # pylint: disable=too-many-arguments - def _replace_content(self, resource, rname, content, force=False): - ''' replace the current object with the content ''' - res = self._get(resource, rname) - if not res['results']: - return res - - fname = '/tmp/%s' % rname - yed = Yedit(fname, res['results'][0]) - changes = [] - for key, value in content.items(): - changes.append(yed.put(key, value)) - - if any([not change[0] for change in changes]): - return {'returncode': 0, 'updated': False} - - yed.write() - - atexit.register(Utils.cleanup, [fname]) - - return self._replace(fname, force) - - def _replace(self, fname, force=False): - '''return all pods ''' - cmd = ['-n', self.namespace, 'replace', '-f', fname] - if force: - cmd.append('--force') - return self.openshift_cmd(cmd) - - def _create(self, fname): - '''return all pods ''' - return self.openshift_cmd(['create', '-f', fname, '-n', self.namespace]) - - def _delete(self, resource, rname): - '''return all pods ''' - return self.openshift_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.openshift_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 openshift_cmd(self, cmd, oadm=False, output=False, output_type='json'): - '''Base command for oc ''' - #cmds = ['/usr/bin/oc', '--config', self.kubeconfig] - cmds = [] - if oadm: - cmds = ['/usr/bin/oadm'] - else: - cmds = ['/usr/bin/oc'] - - cmds.extend(cmd) - - rval = {} - results = '' - err = None - - if self.verbose: - print ' '.join(cmds) - - proc = subprocess.Popen(cmds, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env={'KUBECONFIG': self.kubeconfig}) - - proc.wait() - stdout = proc.stdout.read() - stderr = proc.stderr.read() - rval = {"returncode": proc.returncode, - "results": results, - "cmd": ' '.join(cmds), - } - - if proc.returncode == 0: - if output: - if output_type == 'json': - try: - rval['results'] = json.loads(stdout) - except ValueError as err: - if "No JSON object could be decoded" in err.message: - err = err.message - elif output_type == 'raw': - rval['results'] = stdout - - if self.verbose: - print stdout - print stderr - print - - if err: - rval.update({"err": err, - "stderr": stderr, - "stdout": stdout, - "cmd": cmds - }) - - else: - rval.update({"stderr": stderr, - "stdout": stdout, - "results": {}, - }) - - return rval - -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.safe_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.safe_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, skip_keys=None, 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 = ['metadata', 'status'] - if skip_keys: - skip.extend(skip_keys) - - 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): - if debug: - print 'user_def[key] is not a list' - return False - - for values in zip(user_def[key], value): - if isinstance(values[0], dict) and isinstance(values[1], dict): - if debug: - print 'sending list - list' - print type(values[0]) - print type(values[1]) - result = Utils.check_def_equal(values[0], values[1], skip_keys=skip_keys, debug=debug) - if not result: - print 'list compare returned false' - return False - - elif value != user_def[key]: - if debug: - print 'value should be identical' - print value - print 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, skip_keys=skip_keys, debug=debug) - if not result: - if debug: - print "dict returned false" - print result - 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 YeditException(Exception): - ''' Exception class for Yedit ''' - pass - -class Yedit(object): - ''' Class to modify yaml files ''' - re_valid_key = r"(((\[-?\d+\])|([a-zA-Z-./]+)).?)+$" - re_key = r"(?:\[(-?\d+)\])|([a-zA-Z-./]+)" - - def __init__(self, filename=None, content=None, content_type='yaml'): - self.content = content - self.filename = filename - self.__yaml_dict = content - self.content_type = content_type - if self.filename and not self.content: - self.load(content_type=self.content_type) - - @property - def yaml_dict(self): - ''' getter method for yaml_dict ''' - return self.__yaml_dict - - @yaml_dict.setter - def yaml_dict(self, value): - ''' setter method for yaml_dict ''' - self.__yaml_dict = value - - @staticmethod - def remove_entry(data, key): - ''' remove data at location key ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for remove - # expected list entry - if key_indexes[-1][0]: - if isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - del data[int(key_indexes[-1][0])] - return True - - # expected dict entry - elif key_indexes[-1][1]: - if isinstance(data, dict): - del data[key_indexes[-1][1]] - return True - - @staticmethod - def add_entry(data, key, item=None): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - curr_data = data - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key: - if isinstance(data, dict) and data.has_key(dict_key): - data = data[dict_key] - continue - - data[dict_key] = {} - data = data[dict_key] - - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for add - # expected list entry - if key_indexes[-1][0] and isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - data[int(key_indexes[-1][0])] = item - - # expected dict entry - elif key_indexes[-1][1] and isinstance(data, dict): - data[key_indexes[-1][1]] = item - - return curr_data - - @staticmethod - def get_entry(data, key): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - return data - - def write(self): - ''' write to file ''' - if not self.filename: - raise YeditException('Please specify a filename.') - - with open(self.filename, 'w') as yfd: - yfd.write(yaml.safe_dump(self.yaml_dict, default_flow_style=False)) - - def read(self): - ''' write to file ''' - # check if it exists - if not self.exists(): - return None - - contents = None - with open(self.filename) as yfd: - contents = yfd.read() - - return contents - - def exists(self): - ''' return whether file exists ''' - if os.path.exists(self.filename): - return True - - return False - - def load(self, content_type='yaml'): - ''' return yaml file ''' - contents = self.read() - - if not contents: - return None - - # check if it is yaml - try: - if content_type == 'yaml': - self.yaml_dict = yaml.load(contents) - elif content_type == 'json': - self.yaml_dict = json.loads(contents) - except yaml.YAMLError as _: - # Error loading yaml or json - return None - - return self.yaml_dict - - def get(self, key): - ''' get a specified key''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - return entry - - def delete(self, key): - ''' remove key from a dict''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - if not entry: - return (False, self.yaml_dict) - - result = Yedit.remove_entry(self.yaml_dict, key) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def put(self, key, value): - ''' put key, value into a dict ''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - if entry == value: - return (False, self.yaml_dict) - - result = Yedit.add_entry(self.yaml_dict, key, value) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def create(self, key, value): - ''' create a yaml file ''' - if not self.exists(): - self.yaml_dict = {key: value} - return (True, self.yaml_dict) - - return (False, self.yaml_dict) - -import time - -class RouterConfig(object): - ''' RouterConfig is a DTO for the router. ''' - def __init__(self, rname, kubeconfig, router_options): - self.name = rname - self.kubeconfig = kubeconfig - self._router_options = router_options - - @property - def router_options(self): - ''' return router options ''' - return self._router_options - - def to_option_list(self): - ''' return all options as a string''' - return RouterConfig.stringify(self.router_options) - - @staticmethod - def stringify(options): - ''' return hash as list of key value pairs ''' - rval = [] - for key, data in options.items(): - if data['include'] and data['value']: - rval.append('--%s=%s' % (key.replace('_', '-'), data['value'])) - - return rval - -class Router(OpenShiftCLI): - ''' Class to wrap the oc command line tools ''' - def __init__(self, - router_config, - verbose=False): - ''' Constructor for OpenshiftOC - - a router consists of 3 or more parts - - dc/router - - svc/router - - endpoint/router - ''' - super(Router, self).__init__('default', router_config.kubeconfig, verbose) - self.rconfig = router_config - self.verbose = verbose - self.router_parts = [{'kind': 'dc', 'name': self.rconfig.name}, - {'kind': 'svc', 'name': self.rconfig.name}, - #{'kind': 'endpoints', 'name': self.rconfig.name}, - ] - def get(self, filter_kind=None): - ''' return the self.router_parts ''' - rparts = self.router_parts - parts = [] - if filter_kind: - rparts = [part for part in self.router_parts if filter_kind == part['kind']] - - for part in rparts: - parts.append(self._get(part['kind'], rname=part['name'])) - - return parts - - def exists(self): - '''return a deploymentconfig by name ''' - parts = self.get() - for part in parts: - if part['returncode'] != 0: - return False - - return True - - def delete(self): - '''return all pods ''' - parts = [] - for part in self.router_parts: - parts.append(self._delete(part['kind'], part['name'])) - - return parts - - def create(self, dryrun=False, output=False, output_type='json'): - '''Create a deploymentconfig ''' - # We need to create the pem file - router_pem = '/tmp/router.pem' - with open(router_pem, 'w') as rfd: - rfd.write(open(self.rconfig.router_options['cert_file']['value']).read()) - rfd.write(open(self.rconfig.router_options['key_file']['value']).read()) - - atexit.register(Utils.cleanup, [router_pem]) - self.rconfig.router_options['default_cert']['value'] = router_pem - - options = self.rconfig.to_option_list() - - cmd = ['router'] - cmd.extend(options) - if dryrun: - cmd.extend(['--dry-run=True', '-o', 'json']) - - results = self.openshift_cmd(cmd, oadm=True, output=output, output_type=output_type) - - return results - - def update(self): - '''run update for the router. This performs a delete and then create ''' - parts = self.delete() - if any([part['returncode'] != 0 for part in parts]): - return parts - - # Ugly built in sleep here. - time.sleep(15) - - return self.create() - - def needs_update(self, verbose=False): - ''' check to see if we need to update ''' - dc_inmem = self.get(filter_kind='dc')[0] - if dc_inmem['returncode'] != 0: - return dc_inmem - - user_dc = self.create(dryrun=True, output=True, output_type='raw') - if user_dc['returncode'] != 0: - return user_dc - - # Since the output from oadm_router is returned as raw - # we need to parse it. The first line is the stats_password - user_dc_results = user_dc['results'].split('\n') - # stats_password = user_dc_results[0] - - # Load the string back into json and get the newly created dc - user_dc = json.loads('\n'.join(user_dc_results[1:]))['items'][0] - - # Router needs some exceptions. - # We do not want to check the autogenerated password for stats admin - if not self.rconfig.router_options['stats_password']['value']: - for idx, env_var in enumerate(user_dc['spec']['template']['spec']['containers'][0]['env']): - if env_var['name'] == 'STATS_PASSWORD': - env_var['value'] = \ - dc_inmem['results'][0]['spec']['template']['spec']['containers'][0]['env'][idx]['value'] - - # dry-run doesn't add the protocol to the ports section. We will manually do that. - for idx, port in enumerate(user_dc['spec']['template']['spec']['containers'][0]['ports']): - if not port.has_key('protocol'): - port['protocol'] = 'TCP' - - # These are different when generating - skip = ['dnsPolicy', - 'terminationGracePeriodSeconds', - 'restartPolicy', 'timeoutSeconds', - 'livenessProbe', 'readinessProbe', - 'terminationMessagePath', - 'rollingParams', - ] - - return not Utils.check_def_equal(user_dc, dc_inmem['results'][0], skip_keys=skip, debug=verbose) - -def main(): - ''' - ansible oc module for secrets - ''' - - module = AnsibleModule( - argument_spec=dict( - state=dict(default='present', type='str', - choices=['present', 'absent']), - debug=dict(default=False, type='bool'), - namespace=dict(default='default', type='str'), - name=dict(default='router', type='str'), - - kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'), - credentials=dict(default='/etc/origin/master/openshift-router.kubeconfig', type='str'), - cert_file=dict(default=None, type='str'), - key_file=dict(default=None, type='str'), - image=dict(default=None, type='str'), #'openshift3/ose-${component}:${version}' - latest_image=dict(default=False, type='bool'), - labels=dict(default=None, type='list'), - ports=dict(default=['80:80', '443:443'], type='list'), - replicas=dict(default=1, type='int'), - selector=dict(default=None, type='str'), - service_account=dict(default='router', type='str'), - router_type=dict(default='haproxy-router', type='str'), - host_network=dict(default=True, type='bool'), - # external host options - external_host=dict(default=None, type='str'), - external_host_vserver=dict(default=None, type='str'), - external_host_insecure=dict(default=False, type='bool'), - external_host_partition_path=dict(default=None, type='str'), - external_host_username=dict(default=None, type='str'), - external_host_password=dict(default=None, type='str'), - external_host_private_key=dict(default=None, type='str'), - # Metrics - expose_metrics=dict(default=False, type='bool'), - metrics_image=dict(default=None, type='str'), - # Stats - stats_user=dict(default=None, type='str'), - stats_password=dict(default=None, type='str'), - stats_port=dict(default=1936, type='int'), - - ), - mutually_exclusive=[["router_type", "images"]], - - supports_check_mode=True, - ) - - rconfig = RouterConfig(module.params['name'], - module.params['kubeconfig'], - {'credentials': {'value': module.params['credentials'], 'include': True}, - 'default_cert': {'value': None, 'include': True}, - 'cert_file': {'value': module.params['cert_file'], 'include': False}, - 'key_file': {'value': module.params['key_file'], 'include': False}, - 'image': {'value': module.params['image'], 'include': True}, - 'latest_image': {'value': module.params['latest_image'], 'include': True}, - 'labels': {'value': module.params['labels'], 'include': True}, - 'ports': {'value': ','.join(module.params['ports']), 'include': True}, - 'replicas': {'value': module.params['replicas'], 'include': True}, - 'selector': {'value': module.params['selector'], 'include': True}, - 'service_account': {'value': module.params['service_account'], 'include': True}, - 'router_type': {'value': module.params['router_type'], 'include': False}, - 'host_network': {'value': module.params['host_network'], 'include': True}, - 'external_host': {'value': module.params['external_host'], 'include': True}, - 'external_host_vserver': {'value': module.params['external_host_vserver'], - 'include': True}, - 'external_host_insecure': {'value': module.params['external_host_insecure'], - 'include': True}, - 'external_host_partition_path': {'value': module.params['external_host_partition_path'], - 'include': True}, - 'external_host_username': {'value': module.params['external_host_username'], - 'include': True}, - 'external_host_password': {'value': module.params['external_host_password'], - 'include': True}, - 'external_host_private_key': {'value': module.params['external_host_private_key'], - 'include': True}, - 'expose_metrics': {'value': module.params['expose_metrics'], 'include': True}, - 'metrics_image': {'value': module.params['metrics_image'], 'include': True}, - 'stats_user': {'value': module.params['stats_user'], 'include': True}, - 'stats_password': {'value': module.params['stats_password'], 'include': True}, - 'stats_port': {'value': module.params['stats_port'], 'include': True}, - }) - - - ocrouter = Router(rconfig) - - state = module.params['state'] - - ######## - # Delete - ######## - if state == 'absent': - if not ocrouter.exists(): - module.exit_json(changed=False, state="absent") - - if module.check_mode: - module.exit_json(change=False, msg='Would have performed a delete.') - - api_rval = ocrouter.delete() - module.exit_json(changed=True, results=api_rval, state="absent") - - - if state == 'present': - ######## - # Create - ######## - if not ocrouter.exists(): - - if module.check_mode: - module.exit_json(change=False, msg='Would have performed a create.') - - api_rval = ocrouter.create() - - module.exit_json(changed=True, results=api_rval, state="present") - - ######## - # Update - ######## - if not ocrouter.needs_update(): - module.exit_json(changed=False, state="present") - - if module.check_mode: - module.exit_json(change=False, msg='Would have performed an update.') - - api_rval = ocrouter.update() - - 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_edit.py b/roles/lib_openshift_api/library/oc_edit.py deleted file mode 100644 index e43b6175a..000000000 --- a/roles/lib_openshift_api/library/oc_edit.py +++ /dev/null @@ -1,646 +0,0 @@ -#!/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 re - -import yaml -# This is here because of a bug that causes yaml -# to incorrectly handle timezone info on timestamps -def timestamp_constructor(_, node): - '''return timestamps as strings''' - return str(node.value) -yaml.add_constructor(u'tag:yaml.org,2002:timestamp', timestamp_constructor) - -# pylint: disable=too-few-public-methods -class OpenShiftCLI(object): - ''' Class to wrap the command line tools ''' - def __init__(self, - namespace, - kubeconfig='/etc/origin/master/admin.kubeconfig', - verbose=False): - ''' Constructor for OpenshiftCLI ''' - self.namespace = namespace - self.verbose = verbose - self.kubeconfig = kubeconfig - - # Pylint allows only 5 arguments to be passed. - # pylint: disable=too-many-arguments - def _replace_content(self, resource, rname, content, force=False): - ''' replace the current object with the content ''' - res = self._get(resource, rname) - if not res['results']: - return res - - fname = '/tmp/%s' % rname - yed = Yedit(fname, res['results'][0]) - changes = [] - for key, value in content.items(): - changes.append(yed.put(key, value)) - - if any([not change[0] for change in changes]): - return {'returncode': 0, 'updated': False} - - yed.write() - - atexit.register(Utils.cleanup, [fname]) - - return self._replace(fname, force) - - def _replace(self, fname, force=False): - '''return all pods ''' - cmd = ['-n', self.namespace, 'replace', '-f', fname] - if force: - cmd.append('--force') - return self.openshift_cmd(cmd) - - def _create(self, fname): - '''return all pods ''' - return self.openshift_cmd(['create', '-f', fname, '-n', self.namespace]) - - def _delete(self, resource, rname): - '''return all pods ''' - return self.openshift_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.openshift_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 openshift_cmd(self, cmd, oadm=False, output=False, output_type='json'): - '''Base command for oc ''' - #cmds = ['/usr/bin/oc', '--config', self.kubeconfig] - cmds = [] - if oadm: - cmds = ['/usr/bin/oadm'] - else: - cmds = ['/usr/bin/oc'] - - cmds.extend(cmd) - - rval = {} - results = '' - err = None - - if self.verbose: - print ' '.join(cmds) - - proc = subprocess.Popen(cmds, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env={'KUBECONFIG': self.kubeconfig}) - - proc.wait() - stdout = proc.stdout.read() - stderr = proc.stderr.read() - rval = {"returncode": proc.returncode, - "results": results, - "cmd": ' '.join(cmds), - } - - if proc.returncode == 0: - if output: - if output_type == 'json': - try: - rval['results'] = json.loads(stdout) - except ValueError as err: - if "No JSON object could be decoded" in err.message: - err = err.message - elif output_type == 'raw': - rval['results'] = stdout - - if self.verbose: - print stdout - print stderr - print - - if err: - rval.update({"err": err, - "stderr": stderr, - "stdout": stdout, - "cmd": cmds - }) - - else: - rval.update({"stderr": stderr, - "stdout": stdout, - "results": {}, - }) - - return rval - -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.safe_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.safe_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, skip_keys=None, 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 = ['metadata', 'status'] - if skip_keys: - skip.extend(skip_keys) - - 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): - if debug: - print 'user_def[key] is not a list' - return False - - for values in zip(user_def[key], value): - if isinstance(values[0], dict) and isinstance(values[1], dict): - if debug: - print 'sending list - list' - print type(values[0]) - print type(values[1]) - result = Utils.check_def_equal(values[0], values[1], skip_keys=skip_keys, debug=debug) - if not result: - print 'list compare returned false' - return False - - elif value != user_def[key]: - if debug: - print 'value should be identical' - print value - print 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, skip_keys=skip_keys, debug=debug) - if not result: - if debug: - print "dict returned false" - print result - 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 YeditException(Exception): - ''' Exception class for Yedit ''' - pass - -class Yedit(object): - ''' Class to modify yaml files ''' - re_valid_key = r"(((\[-?\d+\])|([a-zA-Z-./]+)).?)+$" - re_key = r"(?:\[(-?\d+)\])|([a-zA-Z-./]+)" - - def __init__(self, filename=None, content=None, content_type='yaml'): - self.content = content - self.filename = filename - self.__yaml_dict = content - self.content_type = content_type - if self.filename and not self.content: - self.load(content_type=self.content_type) - - @property - def yaml_dict(self): - ''' getter method for yaml_dict ''' - return self.__yaml_dict - - @yaml_dict.setter - def yaml_dict(self, value): - ''' setter method for yaml_dict ''' - self.__yaml_dict = value - - @staticmethod - def remove_entry(data, key): - ''' remove data at location key ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for remove - # expected list entry - if key_indexes[-1][0]: - if isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - del data[int(key_indexes[-1][0])] - return True - - # expected dict entry - elif key_indexes[-1][1]: - if isinstance(data, dict): - del data[key_indexes[-1][1]] - return True - - @staticmethod - def add_entry(data, key, item=None): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - curr_data = data - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key: - if isinstance(data, dict) and data.has_key(dict_key): - data = data[dict_key] - continue - - data[dict_key] = {} - data = data[dict_key] - - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for add - # expected list entry - if key_indexes[-1][0] and isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - data[int(key_indexes[-1][0])] = item - - # expected dict entry - elif key_indexes[-1][1] and isinstance(data, dict): - data[key_indexes[-1][1]] = item - - return curr_data - - @staticmethod - def get_entry(data, key): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - return data - - def write(self): - ''' write to file ''' - if not self.filename: - raise YeditException('Please specify a filename.') - - with open(self.filename, 'w') as yfd: - yfd.write(yaml.safe_dump(self.yaml_dict, default_flow_style=False)) - - def read(self): - ''' write to file ''' - # check if it exists - if not self.exists(): - return None - - contents = None - with open(self.filename) as yfd: - contents = yfd.read() - - return contents - - def exists(self): - ''' return whether file exists ''' - if os.path.exists(self.filename): - return True - - return False - - def load(self, content_type='yaml'): - ''' return yaml file ''' - contents = self.read() - - if not contents: - return None - - # check if it is yaml - try: - if content_type == 'yaml': - self.yaml_dict = yaml.load(contents) - elif content_type == 'json': - self.yaml_dict = json.loads(contents) - except yaml.YAMLError as _: - # Error loading yaml or json - return None - - return self.yaml_dict - - def get(self, key): - ''' get a specified key''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - return entry - - def delete(self, key): - ''' remove key from a dict''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - if not entry: - return (False, self.yaml_dict) - - result = Yedit.remove_entry(self.yaml_dict, key) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def put(self, key, value): - ''' put key, value into a dict ''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - if entry == value: - return (False, self.yaml_dict) - - result = Yedit.add_entry(self.yaml_dict, key, value) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def create(self, key, value): - ''' create a yaml file ''' - if not self.exists(): - self.yaml_dict = {key: value} - return (True, self.yaml_dict) - - return (False, self.yaml_dict) - -class Edit(OpenShiftCLI): - ''' Class to wrap the oc command line tools - ''' - # pylint: disable=too-many-arguments - def __init__(self, - kind, - namespace, - resource_name=None, - kubeconfig='/etc/origin/master/admin.kubeconfig', - verbose=False): - ''' Constructor for OpenshiftOC ''' - super(Edit, self).__init__(namespace, kubeconfig) - self.namespace = namespace - self.kind = kind - self.name = resource_name - self.kubeconfig = kubeconfig - self.verbose = verbose - - def get(self): - '''return a secret by name ''' - return self._get(self.kind, self.name) - - def update(self, file_name, content, force=False, content_type='yaml'): - '''run update ''' - if file_name: - if content_type == 'yaml': - data = yaml.load(open(file_name)) - elif content_type == 'json': - data = json.loads(open(file_name).read()) - - changes = [] - yed = Yedit(file_name, data) - for key, value in content.items(): - changes.append(yed.put(key, value)) - - if any([not change[0] for change in changes]): - return {'returncode': 0, 'updated': False} - - yed.write() - - atexit.register(Utils.cleanup, [file_name]) - - return self._replace(file_name, force=force) - - return self._replace_content(self.kind, self.name, content, force=force) - - - -def main(): - ''' - ansible oc module for services - ''' - - module = AnsibleModule( - argument_spec=dict( - kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'), - state=dict(default='present', type='str', - choices=['present']), - debug=dict(default=False, type='bool'), - namespace=dict(default='default', type='str'), - name=dict(default=None, required=True, type='str'), - kind=dict(required=True, - type='str', - choices=['dc', 'deploymentconfig', - 'svc', 'service', - 'scc', 'securitycontextconstraints', - 'ns', 'namespace', 'project', 'projects', - 'is', 'imagestream', - 'istag', 'imagestreamtag', - 'bc', 'buildconfig', - 'routes', - 'node', - 'secret', - ]), - file_name=dict(default=None, type='str'), - file_format=dict(default='yaml', type='str'), - content=dict(default=None, required=True, type='dict'), - force=dict(default=False, type='bool'), - ), - supports_check_mode=True, - ) - ocedit = Edit(module.params['kind'], - module.params['namespace'], - module.params['name'], - kubeconfig=module.params['kubeconfig'], - verbose=module.params['debug']) - - state = module.params['state'] - - api_rval = ocedit.get() - - ######## - # Create - ######## - if not Utils.exists(api_rval['results'], module.params['name']): - module.fail_json(msg=api_rval) - - ######## - # Update - ######## - api_rval = ocedit.update(module.params['file_name'], - module.params['content'], - module.params['force'], - module.params['file_format']) - - - if api_rval['returncode'] != 0: - module.fail_json(msg=api_rval) - - if api_rval.has_key('updated') and not api_rval['updated']: - module.exit_json(changed=False, results=api_rval, state="present") - - # return the created object - api_rval = ocedit.get() - - 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_obj.py b/roles/lib_openshift_api/library/oc_obj.py deleted file mode 100644 index f0ea66aee..000000000 --- a/roles/lib_openshift_api/library/oc_obj.py +++ /dev/null @@ -1,730 +0,0 @@ -#!/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 re - -import yaml -# This is here because of a bug that causes yaml -# to incorrectly handle timezone info on timestamps -def timestamp_constructor(_, node): - '''return timestamps as strings''' - return str(node.value) -yaml.add_constructor(u'tag:yaml.org,2002:timestamp', timestamp_constructor) - -# pylint: disable=too-few-public-methods -class OpenShiftCLI(object): - ''' Class to wrap the command line tools ''' - def __init__(self, - namespace, - kubeconfig='/etc/origin/master/admin.kubeconfig', - verbose=False): - ''' Constructor for OpenshiftCLI ''' - self.namespace = namespace - self.verbose = verbose - self.kubeconfig = kubeconfig - - # Pylint allows only 5 arguments to be passed. - # pylint: disable=too-many-arguments - def _replace_content(self, resource, rname, content, force=False): - ''' replace the current object with the content ''' - res = self._get(resource, rname) - if not res['results']: - return res - - fname = '/tmp/%s' % rname - yed = Yedit(fname, res['results'][0]) - changes = [] - for key, value in content.items(): - changes.append(yed.put(key, value)) - - if any([not change[0] for change in changes]): - return {'returncode': 0, 'updated': False} - - yed.write() - - atexit.register(Utils.cleanup, [fname]) - - return self._replace(fname, force) - - def _replace(self, fname, force=False): - '''return all pods ''' - cmd = ['-n', self.namespace, 'replace', '-f', fname] - if force: - cmd.append('--force') - return self.openshift_cmd(cmd) - - def _create(self, fname): - '''return all pods ''' - return self.openshift_cmd(['create', '-f', fname, '-n', self.namespace]) - - def _delete(self, resource, rname): - '''return all pods ''' - return self.openshift_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.openshift_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 openshift_cmd(self, cmd, oadm=False, output=False, output_type='json'): - '''Base command for oc ''' - #cmds = ['/usr/bin/oc', '--config', self.kubeconfig] - cmds = [] - if oadm: - cmds = ['/usr/bin/oadm'] - else: - cmds = ['/usr/bin/oc'] - - cmds.extend(cmd) - - rval = {} - results = '' - err = None - - if self.verbose: - print ' '.join(cmds) - - proc = subprocess.Popen(cmds, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env={'KUBECONFIG': self.kubeconfig}) - - proc.wait() - stdout = proc.stdout.read() - stderr = proc.stderr.read() - rval = {"returncode": proc.returncode, - "results": results, - "cmd": ' '.join(cmds), - } - - if proc.returncode == 0: - if output: - if output_type == 'json': - try: - rval['results'] = json.loads(stdout) - except ValueError as err: - if "No JSON object could be decoded" in err.message: - err = err.message - elif output_type == 'raw': - rval['results'] = stdout - - if self.verbose: - print stdout - print stderr - print - - if err: - rval.update({"err": err, - "stderr": stderr, - "stdout": stdout, - "cmd": cmds - }) - - else: - rval.update({"stderr": stderr, - "stdout": stdout, - "results": {}, - }) - - return rval - -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.safe_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.safe_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, skip_keys=None, 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 = ['metadata', 'status'] - if skip_keys: - skip.extend(skip_keys) - - 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): - if debug: - print 'user_def[key] is not a list' - return False - - for values in zip(user_def[key], value): - if isinstance(values[0], dict) and isinstance(values[1], dict): - if debug: - print 'sending list - list' - print type(values[0]) - print type(values[1]) - result = Utils.check_def_equal(values[0], values[1], skip_keys=skip_keys, debug=debug) - if not result: - print 'list compare returned false' - return False - - elif value != user_def[key]: - if debug: - print 'value should be identical' - print value - print 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, skip_keys=skip_keys, debug=debug) - if not result: - if debug: - print "dict returned false" - print result - 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 YeditException(Exception): - ''' Exception class for Yedit ''' - pass - -class Yedit(object): - ''' Class to modify yaml files ''' - re_valid_key = r"(((\[-?\d+\])|([a-zA-Z-./]+)).?)+$" - re_key = r"(?:\[(-?\d+)\])|([a-zA-Z-./]+)" - - def __init__(self, filename=None, content=None, content_type='yaml'): - self.content = content - self.filename = filename - self.__yaml_dict = content - self.content_type = content_type - if self.filename and not self.content: - self.load(content_type=self.content_type) - - @property - def yaml_dict(self): - ''' getter method for yaml_dict ''' - return self.__yaml_dict - - @yaml_dict.setter - def yaml_dict(self, value): - ''' setter method for yaml_dict ''' - self.__yaml_dict = value - - @staticmethod - def remove_entry(data, key): - ''' remove data at location key ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for remove - # expected list entry - if key_indexes[-1][0]: - if isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - del data[int(key_indexes[-1][0])] - return True - - # expected dict entry - elif key_indexes[-1][1]: - if isinstance(data, dict): - del data[key_indexes[-1][1]] - return True - - @staticmethod - def add_entry(data, key, item=None): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - curr_data = data - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key: - if isinstance(data, dict) and data.has_key(dict_key): - data = data[dict_key] - continue - - data[dict_key] = {} - data = data[dict_key] - - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for add - # expected list entry - if key_indexes[-1][0] and isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - data[int(key_indexes[-1][0])] = item - - # expected dict entry - elif key_indexes[-1][1] and isinstance(data, dict): - data[key_indexes[-1][1]] = item - - return curr_data - - @staticmethod - def get_entry(data, key): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - return data - - def write(self): - ''' write to file ''' - if not self.filename: - raise YeditException('Please specify a filename.') - - with open(self.filename, 'w') as yfd: - yfd.write(yaml.safe_dump(self.yaml_dict, default_flow_style=False)) - - def read(self): - ''' write to file ''' - # check if it exists - if not self.exists(): - return None - - contents = None - with open(self.filename) as yfd: - contents = yfd.read() - - return contents - - def exists(self): - ''' return whether file exists ''' - if os.path.exists(self.filename): - return True - - return False - - def load(self, content_type='yaml'): - ''' return yaml file ''' - contents = self.read() - - if not contents: - return None - - # check if it is yaml - try: - if content_type == 'yaml': - self.yaml_dict = yaml.load(contents) - elif content_type == 'json': - self.yaml_dict = json.loads(contents) - except yaml.YAMLError as _: - # Error loading yaml or json - return None - - return self.yaml_dict - - def get(self, key): - ''' get a specified key''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - return entry - - def delete(self, key): - ''' remove key from a dict''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - if not entry: - return (False, self.yaml_dict) - - result = Yedit.remove_entry(self.yaml_dict, key) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def put(self, key, value): - ''' put key, value into a dict ''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - if entry == value: - return (False, self.yaml_dict) - - result = Yedit.add_entry(self.yaml_dict, key, value) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def create(self, key, value): - ''' create a yaml file ''' - if not self.exists(): - self.yaml_dict = {key: value} - return (True, self.yaml_dict) - - return (False, self.yaml_dict) - -class OCObject(OpenShiftCLI): - ''' Class to wrap the oc command line tools ''' - - # pylint allows 5. we need 6 - # pylint: disable=too-many-arguments - def __init__(self, - kind, - namespace, - rname=None, - kubeconfig='/etc/origin/master/admin.kubeconfig', - verbose=False): - ''' Constructor for OpenshiftOC ''' - super(OCObject, self).__init__(namespace, kubeconfig) - self.kind = kind - self.namespace = namespace - self.name = rname - self.kubeconfig = kubeconfig - self.verbose = verbose - - def get(self): - '''return a deploymentconfig by name ''' - return self._get(self.kind, rname=self.name) - - def delete(self): - '''return all pods ''' - return self._delete(self.kind, self.name) - - def create(self, files=None, content=None): - '''Create a deploymentconfig ''' - if files: - return self._create(files[0]) - - return self._create(Utils.create_files_from_contents(content)) - - - # pylint: disable=too-many-function-args - def update(self, files=None, content=None, force=False): - '''run update dc - - This receives a list of file names and takes the first filename and calls replace. - ''' - if files: - return self._replace(files[0], force) - - return self.update_content(content, force) - - def update_content(self, content, force=False): - '''update the dc with the content''' - return self._replace_content(self.kind, self.name, content, force=force) - - def needs_update(self, files=None, content=None, content_type='yaml'): - ''' check to see if we need to update ''' - objects = self.get() - if objects['returncode'] != 0: - return objects - - # pylint: disable=no-member - data = None - if files: - data = Utils.get_resource_file(files[0], content_type) - - # if equal then no need. So not equal is True - return not Utils.check_def_equal(data, objects['results'][0], skip_keys=None, debug=False) - else: - data = content - - for key, value in data.items(): - if key == 'metadata': - continue - if not objects['results'][0].has_key(key): - return True - if value != objects['results'][0][key]: - return True - - return False - - -# pylint: disable=too-many-branches -def main(): - ''' - ansible oc module for services - ''' - - 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'), - files=dict(default=None, type='list'), - kind=dict(required=True, - type='str', - choices=['dc', 'deploymentconfig', - 'svc', 'service', - 'scc', 'securitycontextconstraints', - 'ns', 'namespace', 'project', 'projects', - 'is', 'imagestream', - 'istag', 'imagestreamtag', - 'bc', 'buildconfig', - 'routes', - 'node', - 'secret', - ]), - delete_after=dict(default=False, type='bool'), - content=dict(default=None, type='dict'), - force=dict(default=False, type='bool'), - ), - mutually_exclusive=[["content", "files"]], - - supports_check_mode=True, - ) - ocobj = OCObject(module.params['kind'], - module.params['namespace'], - module.params['name'], - kubeconfig=module.params['kubeconfig'], - verbose=module.params['debug']) - - state = module.params['state'] - - api_rval = ocobj.get() - - ##### - # 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 = ocobj.delete() - module.exit_json(changed=True, results=api_rval, state="absent") - - if state == 'present': - ######## - # 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.') - - # Create it here - api_rval = ocobj.create(module.params['files'], module.params['content']) - if api_rval['returncode'] != 0: - module.fail_json(msg=api_rval) - - # return the created object - api_rval = ocobj.get() - - if api_rval['returncode'] != 0: - module.fail_json(msg=api_rval) - - # Remove files - if module.params['files'] and module.params['delete_after']: - Utils.cleanup(module.params['files']) - - module.exit_json(changed=True, results=api_rval, state="present") - - ######## - # Update - ######## - # if a file path is passed, use it. - update = ocobj.needs_update(module.params['files'], module.params['content']) - if not isinstance(update, bool): - module.fail_json(msg=update) - - # No changes - if not update: - if module.params['files'] and module.params['delete_after']: - Utils.cleanup(module.params['files']) - - module.exit_json(changed=False, results=api_rval['results'][0], state="present") - - if module.check_mode: - module.exit_json(change=False, msg='Would have performed an update.') - - api_rval = ocobj.update(module.params['files'], - module.params['content'], - module.params['force']) - - - if api_rval['returncode'] != 0: - module.fail_json(msg=api_rval) - - # return the created object - api_rval = ocobj.get() - - 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 deleted file mode 100644 index ca58d7139..000000000 --- a/roles/lib_openshift_api/library/oc_secret.py +++ /dev/null @@ -1,702 +0,0 @@ -#!/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 re - -import yaml -# This is here because of a bug that causes yaml -# to incorrectly handle timezone info on timestamps -def timestamp_constructor(_, node): - '''return timestamps as strings''' - return str(node.value) -yaml.add_constructor(u'tag:yaml.org,2002:timestamp', timestamp_constructor) - -# pylint: disable=too-few-public-methods -class OpenShiftCLI(object): - ''' Class to wrap the command line tools ''' - def __init__(self, - namespace, - kubeconfig='/etc/origin/master/admin.kubeconfig', - verbose=False): - ''' Constructor for OpenshiftCLI ''' - self.namespace = namespace - self.verbose = verbose - self.kubeconfig = kubeconfig - - # Pylint allows only 5 arguments to be passed. - # pylint: disable=too-many-arguments - def _replace_content(self, resource, rname, content, force=False): - ''' replace the current object with the content ''' - res = self._get(resource, rname) - if not res['results']: - return res - - fname = '/tmp/%s' % rname - yed = Yedit(fname, res['results'][0]) - changes = [] - for key, value in content.items(): - changes.append(yed.put(key, value)) - - if any([not change[0] for change in changes]): - return {'returncode': 0, 'updated': False} - - yed.write() - - atexit.register(Utils.cleanup, [fname]) - - return self._replace(fname, force) - - def _replace(self, fname, force=False): - '''return all pods ''' - cmd = ['-n', self.namespace, 'replace', '-f', fname] - if force: - cmd.append('--force') - return self.openshift_cmd(cmd) - - def _create(self, fname): - '''return all pods ''' - return self.openshift_cmd(['create', '-f', fname, '-n', self.namespace]) - - def _delete(self, resource, rname): - '''return all pods ''' - return self.openshift_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.openshift_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 openshift_cmd(self, cmd, oadm=False, output=False, output_type='json'): - '''Base command for oc ''' - #cmds = ['/usr/bin/oc', '--config', self.kubeconfig] - cmds = [] - if oadm: - cmds = ['/usr/bin/oadm'] - else: - cmds = ['/usr/bin/oc'] - - cmds.extend(cmd) - - rval = {} - results = '' - err = None - - if self.verbose: - print ' '.join(cmds) - - proc = subprocess.Popen(cmds, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env={'KUBECONFIG': self.kubeconfig}) - - proc.wait() - stdout = proc.stdout.read() - stderr = proc.stderr.read() - rval = {"returncode": proc.returncode, - "results": results, - "cmd": ' '.join(cmds), - } - - if proc.returncode == 0: - if output: - if output_type == 'json': - try: - rval['results'] = json.loads(stdout) - except ValueError as err: - if "No JSON object could be decoded" in err.message: - err = err.message - elif output_type == 'raw': - rval['results'] = stdout - - if self.verbose: - print stdout - print stderr - print - - if err: - rval.update({"err": err, - "stderr": stderr, - "stdout": stdout, - "cmd": cmds - }) - - else: - rval.update({"stderr": stderr, - "stdout": stdout, - "results": {}, - }) - - return rval - -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.safe_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.safe_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, skip_keys=None, 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 = ['metadata', 'status'] - if skip_keys: - skip.extend(skip_keys) - - 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): - if debug: - print 'user_def[key] is not a list' - return False - - for values in zip(user_def[key], value): - if isinstance(values[0], dict) and isinstance(values[1], dict): - if debug: - print 'sending list - list' - print type(values[0]) - print type(values[1]) - result = Utils.check_def_equal(values[0], values[1], skip_keys=skip_keys, debug=debug) - if not result: - print 'list compare returned false' - return False - - elif value != user_def[key]: - if debug: - print 'value should be identical' - print value - print 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, skip_keys=skip_keys, debug=debug) - if not result: - if debug: - print "dict returned false" - print result - 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 YeditException(Exception): - ''' Exception class for Yedit ''' - pass - -class Yedit(object): - ''' Class to modify yaml files ''' - re_valid_key = r"(((\[-?\d+\])|([a-zA-Z-./]+)).?)+$" - re_key = r"(?:\[(-?\d+)\])|([a-zA-Z-./]+)" - - def __init__(self, filename=None, content=None, content_type='yaml'): - self.content = content - self.filename = filename - self.__yaml_dict = content - self.content_type = content_type - if self.filename and not self.content: - self.load(content_type=self.content_type) - - @property - def yaml_dict(self): - ''' getter method for yaml_dict ''' - return self.__yaml_dict - - @yaml_dict.setter - def yaml_dict(self, value): - ''' setter method for yaml_dict ''' - self.__yaml_dict = value - - @staticmethod - def remove_entry(data, key): - ''' remove data at location key ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for remove - # expected list entry - if key_indexes[-1][0]: - if isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - del data[int(key_indexes[-1][0])] - return True - - # expected dict entry - elif key_indexes[-1][1]: - if isinstance(data, dict): - del data[key_indexes[-1][1]] - return True - - @staticmethod - def add_entry(data, key, item=None): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - curr_data = data - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes[:-1]: - if dict_key: - if isinstance(data, dict) and data.has_key(dict_key): - data = data[dict_key] - continue - - data[dict_key] = {} - data = data[dict_key] - - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - # process last index for add - # expected list entry - if key_indexes[-1][0] and isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: - data[int(key_indexes[-1][0])] = item - - # expected dict entry - elif key_indexes[-1][1] and isinstance(data, dict): - data[key_indexes[-1][1]] = item - - return curr_data - - @staticmethod - def get_entry(data, key): - ''' Get an item from a dictionary with key notation a.b.c - d = {'a': {'b': 'c'}}} - key = a.b - return c - ''' - if not (key and re.match(Yedit.re_valid_key, key) and isinstance(data, (list, dict))): - return None - - key_indexes = re.findall(Yedit.re_key, key) - for arr_ind, dict_key in key_indexes: - if dict_key and isinstance(data, dict): - data = data.get(dict_key, None) - elif arr_ind and isinstance(data, list) and int(arr_ind) <= len(data) - 1: - data = data[int(arr_ind)] - else: - return None - - return data - - def write(self): - ''' write to file ''' - if not self.filename: - raise YeditException('Please specify a filename.') - - with open(self.filename, 'w') as yfd: - yfd.write(yaml.safe_dump(self.yaml_dict, default_flow_style=False)) - - def read(self): - ''' write to file ''' - # check if it exists - if not self.exists(): - return None - - contents = None - with open(self.filename) as yfd: - contents = yfd.read() - - return contents - - def exists(self): - ''' return whether file exists ''' - if os.path.exists(self.filename): - return True - - return False - - def load(self, content_type='yaml'): - ''' return yaml file ''' - contents = self.read() - - if not contents: - return None - - # check if it is yaml - try: - if content_type == 'yaml': - self.yaml_dict = yaml.load(contents) - elif content_type == 'json': - self.yaml_dict = json.loads(contents) - except yaml.YAMLError as _: - # Error loading yaml or json - return None - - return self.yaml_dict - - def get(self, key): - ''' get a specified key''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - return entry - - def delete(self, key): - ''' remove key from a dict''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - if not entry: - return (False, self.yaml_dict) - - result = Yedit.remove_entry(self.yaml_dict, key) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def put(self, key, value): - ''' put key, value into a dict ''' - try: - entry = Yedit.get_entry(self.yaml_dict, key) - except KeyError as _: - entry = None - - if entry == value: - return (False, self.yaml_dict) - - result = Yedit.add_entry(self.yaml_dict, key, value) - if not result: - return (False, self.yaml_dict) - - return (True, self.yaml_dict) - - def create(self, key, value): - ''' create a yaml file ''' - if not self.exists(): - self.yaml_dict = {key: value} - return (True, self.yaml_dict) - - return (False, self.yaml_dict) - -class Secret(OpenShiftCLI): - ''' Class to wrap the oc command line tools - ''' - def __init__(self, - namespace, - secret_name=None, - kubeconfig='/etc/origin/master/admin.kubeconfig', - verbose=False): - ''' Constructor for OpenshiftOC ''' - super(Secret, self).__init__(namespace, kubeconfig) - self.namespace = namespace - self.name = secret_name - self.kubeconfig = kubeconfig - self.verbose = verbose - - def get(self): - '''return a secret by name ''' - return self._get('secrets', self.name) - - def delete(self): - '''delete a secret by name''' - return self._delete('secrets', self.name) - - def create(self, files=None, contents=None): - '''Create a secret ''' - if not files: - files = Utils.create_files_from_contents(contents) - - secrets = ["%s=%s" % (os.path.basename(sfile), sfile) for sfile in files] - cmd = ['-n%s' % self.namespace, 'secrets', 'new', self.name] - cmd.extend(secrets) - - return self.openshift_cmd(cmd) - - def update(self, files, force=False): - '''run update secret - - 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. - ''' - secret = self.prep_secret(files) - if secret['returncode'] != 0: - return secret - - sfile_path = '/tmp/%s' % self.name - with open(sfile_path, 'w') as sfd: - sfd.write(json.dumps(secret['results'])) - - atexit.register(Utils.cleanup, [sfile_path]) - - return self._replace(sfile_path, force=force) - - def prep_secret(self, files=None, contents=None): - ''' return what the secret would look like if created - This is accomplished by passing -ojson. This will most likely change in the future - ''' - if not files: - files = Utils.create_files_from_contents(contents) - - secrets = ["%s=%s" % (os.path.basename(sfile), sfile) for sfile in files] - cmd = ['-ojson', '-n%s' % self.namespace, 'secrets', 'new', self.name] - cmd.extend(secrets) - - return self.openshift_cmd(cmd, output=True) - - - -# pylint: disable=too-many-branches -def main(): - ''' - ansible oc module for secrets - ''' - - 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'), - files=dict(default=None, type='list'), - delete_after=dict(default=False, type='bool'), - contents=dict(default=None, type='list'), - force=dict(default=False, type='bool'), - ), - mutually_exclusive=[["contents", "files"]], - - supports_check_mode=True, - ) - occmd = Secret(module.params['namespace'], - module.params['name'], - kubeconfig=module.params['kubeconfig'], - verbose=module.params['debug']) - - state = module.params['state'] - - api_rval = occmd.get() - - ##### - # 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() - module.exit_json(changed=True, results=api_rval, state="absent") - - - if state == 'present': - if module.params['files']: - files = module.params['files'] - elif module.params['contents']: - files = Utils.create_files_from_contents(module.params['contents']) - else: - module.fail_json(msg='Either specify files or contents.') - - ######## - # 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.create(module.params['files'], module.params['contents']) - - # Remove files - if files and module.params['delete_after']: - Utils.cleanup(files) - - module.exit_json(changed=True, results=api_rval, state="present") - - ######## - # Update - ######## - secret = occmd.prep_secret(module.params['files'], module.params['contents']) - - if secret['returncode'] != 0: - module.fail_json(msg=secret) - - if Utils.check_def_equal(secret['results'], api_rval['results'][0]): - - # Remove files - if files and module.params['delete_after']: - Utils.cleanup(files) - - module.exit_json(changed=False, results=secret['results'], state="present") - - if module.check_mode: - module.exit_json(change=False, msg='Would have performed an update.') - - api_rval = occmd.update(files, force=module.params['force']) - - # Remove files - if secret and module.params['delete_after']: - Utils.cleanup(files) - - 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() -- cgit v1.2.3