Skip to content

Instantly share code, notes, and snippets.

Created December 20, 2012 22:40
Show Gist options
  • Save anonymous/4349222 to your computer and use it in GitHub Desktop.
Save anonymous/4349222 to your computer and use it in GitHub Desktop.
# Append values to a pre-defined list
import os
import pwd
import random
import traceback
import tempfile
import json
from ansible.callbacks import vv
from ansible import utils
from ansible.utils.template import _varFind
from ansible import errors
from ansible.runner.return_data import ReturnData
class ActionModule(object):
_opt_names = frozenset(['list', 'items', 'item'])
def __init__(self, runner):
self.runner = runner
def run(self, conn, tmp, module_name, module_args, inject):
'''
Append values to pre-defined list variables. Intended as a
means to subscribe to services which operate on some list of
subscriptions.
'''
# Helper function: given a path into a dict defined by a list
# of keys, and a dict, returns the value found at the path, or None
def _get(path, dct):
if len(path) is 0 or dct is None:
return dct
elem = path[0]
dct = dct.get(elem, None)
path = path[1::1]
return _get(path, dct)
def _varReplace(basedir, raw, vars, depth=0, expand_lists=False):
'''
Perform variable replacement of $variables in string raw using vars dictionary. This
is a lightly modified version of utils.varReplace() which uses json.dumps() instead of
unicode()
'''
if (depth > 20):
raise errors.AnsibleError("template recursion depth exceeded")
done = [] # Completed chunks to return
while raw:
m = _varFind(basedir, raw, vars, depth)
if not m:
done.append(raw)
break
# Determine replacement value (if unknown variable then preserve
# original)
replacement = m['replacement']
if expand_lists and isinstance(replacement, (list, tuple)):
replacement = ",".join(replacement)
if isinstance(replacement, (str, unicode)):
replacement = _varReplace(basedir, replacement, vars, depth=depth+1, expand_lists=expand_lists)
if replacement is None:
replacement = raw[m['start']:m['end']]
start, end = m['start'], m['end']
done.append(raw[:start]) # Keep stuff leading up to token
done.append(json.dumps(replacement, sort_keys=True)) # Append replacement value
raw = raw[end:] # Continue with remainder of string
return ''.join(done)
# A container for the top-level facts we want to modify
modified_facts = {}
# Parse the arguments in the standard key-value way (initially).
options = utils.parse_kv(self.runner.module_args)
# Pull out the keys we don't recognise and throw if there are any
invalids = [name for name in options.keys() if name not in ActionModule._opt_names]
if len(invalids) > 0:
raise errors.AnsibleError("invalid paramters to appendvar: %s" % ", ".join(invalids))
listname = options.get('list', None)
item = options.get('item', None)
items = options.get('items', None)
if listname is None:
raise errors.AnsibleError("you must supply a 'list' option")
if item is None and items is None:
raise errors.AnsibleError("you must supply either an 'item' or 'items' option")
listname = utils.template(self.runner.basedir, listname, inject)
path = listname.split('.')
target = _get(path, inject)
# The value must exist already, and must be a list
if target is None:
raise errors.AnsibleError("cannot append to variable '%s', as it is not defined" % listname)
# target = _put([], path, inject)
else:
if not type(target) == list:
raise errors.AnsibleError("cannot append to variable '%s', as it is not a list" % listname)
if item is None:
items = _varReplace(self.runner.basedir, items, inject)
items = json.loads(items)
if not type(items) is list:
raise errors.AnsibleError("items to be added to variable '%s' must be a list, not '%s'" % (listname, type(items)))
else:
items = _varReplace(self.runner.basedir, item, inject)
items = [json.loads(items)]
for item in items:
target.append(item)
# Now we must copy the top-level variable below which we made our change,
# into modified_facts in entirity, so that we don't modify anything else
# when we redefine it
modified_facts[path[0]] = inject[path[0]]
result = {'ansible_facts': modified_facts} #, 'changed': True}
return ReturnData(conn=conn, result=result)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment