From aa9e19c20b745f91a47292f8754a8cf52017c3e4 Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Fri, 24 Mar 2017 13:07:24 -0400 Subject: Adding a few more test cases. Fixed a bug when key was empty. Safeguard against yedit module being passed an empty key --- roles/lib_openshift/library/oc_adm_router.py | 170 +++++++++++++++++---------- 1 file changed, 107 insertions(+), 63 deletions(-) (limited to 'roles/lib_openshift/library/oc_adm_router.py') diff --git a/roles/lib_openshift/library/oc_adm_router.py b/roles/lib_openshift/library/oc_adm_router.py index e666e0d09..760ad48ad 100644 --- a/roles/lib_openshift/library/oc_adm_router.py +++ b/roles/lib_openshift/library/oc_adm_router.py @@ -270,8 +270,6 @@ EXAMPLES = ''' # -*- -*- -*- End included fragment: doc/router -*- -*- -*- # -*- -*- -*- Begin included fragment: ../../lib_utils/src/class/yedit.py -*- -*- -*- -# pylint: disable=undefined-variable,missing-docstring -# noqa: E301,E302 class YeditException(Exception): @@ -305,13 +303,13 @@ class Yedit(object): @property def separator(self): - ''' getter method for yaml_dict ''' + ''' getter method for separator ''' return self._separator @separator.setter - def separator(self): - ''' getter method for yaml_dict ''' - return self._separator + def separator(self, inc_sep): + ''' setter method for separator ''' + self._separator = inc_sep @property def yaml_dict(self): @@ -725,7 +723,17 @@ class Yedit(object): pass result = Yedit.add_entry(tmp_copy, path, value, self.separator) - if not result: + if result is None: + return (False, self.yaml_dict) + + # When path equals "" it is a special case. + # "" refers to the root of the document + # Only update the root path (entire document) when its a list or dict + if path == '': + if isinstance(result, list) or isinstance(result, dict): + self.yaml_dict = result + return (True, self.yaml_dict) + return (False, self.yaml_dict) self.yaml_dict = tmp_copy @@ -751,7 +759,7 @@ class Yedit(object): pass result = Yedit.add_entry(tmp_copy, path, value, self.separator) - if result: + if result is not None: self.yaml_dict = tmp_copy return (True, self.yaml_dict) @@ -783,15 +791,17 @@ class Yedit(object): # we will convert to bool if it matches any of the above cases if isinstance(inc_value, str) and 'bool' in vtype: if inc_value not in true_bools and inc_value not in false_bools: - raise YeditException('Not a boolean type. str=[%s] vtype=[%s]' - % (inc_value, vtype)) + raise YeditException('Not a boolean type. str=[%s] vtype=[%s]' % (inc_value, vtype)) elif isinstance(inc_value, bool) and 'str' in vtype: inc_value = str(inc_value) + # There is a special case where '' will turn into None after yaml loading it so skip + if isinstance(inc_value, str) and inc_value == '': + pass # If vtype is not str then go ahead and attempt to yaml load it. - if isinstance(inc_value, str) and 'str' not in vtype: + elif isinstance(inc_value, str) and 'str' not in vtype: try: - inc_value = yaml.load(inc_value) + inc_value = yaml.safe_load(inc_value) except Exception: raise YeditException('Could not determine type of incoming ' + 'value. value=[%s] vtype=[%s]' @@ -799,98 +809,132 @@ class Yedit(object): return inc_value + @staticmethod + def process_edits(edits, yamlfile): + '''run through a list of edits and process them one-by-one''' + results = [] + for edit in edits: + value = Yedit.parse_value(edit['value'], edit.get('value_type', '')) + if 'action' in edit and edit['action'] == 'update': + # pylint: disable=line-too-long + curr_value = Yedit.get_curr_value(Yedit.parse_value(edit.get('curr_value', None)), # noqa: E501 + edit.get('curr_value_format', None)) # noqa: E501 + + rval = yamlfile.update(edit['key'], + value, + edit.get('index', None), + curr_value) + + elif 'action' in edit and edit['action'] == 'append': + rval = yamlfile.append(edit['key'], value) + + else: + rval = yamlfile.put(edit['key'], value) + + if rval[0]: + results.append({'key': edit['key'], 'edit': rval[1]}) + + return {'changed': len(results) > 0, 'results': results} + # pylint: disable=too-many-return-statements,too-many-branches @staticmethod - def run_ansible(module): + def run_ansible(params): '''perform the idempotent crud operations''' - yamlfile = Yedit(filename=module.params['src'], - backup=module.params['backup'], - separator=module.params['separator']) + yamlfile = Yedit(filename=params['src'], + backup=params['backup'], + separator=params['separator']) + + state = params['state'] - if module.params['src']: + if params['src']: rval = yamlfile.load() - if yamlfile.yaml_dict is None and \ - module.params['state'] != 'present': + if yamlfile.yaml_dict is None and state != 'present': return {'failed': True, 'msg': 'Error opening file [%s]. Verify that the ' + 'file exists, that it is has correct' + ' permissions, and is valid yaml.'} - if module.params['state'] == 'list': - if module.params['content']: - content = Yedit.parse_value(module.params['content'], - module.params['content_type']) + if state == 'list': + if params['content']: + content = Yedit.parse_value(params['content'], params['content_type']) yamlfile.yaml_dict = content - if module.params['key']: - rval = yamlfile.get(module.params['key']) or {} + if params['key']: + rval = yamlfile.get(params['key']) or {} - return {'changed': False, 'result': rval, 'state': "list"} + return {'changed': False, 'result': rval, 'state': state} - elif module.params['state'] == 'absent': - if module.params['content']: - content = Yedit.parse_value(module.params['content'], - module.params['content_type']) + elif state == 'absent': + if params['content']: + content = Yedit.parse_value(params['content'], params['content_type']) yamlfile.yaml_dict = content - if module.params['update']: - rval = yamlfile.pop(module.params['key'], - module.params['value']) + if params['update']: + rval = yamlfile.pop(params['key'], params['value']) else: - rval = yamlfile.delete(module.params['key']) + rval = yamlfile.delete(params['key']) - if rval[0] and module.params['src']: + if rval[0] and params['src']: yamlfile.write() - return {'changed': rval[0], 'result': rval[1], 'state': "absent"} + return {'changed': rval[0], 'result': rval[1], 'state': state} - elif module.params['state'] == 'present': + elif state == 'present': # check if content is different than what is in the file - if module.params['content']: - content = Yedit.parse_value(module.params['content'], - module.params['content_type']) + if params['content']: + content = Yedit.parse_value(params['content'], params['content_type']) # We had no edits to make and the contents are the same if yamlfile.yaml_dict == content and \ - module.params['value'] is None: - return {'changed': False, - 'result': yamlfile.yaml_dict, - 'state': "present"} + params['value'] is None: + return {'changed': False, 'result': yamlfile.yaml_dict, 'state': state} yamlfile.yaml_dict = content - # we were passed a value; parse it - if module.params['value']: - value = Yedit.parse_value(module.params['value'], - module.params['value_type']) - key = module.params['key'] - if module.params['update']: - # pylint: disable=line-too-long - curr_value = Yedit.get_curr_value(Yedit.parse_value(module.params['curr_value']), # noqa: E501 - module.params['curr_value_format']) # noqa: E501 + # If we were passed a key, value then + # we enapsulate it in a list and process it + # Key, Value passed to the module : Converted to Edits list # + edits = [] + _edit = {} + if params['value'] is not None: + _edit['value'] = params['value'] + _edit['value_type'] = params['value_type'] + _edit['key'] = params['key'] - rval = yamlfile.update(key, value, module.params['index'], curr_value) # noqa: E501 + if params['update']: + _edit['action'] = 'update' + _edit['curr_value'] = params['curr_value'] + _edit['curr_value_format'] = params['curr_value_format'] + _edit['index'] = params['index'] - elif module.params['append']: - rval = yamlfile.append(key, value) - else: - rval = yamlfile.put(key, value) + elif params['append']: + _edit['action'] = 'append' + + edits.append(_edit) - if rval[0] and module.params['src']: + elif params['edits'] is not None: + edits = params['edits'] + + if edits: + results = Yedit.process_edits(edits, yamlfile) + + # if there were changes and a src provided to us we need to write + if results['changed'] and params['src']: yamlfile.write() - return {'changed': rval[0], - 'result': rval[1], 'state': "present"} + return {'changed': results['changed'], 'result': results['results'], 'state': state} # no edits to make - if module.params['src']: + if params['src']: # pylint: disable=redefined-variable-type rval = yamlfile.write() return {'changed': rval[0], 'result': rval[1], - 'state': "present"} + 'state': state} + # We were passed content but no src, key or value, or edits. Return contents in memory + return {'changed': False, 'result': yamlfile.yaml_dict, 'state': state} return {'failed': True, 'msg': 'Unkown state passed'} # -*- -*- -*- End included fragment: ../../lib_utils/src/class/yedit.py -*- -*- -*- -- cgit v1.2.1