|
@@ -180,6 +180,22 @@ EXAMPLES = '''
|
|
|
# a:
|
|
|
# b:
|
|
|
# c: d
|
|
|
+#
|
|
|
+# multiple edits at the same time
|
|
|
+- name: perform multiple edits
|
|
|
+ yedit:
|
|
|
+ src: somefile.yml
|
|
|
+ edits:
|
|
|
+ - key: a#b#c
|
|
|
+ value: d
|
|
|
+ - key: a#b#c#d
|
|
|
+ value: e
|
|
|
+ state: present
|
|
|
+# Results:
|
|
|
+# a:
|
|
|
+# b:
|
|
|
+# c:
|
|
|
+# d: e
|
|
|
'''
|
|
|
|
|
|
# -*- -*- -*- End included fragment: doc/yedit -*- -*- -*-
|
|
@@ -698,13 +714,15 @@ 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)
|
|
|
except Exception:
|
|
@@ -714,97 +732,129 @@ 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)
|
|
|
+
|
|
|
+ elif params['edits'] is not None:
|
|
|
+ edits = params['edits']
|
|
|
|
|
|
- if rval[0] and module.params['src']:
|
|
|
+ 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}
|
|
|
|
|
|
return {'failed': True, 'msg': 'Unkown state passed'}
|
|
|
|
|
@@ -837,12 +887,13 @@ def main():
|
|
|
type='str'),
|
|
|
backup=dict(default=True, type='bool'),
|
|
|
separator=dict(default='.', type='str'),
|
|
|
+ edits=dict(default=None, type='list'),
|
|
|
),
|
|
|
mutually_exclusive=[["curr_value", "index"], ['update', "append"]],
|
|
|
required_one_of=[["content", "src"]],
|
|
|
)
|
|
|
|
|
|
- rval = Yedit.run_ansible(module)
|
|
|
+ rval = Yedit.run_ansible(module.params)
|
|
|
if 'failed' in rval and rval['failed']:
|
|
|
module.fail_json(**rval)
|
|
|
|