def legacy_varReplace(basedir, raw, vars, lookup_fatal=True, depth=0, expand_lists=False): ''' Perform variable replacement of $variables in string raw using vars dictionary ''' # this code originally from yum orig = raw if not isinstance(raw, unicode): raw = raw.decode("utf-8") if (depth > 20): raise errors.AnsibleError("template recursion depth exceeded") done = [] # Completed chunks to return while raw: m = _legacy_varFind(basedir, raw, vars, lookup_fatal, depth, expand_lists) 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([str(x) for x in replacement]) if isinstance(replacement, (str, unicode)): replacement = legacy_varReplace(basedir, replacement, vars, lookup_fatal, 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(unicode(replacement)) # Append replacement value raw = raw[end:] # Continue with remainder of string result = ''.join(done) if (not '\$' in orig) and (result != orig): from ansible import utils # above check against \$ as templating will remove the backslash utils.deprecated( "Legacy variable substitution, such as using ${foo} or $foo instead of {{ foo }} is currently valid but will be phased out and has been out of favor since version 1.2. This is the last of legacy features on our deprecation list. You may continue to use this if you have specific needs for now", "1.6") return result
def legacy_varReplace(basedir, raw, vars, lookup_fatal=True, depth=0, expand_lists=False): ''' Perform variable replacement of $variables in string raw using vars dictionary ''' # this code originally from yum orig = raw if not isinstance(raw, unicode): raw = raw.decode("utf-8") if (depth > 20): raise errors.AnsibleError("template recursion depth exceeded") done = [] # Completed chunks to return while raw: m = _legacy_varFind(basedir, raw, vars, lookup_fatal, depth, expand_lists) 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([str(x) for x in replacement]) if isinstance(replacement, (str, unicode)): replacement = legacy_varReplace(basedir, replacement, vars, lookup_fatal, 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(unicode(replacement)) # Append replacement value raw = raw[end:] # Continue with remainder of string result = ''.join(done) if (not '\$' in orig) and (result != orig): from ansible import utils # above check against \$ as templating will remove the backslash utils.deprecated("Legacy variable substitution, such as using ${foo} or $foo instead of {{ foo }} is currently valid but will be phased out and has been out of favor since version 1.2. This is the last of legacy features on our deprecation list. You may continue to use this if you have specific needs for now","1.6") return result
def _load_tasks(self, tasks, vars=None, default_vars=None, sudo_vars=None, additional_conditions=None, original_file=None, role_name=None): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] if additional_conditions is None: additional_conditions = [] if vars is None: vars = {} if default_vars is None: default_vars = {} if sudo_vars is None: sudo_vars = {} old_conditions = list(additional_conditions) for x in tasks: # prevent assigning the same conditions to each task on an include included_additional_conditions = list(old_conditions) if not isinstance(x, dict): raise errors.AnsibleError("expecting dict; got: %s" % x) # evaluate sudo vars for current and child tasks included_sudo_vars = {} for k in ["sudo", "sudo_user"]: if k in x: included_sudo_vars[k] = x[k] elif k in sudo_vars: included_sudo_vars[k] = sudo_vars[k] x[k] = sudo_vars[k] if 'meta' in x: if x['meta'] == 'flush_handlers': results.append(Task(self,x)) continue task_vars = self.vars.copy() task_vars.update(vars) if original_file: task_vars['_original_file'] = original_file if 'include' in x: tokens = shlex.split(str(x['include'])) items = [''] included_additional_conditions = list(additional_conditions) include_vars = {} for k in x: if k.startswith("with_"): utils.deprecated("include + with_items is an unsupported feature and has been undocumented for many releases because of this", "1.5") plugin_name = k[5:] if plugin_name not in utils.plugins.lookup_loader: raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) terms = template(self.basedir, x[k], task_vars) items = utils.plugins.lookup_loader.get(plugin_name, basedir=self.basedir, runner=None).run(terms, inject=task_vars) elif k.startswith("when_"): included_additional_conditions.insert(0, utils.compile_when_to_only_if("%s %s" % (k[5:], x[k]))) elif k == 'when': if type(x[k]) is str: included_additional_conditions.insert(0, utils.compile_when_to_only_if("jinja2_compare %s" % x[k])) elif type(x[k]) is list: for i in x[k]: included_additional_conditions.insert(0, utils.compile_when_to_only_if("jinja2_compare %s" % i)) elif k in ("include", "vars", "default_vars", "only_if", "sudo", "sudo_user", "role_name"): continue else: include_vars[k] = x[k] default_vars = x.get('default_vars', {}) if not default_vars: default_vars = self.default_vars else: default_vars = utils.combine_vars(self.default_vars, default_vars) # append the vars defined with the include (from above) # as well as the old-style 'vars' element. The old-style # vars are given higher precedence here (just in case) task_vars = utils.combine_vars(task_vars, include_vars) if 'vars' in x: task_vars = utils.combine_vars(task_vars, x['vars']) if 'only_if' in x: included_additional_conditions.append(x['only_if']) new_role = None if 'role_name' in x: new_role = x['role_name'] for item in items: mv = task_vars.copy() mv['item'] = item for t in tokens[1:]: (k,v) = t.split("=", 1) mv[k] = template(self.basedir, v, mv) dirname = self.basedir if original_file: dirname = os.path.dirname(original_file) include_file = template(dirname, tokens[0], mv) include_filename = utils.path_dwim(dirname, include_file) data = utils.parse_yaml_from_file(include_filename) if 'role_name' in x and data is not None: for x in data: if 'include' in x: x['role_name'] = new_role loaded = self._load_tasks(data, mv, default_vars, included_sudo_vars, list(included_additional_conditions), original_file=include_filename, role_name=new_role) results += loaded elif type(x) == dict: task = Task(self,x,module_vars=task_vars,default_vars=default_vars,additional_conditions=list(additional_conditions),role_name=role_name) results.append(task) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def _load_tasks(self, tasks, vars=None, default_vars=None, sudo_vars=None, additional_conditions=None, original_file=None, role_name=None): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] if additional_conditions is None: additional_conditions = [] if vars is None: vars = {} if default_vars is None: default_vars = {} if sudo_vars is None: sudo_vars = {} old_conditions = list(additional_conditions) for x in tasks: # prevent assigning the same conditions to each task on an include included_additional_conditions = list(old_conditions) if not isinstance(x, dict): raise errors.AnsibleError( "expecting dict; got: %s, error in %s" % (x, original_file)) # evaluate sudo vars for current and child tasks included_sudo_vars = {} for k in ["sudo", "sudo_user"]: if k in x: included_sudo_vars[k] = x[k] elif k in sudo_vars: included_sudo_vars[k] = sudo_vars[k] x[k] = sudo_vars[k] if 'meta' in x: if x['meta'] == 'flush_handlers': results.append(Task(self, x)) continue task_vars = self.vars.copy() task_vars.update(vars) if original_file: task_vars['_original_file'] = original_file if 'include' in x: tokens = shlex.split(str(x['include'])) items = [''] included_additional_conditions = list(additional_conditions) include_vars = {} for k in x: if k.startswith("with_"): if original_file: offender = " (in %s)" % original_file else: offender = "" utils.deprecated( "include + with_items is a removed deprecated feature" + offender, "1.5", removed=True) elif k.startswith("when_"): utils.deprecated( "\"when_<criteria>:\" is a removed deprecated feature, use the simplified 'when:' conditional directly", None, removed=True) elif k == 'when': if type(x[k]) is str: included_additional_conditions.insert(0, x[k]) elif type(x[k]) is list: for i in x[k]: included_additional_conditions.insert(0, i) elif k in ("include", "vars", "default_vars", "sudo", "sudo_user", "role_name", "no_log"): continue else: include_vars[k] = x[k] default_vars = x.get('default_vars', {}) if not default_vars: default_vars = self.default_vars else: default_vars = utils.combine_vars(self.default_vars, default_vars) # append the vars defined with the include (from above) # as well as the old-style 'vars' element. The old-style # vars are given higher precedence here (just in case) task_vars = utils.combine_vars(task_vars, include_vars) if 'vars' in x: task_vars = utils.combine_vars(task_vars, x['vars']) if 'when' in x: if isinstance(x['when'], (basestring, bool)): included_additional_conditions.append(x['when']) elif isinstance(x['when'], list): included_additional_conditions.extend(x['when']) new_role = None if 'role_name' in x: new_role = x['role_name'] for item in items: mv = task_vars.copy() mv['item'] = item for t in tokens[1:]: (k, v) = t.split("=", 1) mv[k] = template(self.basedir, v, mv) dirname = self.basedir if original_file: dirname = os.path.dirname(original_file) include_file = template(dirname, tokens[0], mv) include_filename = utils.path_dwim(dirname, include_file) data = utils.parse_yaml_from_file( include_filename, vault_password=self.vault_password) if 'role_name' in x and data is not None: for y in data: if isinstance(y, dict) and 'include' in y: y['role_name'] = new_role loaded = self._load_tasks( data, mv, default_vars, included_sudo_vars, list(included_additional_conditions), original_file=include_filename, role_name=new_role) results += loaded elif type(x) == dict: task = Task(self, x, module_vars=task_vars, default_vars=default_vars, additional_conditions=list(additional_conditions), role_name=role_name) results.append(task) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def __init__(self, play, ds, module_vars=None, play_vars=None, play_file_vars=None, role_vars=None, role_params=None, default_vars=None, additional_conditions=None, role_name=None): ''' constructor loads from a task or handler datastructure ''' # meta directives are used to tell things like ansible/playbook to run # operations like handler execution. Meta tasks are not executed # normally. if 'meta' in ds: self.meta = ds['meta'] self.tags = [] return else: self.meta = None library = os.path.join(play.basedir, 'library') if os.path.exists(library): utils.plugins.module_finder.add_directory(library) for x in ds.keys(): # code to allow for saying "modulename: args" versus "action: modulename args" if x in utils.plugins.module_finder: if 'action' in ds: raise errors.AnsibleError( "multiple actions specified in task: '%s' and '%s'" % (x, ds.get('name', ds['action']))) if isinstance(ds[x], dict): if 'args' in ds: raise errors.AnsibleError( "can't combine args: and a dict for %s: in task %s" % (x, ds.get('name', "%s: %s" % (x, ds[x])))) ds['args'] = ds[x] ds[x] = '' elif ds[x] is None: ds[x] = '' if not isinstance(ds[x], basestring): raise errors.AnsibleError( "action specified for task %s has invalid type %s" % (ds.get('name', "%s: %s" % (x, ds[x])), type(ds[x]))) ds['action'] = x + " " + ds[x] ds.pop(x) # code to allow "with_glob" and to reference a lookup plugin named glob elif x.startswith("with_"): if isinstance(ds[x], basestring): param = ds[x].strip() # Only a variable, no logic if (param.startswith('{{') and param.find('}}') == len(ds[x]) - 2 and param.find('|') == -1): utils.warning( "It is unnecessary to use '{{' in loops, leave variables in loop expressions bare." ) plugin_name = x.replace("with_", "") if plugin_name in utils.plugins.lookup_loader: ds['items_lookup_plugin'] = plugin_name ds['items_lookup_terms'] = ds[x] ds.pop(x) else: raise errors.AnsibleError( "cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) elif x in ['changed_when', 'failed_when', 'when']: if isinstance(ds[x], basestring): param = ds[x].strip() # Only a variable, no logic if (param.startswith('{{') and param.find('}}') == len(ds[x]) - 2 and param.find('|') == -1): utils.warning( "It is unnecessary to use '{{' in conditionals, leave variables in loop expressions bare." ) elif x.startswith("when_"): utils.deprecated( "The 'when_' conditional has been removed. Switch to using the regular unified 'when' statements as described on docs.ansible.com.", "1.5", removed=True) if 'when' in ds: raise errors.AnsibleError( "multiple when_* statements specified in task %s" % (ds.get('name', ds['action']))) when_name = x.replace("when_", "") ds['when'] = "%s %s" % (when_name, ds[x]) ds.pop(x) elif not x in Task.VALID_KEYS: raise errors.AnsibleError( "%s is not a legal parameter in an Ansible task or handler" % x) self.module_vars = module_vars self.play_vars = play_vars self.play_file_vars = play_file_vars self.role_vars = role_vars self.role_params = role_params self.default_vars = default_vars self.play = play # load various attributes self.name = ds.get('name', None) self.tags = ['all'] self.register = ds.get('register', None) self.sudo = utils.boolean(ds.get('sudo', play.sudo)) self.su = utils.boolean(ds.get('su', play.su)) self.environment = ds.get('environment', {}) self.role_name = role_name self.no_log = utils.boolean(ds.get('no_log', "false")) or self.play.no_log self.run_once = utils.boolean(ds.get('run_once', 'false')) #Code to allow do until feature in a Task if 'until' in ds: if not ds.get('register'): raise errors.AnsibleError( "register keyword is mandatory when using do until feature" ) self.module_vars['delay'] = ds.get('delay', 5) self.module_vars['retries'] = ds.get('retries', 3) self.module_vars['register'] = ds.get('register', None) self.until = ds.get('until') self.module_vars['until'] = self.until # rather than simple key=value args on the options line, these represent structured data and the values # can be hashes and lists, not just scalars self.args = ds.get('args', {}) # get remote_user for task, then play, then playbook if ds.get('remote_user') is not None: self.remote_user = ds.get('remote_user') elif ds.get('remote_user', play.remote_user) is not None: self.remote_user = ds.get('remote_user', play.remote_user) else: self.remote_user = ds.get('remote_user', play.playbook.remote_user) self.sudo_user = None self.sudo_pass = None self.su_user = None self.su_pass = None if self.sudo: self.sudo_user = ds.get('sudo_user', play.sudo_user) self.sudo_pass = ds.get('sudo_pass', play.playbook.sudo_pass) elif self.su: self.su_user = ds.get('su_user', play.su_user) self.su_pass = ds.get('su_pass', play.playbook.su_pass) # Fail out if user specifies a sudo param with a su param in a given play if (ds.get('sudo') or ds.get('sudo_user') or ds.get('sudo_pass')) and \ (ds.get('su') or ds.get('su_user') or ds.get('su_pass')): raise errors.AnsibleError( 'sudo params ("sudo", "sudo_user", "sudo_pass") ' 'and su params "su", "su_user", "su_pass") ' 'cannot be used together') # Both are defined if ('action' in ds) and ('local_action' in ds): raise errors.AnsibleError( "the 'action' and 'local_action' attributes can not be used together" ) # Both are NOT defined elif (not 'action' in ds) and (not 'local_action' in ds): raise errors.AnsibleError( "'action' or 'local_action' attribute missing in task \"%s\"" % ds.get('name', '<Unnamed>')) # Only one of them is defined elif 'local_action' in ds: self.action = ds.get('local_action', '') self.delegate_to = '127.0.0.1' else: self.action = ds.get('action', '') self.delegate_to = ds.get('delegate_to', None) self.transport = ds.get('connection', ds.get('transport', play.transport)) if isinstance(self.action, dict): if 'module' not in self.action: raise errors.AnsibleError( "'module' attribute missing from action in task \"%s\"" % ds.get('name', '%s' % self.action)) if self.args: raise errors.AnsibleError( "'args' cannot be combined with dict 'action' in task \"%s\"" % ds.get('name', '%s' % self.action)) self.args = self.action self.action = self.args.pop('module') # delegate_to can use variables if not (self.delegate_to is None): # delegate_to: localhost should use local transport if self.delegate_to in ['127.0.0.1', 'localhost']: self.transport = 'local' # notified by is used by Playbook code to flag which hosts # need to run a notifier self.notified_by = [] # if no name is specified, use the action line as the name if self.name is None: self.name = self.action # load various attributes self.when = ds.get('when', None) self.changed_when = ds.get('changed_when', None) self.failed_when = ds.get('failed_when', None) # combine the default and module vars here for use in templating all_vars = self.default_vars.copy() all_vars = utils.combine_vars(all_vars, self.play_vars) all_vars = utils.combine_vars(all_vars, self.play_file_vars) all_vars = utils.combine_vars(all_vars, self.role_vars) all_vars = utils.combine_vars(all_vars, self.module_vars) all_vars = utils.combine_vars(all_vars, self.role_params) self.async_seconds = ds.get('async', 0) # not async by default self.async_seconds = template.template_from_string( play.basedir, self.async_seconds, all_vars) self.async_seconds = int(self.async_seconds) self.async_poll_interval = ds.get('poll', 10) # default poll = 10 seconds self.async_poll_interval = template.template_from_string( play.basedir, self.async_poll_interval, all_vars) self.async_poll_interval = int(self.async_poll_interval) self.notify = ds.get('notify', []) self.first_available_file = ds.get('first_available_file', None) self.items_lookup_plugin = ds.get('items_lookup_plugin', None) self.items_lookup_terms = ds.get('items_lookup_terms', None) self.ignore_errors = ds.get('ignore_errors', False) self.any_errors_fatal = ds.get('any_errors_fatal', play.any_errors_fatal) self.always_run = ds.get('always_run', False) # action should be a string if not isinstance(self.action, basestring): raise errors.AnsibleError( "action is of type '%s' and not a string in task. name: %s" % (type(self.action).__name__, self.name)) # notify can be a string or a list, store as a list if isinstance(self.notify, basestring): self.notify = [self.notify] # split the action line into a module name + arguments try: tokens = split_args(self.action) except Exception, e: if "unbalanced" in str(e): raise errors.AnsibleError("There was an error while parsing the task %s.\n" % repr(self.action) + \ "Make sure quotes are matched or escaped properly") else: raise
def _load_tasks(self, tasks, vars=None, default_vars=None, sudo_vars=None, additional_conditions=None, original_file=None, role_name=None): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] if additional_conditions is None: additional_conditions = [] if vars is None: vars = {} if default_vars is None: default_vars = {} if sudo_vars is None: sudo_vars = {} old_conditions = list(additional_conditions) for x in tasks: # prevent assigning the same conditions to each task on an include included_additional_conditions = list(old_conditions) if not isinstance(x, dict): raise errors.AnsibleError("expecting dict; got: %s, error in %s" % (x, original_file)) # evaluate sudo vars for current and child tasks included_sudo_vars = {} for k in ["sudo", "sudo_user"]: if k in x: included_sudo_vars[k] = x[k] elif k in sudo_vars: included_sudo_vars[k] = sudo_vars[k] x[k] = sudo_vars[k] if 'meta' in x: if x['meta'] == 'flush_handlers': results.append(Task(self, x)) continue task_vars = self.vars.copy() task_vars.update(vars) if original_file: task_vars['_original_file'] = original_file if 'include' in x: tokens = split_args(str(x['include'])) included_additional_conditions = list(additional_conditions) include_vars = {} for k in x: if k.startswith("with_"): if original_file: offender = " (in %s)" % original_file else: offender = "" utils.deprecated("include + with_items is a removed deprecated feature" + offender, "1.5", removed=True) elif k.startswith("when_"): utils.deprecated("\"when_<criteria>:\" is a removed deprecated feature, use the simplified 'when:' conditional directly", None, removed=True) elif k == 'when': if isinstance(x[k], (basestring, bool)): included_additional_conditions.append(x[k]) elif type(x[k]) is list: included_additional_conditions.extend(x[k]) elif k in ("include", "vars", "default_vars", "sudo", "sudo_user", "role_name", "no_log"): continue else: include_vars[k] = x[k] default_vars = x.get('default_vars', {}) if not default_vars: default_vars = self.default_vars else: default_vars = utils.combine_vars(self.default_vars, default_vars) # append the vars defined with the include (from above) # as well as the old-style 'vars' element. The old-style # vars are given higher precedence here (just in case) task_vars = utils.combine_vars(task_vars, include_vars) if 'vars' in x: task_vars = utils.combine_vars(task_vars, x['vars']) new_role = None if 'role_name' in x: new_role = x['role_name'] mv = task_vars.copy() for t in tokens[1:]: (k,v) = t.split("=", 1) v = unquote(v) mv[k] = template(self.basedir, v, mv) dirname = self.basedir if original_file: dirname = os.path.dirname(original_file) include_file = template(dirname, tokens[0], mv) include_filename = utils.path_dwim(dirname, include_file) data = utils.parse_yaml_from_file(include_filename, vault_password=self.vault_password) if 'role_name' in x and data is not None: for y in data: if isinstance(y, dict) and 'include' in y: y['role_name'] = new_role loaded = self._load_tasks(data, mv, default_vars, included_sudo_vars, list(included_additional_conditions), original_file=include_filename, role_name=new_role) results += loaded elif type(x) == dict: task = Task( self, x, module_vars=task_vars, default_vars=default_vars, additional_conditions=list(additional_conditions), role_name=role_name ) results.append(task) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def __init__(self, play, ds, module_vars=None, default_vars=None, additional_conditions=None, role_name=None): ''' constructor loads from a task or handler datastructure ''' # meta directives are used to tell things like ansible/playbook to run # operations like handler execution. Meta tasks are not executed # normally. if 'meta' in ds: self.meta = ds['meta'] self.tags = [] return else: self.meta = None library = os.path.join(play.basedir, 'library') if os.path.exists(library): utils.plugins.module_finder.add_directory(library) for x in ds.keys(): # code to allow for saying "modulename: args" versus "action: modulename args" if x in utils.plugins.module_finder: if 'action' in ds: raise errors.AnsibleError("multiple actions specified in task: '%s' and '%s'" % (x, ds.get('name', ds['action']))) if isinstance(ds[x], dict): if 'args' in ds: raise errors.AnsibleError("can't combine args: and a dict for %s: in task %s" % (x, ds.get('name', "%s: %s" % (x, ds[x])))) ds['args'] = ds[x] ds[x] = '' elif ds[x] is None: ds[x] = '' if not isinstance(ds[x], basestring): raise errors.AnsibleError("action specified for task %s has invalid type %s" % (ds.get('name', "%s: %s" % (x, ds[x])), type(ds[x]))) ds['action'] = x + " " + ds[x] ds.pop(x) # code to allow "with_glob" and to reference a lookup plugin named glob elif x.startswith("with_"): if isinstance(ds[x], basestring) and ds[x].lstrip().startswith("{{"): utils.warning("It is unnecessary to use '{{' in loops, leave variables in loop expressions bare.") plugin_name = x.replace("with_","") if plugin_name in utils.plugins.lookup_loader: ds['items_lookup_plugin'] = plugin_name ds['items_lookup_terms'] = ds[x] ds.pop(x) else: raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) elif x in [ 'changed_when', 'failed_when', 'when']: if isinstance(ds[x], basestring) and ds[x].lstrip().startswith("{{"): utils.warning("It is unnecessary to use '{{' in conditionals, leave variables in loop expressions bare.") elif x.startswith("when_"): utils.deprecated("The 'when_' conditional has been removed. Switch to using the regular unified 'when' statements as described on docs.ansible.com.","1.5", removed=True) if 'when' in ds: raise errors.AnsibleError("multiple when_* statements specified in task %s" % (ds.get('name', ds['action']))) when_name = x.replace("when_","") ds['when'] = "%s %s" % (when_name, ds[x]) ds.pop(x) elif not x in Task.VALID_KEYS: raise errors.AnsibleError("%s is not a legal parameter in an Ansible task or handler" % x) self.module_vars = module_vars self.default_vars = default_vars self.play = play # load various attributes self.name = ds.get('name', None) self.tags = [ 'all' ] self.register = ds.get('register', None) self.sudo = utils.boolean(ds.get('sudo', play.sudo)) self.su = utils.boolean(ds.get('su', play.su)) self.environment = ds.get('environment', {}) self.role_name = role_name self.no_log = utils.boolean(ds.get('no_log', "false")) self.run_once = utils.boolean(ds.get('run_once', 'false')) #Code to allow do until feature in a Task if 'until' in ds: if not ds.get('register'): raise errors.AnsibleError("register keyword is mandatory when using do until feature") self.module_vars['delay'] = ds.get('delay', 5) self.module_vars['retries'] = ds.get('retries', 3) self.module_vars['register'] = ds.get('register', None) self.until = ds.get('until') self.module_vars['until'] = self.until # rather than simple key=value args on the options line, these represent structured data and the values # can be hashes and lists, not just scalars self.args = ds.get('args', {}) # get remote_user for task, then play, then playbook if ds.get('remote_user') is not None: self.remote_user = ds.get('remote_user') elif ds.get('remote_user', play.remote_user) is not None: self.remote_user = ds.get('remote_user', play.remote_user) else: self.remote_user = ds.get('remote_user', play.playbook.remote_user) self.sudo_user = None self.sudo_pass = None self.su_user = None self.su_pass = None if self.sudo: self.sudo_user = ds.get('sudo_user', play.sudo_user) self.sudo_pass = ds.get('sudo_pass', play.playbook.sudo_pass) elif self.su: self.su_user = ds.get('su_user', play.su_user) self.su_pass = ds.get('su_pass', play.playbook.su_pass) # Fail out if user specifies a sudo param with a su param in a given play if (ds.get('sudo') or ds.get('sudo_user') or ds.get('sudo_pass')) and \ (ds.get('su') or ds.get('su_user') or ds.get('su_pass')): raise errors.AnsibleError('sudo params ("sudo", "sudo_user", "sudo_pass") ' 'and su params "su", "su_user", "su_pass") ' 'cannot be used together') # Both are defined if ('action' in ds) and ('local_action' in ds): raise errors.AnsibleError("the 'action' and 'local_action' attributes can not be used together") # Both are NOT defined elif (not 'action' in ds) and (not 'local_action' in ds): raise errors.AnsibleError("'action' or 'local_action' attribute missing in task \"%s\"" % ds.get('name', '<Unnamed>')) # Only one of them is defined elif 'local_action' in ds: self.action = ds.get('local_action', '') self.delegate_to = '127.0.0.1' else: self.action = ds.get('action', '') self.delegate_to = ds.get('delegate_to', None) self.transport = ds.get('connection', ds.get('transport', play.transport)) if isinstance(self.action, dict): if 'module' not in self.action: raise errors.AnsibleError("'module' attribute missing from action in task \"%s\"" % ds.get('name', '%s' % self.action)) if self.args: raise errors.AnsibleError("'args' cannot be combined with dict 'action' in task \"%s\"" % ds.get('name', '%s' % self.action)) self.args = self.action self.action = self.args.pop('module') # delegate_to can use variables if not (self.delegate_to is None): # delegate_to: localhost should use local transport if self.delegate_to in ['127.0.0.1', 'localhost']: self.transport = 'local' # notified by is used by Playbook code to flag which hosts # need to run a notifier self.notified_by = [] # if no name is specified, use the action line as the name if self.name is None: self.name = self.action # load various attributes self.when = ds.get('when', None) self.changed_when = ds.get('changed_when', None) self.failed_when = ds.get('failed_when', None) # combine the default and module vars here for use in templating all_vars = self.default_vars.copy() all_vars = utils.combine_vars(all_vars, self.module_vars) self.async_seconds = ds.get('async', 0) # not async by default self.async_seconds = template.template_from_string(play.basedir, self.async_seconds, all_vars) self.async_seconds = int(self.async_seconds) self.async_poll_interval = ds.get('poll', 10) # default poll = 10 seconds self.async_poll_interval = template.template_from_string(play.basedir, self.async_poll_interval, all_vars) self.async_poll_interval = int(self.async_poll_interval) self.notify = ds.get('notify', []) self.first_available_file = ds.get('first_available_file', None) self.items_lookup_plugin = ds.get('items_lookup_plugin', None) self.items_lookup_terms = ds.get('items_lookup_terms', None) self.ignore_errors = ds.get('ignore_errors', False) self.any_errors_fatal = ds.get('any_errors_fatal', play.any_errors_fatal) self.always_run = ds.get('always_run', False) # action should be a string if not isinstance(self.action, basestring): raise errors.AnsibleError("action is of type '%s' and not a string in task. name: %s" % (type(self.action).__name__, self.name)) # notify can be a string or a list, store as a list if isinstance(self.notify, basestring): self.notify = [ self.notify ] # split the action line into a module name + arguments try: tokens = split_args(self.action) except Exception, e: if "unbalanced" in str(e): raise errors.AnsibleError("There was an error while parsing the task %s.\n" % repr(self.action) + \ "Make sure quotes are matched or escaped properly") else: raise
def __init__(self, play, ds, module_vars=None, default_vars=None, additional_conditions=None, role_name=None): ''' constructor loads from a task or handler datastructure ''' # meta directives are used to tell things like ansible/playbook to run # operations like handler execution. Meta tasks are not executed # normally. if 'meta' in ds: self.meta = ds['meta'] self.tags = [] return else: self.meta = None library = os.path.join(play.basedir, 'library') if os.path.exists(library): utils.plugins.module_finder.add_directory(library) for x in ds.keys(): # code to allow for saying "modulename: args" versus "action: modulename args" if x in utils.plugins.module_finder: if 'action' in ds: raise errors.AnsibleError("multiple actions specified in task %s" % (ds.get('name', ds['action']))) if isinstance(ds[x], dict): if 'args' in ds: raise errors.AnsibleError("can't combine args: and a dict for %s: in task %s" % (x, ds.get('name', "%s: %s" % (x, ds[x])))) ds['args'] = ds[x] ds[x] = '' elif ds[x] is None: ds[x] = '' if not isinstance(ds[x], basestring): raise errors.AnsibleError("action specified for task %s has invalid type %s" % (ds.get('name', "%s: %s" % (x, ds[x])), type(ds[x]))) ds['action'] = x + " " + ds[x] ds.pop(x) # code to allow "with_glob" and to reference a lookup plugin named glob elif x.startswith("with_"): if isinstance(ds[x], basestring) and ds[x].lstrip().startswith("{{"): utils.warning("It is unneccessary to use '{{' in loops, leave variables in loop expressions bare.") plugin_name = x.replace("with_","") if plugin_name in utils.plugins.lookup_loader: ds['items_lookup_plugin'] = plugin_name ds['items_lookup_terms'] = ds[x] ds.pop(x) else: raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) elif x in [ 'changed_when', 'failed_when', 'when']: if isinstance(ds[x], basestring) and ds[x].lstrip().startswith("{{"): utils.warning("It is unneccessary to use '{{' in conditionals, leave variables in loop expressions bare.") elif x.startswith("when_"): utils.deprecated("The 'when_' conditional has been removed. Switch to using the regular unified 'when' statements as described in ansibleworks.com/docs/.","1.5", removed=True) if 'when' in ds: raise errors.AnsibleError("multiple when_* statements specified in task %s" % (ds.get('name', ds['action']))) when_name = x.replace("when_","") ds['when'] = "%s %s" % (when_name, ds[x]) ds.pop(x) elif not x in Task.VALID_KEYS: raise errors.AnsibleError("%s is not a legal parameter in an Ansible task or handler" % x) self.module_vars = module_vars self.default_vars = default_vars self.play = play # load various attributes self.name = ds.get('name', None) self.tags = [ 'all' ] self.register = ds.get('register', None) self.sudo = utils.boolean(ds.get('sudo', play.sudo)) self.environment = ds.get('environment', {}) self.role_name = role_name #Code to allow do until feature in a Task if 'until' in ds: if not ds.get('register'): raise errors.AnsibleError("register keyword is mandatory when using do until feature") self.module_vars['delay'] = ds.get('delay', 5) self.module_vars['retries'] = ds.get('retries', 3) self.module_vars['register'] = ds.get('register', None) self.until = ds.get('until') self.module_vars['until'] = self.until # rather than simple key=value args on the options line, these represent structured data and the values # can be hashes and lists, not just scalars self.args = ds.get('args', {}) # get remote_user for task, then play, then playbook if ds.get('remote_user') is not None: self.remote_user = ds.get('remote_user') elif ds.get('remote_user', play.remote_user) is not None: self.remote_user = ds.get('remote_user', play.remote_user) else: self.remote_user = ds.get('remote_user', play.playbook.remote_user) if self.sudo: self.sudo_user = ds.get('sudo_user', play.sudo_user) self.sudo_pass = ds.get('sudo_pass', play.playbook.sudo_pass) else: self.sudo_user = None self.sudo_pass = None # Both are defined if ('action' in ds) and ('local_action' in ds): raise errors.AnsibleError("the 'action' and 'local_action' attributes can not be used together") # Both are NOT defined elif (not 'action' in ds) and (not 'local_action' in ds): raise errors.AnsibleError("'action' or 'local_action' attribute missing in task \"%s\"" % ds.get('name', '<Unnamed>')) # Only one of them is defined elif 'local_action' in ds: self.action = ds.get('local_action', '') self.delegate_to = '127.0.0.1' else: self.action = ds.get('action', '') self.delegate_to = ds.get('delegate_to', None) self.transport = ds.get('connection', ds.get('transport', play.transport)) if isinstance(self.action, dict): if 'module' not in self.action: raise errors.AnsibleError("'module' attribute missing from action in task \"%s\"" % ds.get('name', '%s' % self.action)) if self.args: raise errors.AnsibleError("'args' cannot be combined with dict 'action' in task \"%s\"" % ds.get('name', '%s' % self.action)) self.args = self.action self.action = self.args.pop('module') # delegate_to can use variables if not (self.delegate_to is None): # delegate_to: localhost should use local transport if self.delegate_to in ['127.0.0.1', 'localhost']: self.transport = 'local' # notified by is used by Playbook code to flag which hosts # need to run a notifier self.notified_by = [] # if no name is specified, use the action line as the name if self.name is None: self.name = self.action # load various attributes self.when = ds.get('when', None) self.changed_when = ds.get('changed_when', None) self.failed_when = ds.get('failed_when', None) self.async_seconds = int(ds.get('async', 0)) # not async by default self.async_poll_interval = int(ds.get('poll', 10)) # default poll = 10 seconds self.notify = ds.get('notify', []) self.first_available_file = ds.get('first_available_file', None) self.items_lookup_plugin = ds.get('items_lookup_plugin', None) self.items_lookup_terms = ds.get('items_lookup_terms', None) self.ignore_errors = ds.get('ignore_errors', False) self.any_errors_fatal = ds.get('any_errors_fatal', play.any_errors_fatal) self.always_run = ds.get('always_run', False) # action should be a string if not isinstance(self.action, basestring): raise errors.AnsibleError("action is of type '%s' and not a string in task. name: %s" % (type(self.action).__name__, self.name)) # notify can be a string or a list, store as a list if isinstance(self.notify, basestring): self.notify = [ self.notify ] # split the action line into a module name + arguments tokens = self.action.split(None, 1) if len(tokens) < 1: raise errors.AnsibleError("invalid/missing action in task. name: %s" % self.name) self.module_name = tokens[0] self.module_args = '' if len(tokens) > 1: self.module_args = tokens[1] import_tags = self.module_vars.get('tags',[]) if type(import_tags) in [int,float]: import_tags = str(import_tags) elif type(import_tags) in [str,unicode]: # allow the user to list comma delimited tags import_tags = import_tags.split(",") # handle mutually incompatible options incompatibles = [ x for x in [ self.first_available_file, self.items_lookup_plugin ] if x is not None ] if len(incompatibles) > 1: raise errors.AnsibleError("with_(plugin), and first_available_file are mutually incompatible in a single task") # make first_available_file accessable to Runner code if self.first_available_file: self.module_vars['first_available_file'] = self.first_available_file if self.items_lookup_plugin is not None: self.module_vars['items_lookup_plugin'] = self.items_lookup_plugin self.module_vars['items_lookup_terms'] = self.items_lookup_terms # allow runner to see delegate_to option self.module_vars['delegate_to'] = self.delegate_to # make some task attributes accessible to Runner code self.module_vars['ignore_errors'] = self.ignore_errors self.module_vars['register'] = self.register self.module_vars['changed_when'] = self.changed_when self.module_vars['failed_when'] = self.failed_when self.module_vars['always_run'] = self.always_run # tags allow certain parts of a playbook to be run without running the whole playbook apply_tags = ds.get('tags', None) if apply_tags is not None: if type(apply_tags) in [ str, unicode ]: self.tags.append(apply_tags) elif type(apply_tags) in [ int, float ]: self.tags.append(str(apply_tags)) elif type(apply_tags) == list: self.tags.extend(apply_tags) self.tags.extend(import_tags) if additional_conditions: new_conditions = additional_conditions new_conditions.append(self.when) self.when = new_conditions
def _load_tasks(self, tasks, vars=None, role_params=None, default_vars=None, become_vars=None, additional_conditions=None, original_file=None, role_name=None): ''' handle task and handler include statements ''' results = [] if tasks is None: # support empty handler files, and the like. tasks = [] if additional_conditions is None: additional_conditions = [] if vars is None: vars = {} if role_params is None: role_params = {} if default_vars is None: default_vars = {} if become_vars is None: become_vars = {} old_conditions = list(additional_conditions) for x in tasks: # prevent assigning the same conditions to each task on an include included_additional_conditions = list(old_conditions) if not isinstance(x, dict): raise errors.AnsibleError("expecting dict; got: %s, error in %s" % (x, original_file)) # evaluate privilege escalation vars for current and child tasks included_become_vars = {} for k in ["become", "become_user", "become_method", "become_exe", "sudo", "su", "sudo_user", "su_user"]: if k in x: included_become_vars[k] = x[k] elif k in become_vars: included_become_vars[k] = become_vars[k] x[k] = become_vars[k] task_vars = vars.copy() if original_file: task_vars['_original_file'] = original_file if 'meta' in x: if x['meta'] == 'flush_handlers': if role_name and 'role_name' not in x: x['role_name'] = role_name results.append(Task(self, x, module_vars=task_vars, role_name=role_name)) continue if 'include' in x: tokens = split_args(str(x['include'])) included_additional_conditions = list(additional_conditions) include_vars = {} for k in x: if k.startswith("with_"): if original_file: offender = " (in %s)" % original_file else: offender = "" utils.deprecated("include + with_items is a removed deprecated feature" + offender, "1.5", removed=True) elif k.startswith("when_"): utils.deprecated("\"when_<criteria>:\" is a removed deprecated feature, use the simplified 'when:' conditional directly", None, removed=True) elif k == 'when': if isinstance(x[k], (basestring, bool)): included_additional_conditions.append(x[k]) elif type(x[k]) is list: included_additional_conditions.extend(x[k]) elif k in ("include", "vars", "role_params", "default_vars", "sudo", "sudo_user", "role_name", "no_log", "become", "become_user", "su", "su_user"): continue else: include_vars[k] = x[k] # get any role parameters specified role_params = x.get('role_params', {}) # get any role default variables specified default_vars = x.get('default_vars', {}) if not default_vars: default_vars = self.default_vars else: default_vars = utils.combine_vars(self.default_vars, default_vars) # append the vars defined with the include (from above) # as well as the old-style 'vars' element. The old-style # vars are given higher precedence here (just in case) task_vars = utils.combine_vars(task_vars, include_vars) if 'vars' in x: task_vars = utils.combine_vars(task_vars, x['vars']) new_role = None if 'role_name' in x: new_role = x['role_name'] mv = task_vars.copy() for t in tokens[1:]: (k,v) = t.split("=", 1) v = unquote(v) mv[k] = template(self.basedir, v, mv) dirname = self.basedir if original_file: dirname = os.path.dirname(original_file) # temp vars are used here to avoid trampling on the existing vars structures temp_vars = utils.combine_vars(self.vars, self.vars_file_vars) temp_vars = utils.combine_vars(temp_vars, mv) temp_vars = utils.combine_vars(temp_vars, self.playbook.extra_vars) include_file = template(dirname, tokens[0], temp_vars) include_filename = utils.path_dwim(dirname, include_file) data = utils.parse_yaml_from_file(include_filename, vault_password=self.vault_password) if 'role_name' in x and data is not None: for y in data: if isinstance(y, dict) and 'include' in y: y['role_name'] = new_role loaded = self._load_tasks(data, mv, role_params, default_vars, included_become_vars, list(included_additional_conditions), original_file=include_filename, role_name=new_role) results += loaded elif type(x) == dict: task = Task( self, x, module_vars=task_vars, play_vars=self.vars, play_file_vars=self.vars_file_vars, role_vars=self.role_vars, role_params=role_params, default_vars=default_vars, additional_conditions=list(additional_conditions), role_name=role_name ) results.append(task) else: raise Exception("unexpected task type") for x in results: if self.tags is not None: x.tags.extend(self.tags) return results
def __init__(self, play, ds, module_vars=None, default_vars=None, additional_conditions=None, role_name=None): ''' constructor loads from a task or handler datastructure ''' # meta directives are used to tell things like ansible/playbook to run # operations like handler execution. Meta tasks are not executed # normally. if 'meta' in ds: self.meta = ds['meta'] self.tags = [] return else: self.meta = None library = os.path.join(play.basedir, 'library') if os.path.exists(library): utils.plugins.module_finder.add_directory(library) for x in ds.keys(): # code to allow for saying "modulename: args" versus "action: modulename args" if x in utils.plugins.module_finder: if 'action' in ds: raise errors.AnsibleError("multiple actions specified in task %s" % (ds.get('name', ds['action']))) if isinstance(ds[x], dict): if 'args' in ds: raise errors.AnsibleError("can't combine args: and a dict for %s: in task %s" % (x, ds.get('name', "%s: %s" % (x, ds[x])))) ds['args'] = ds[x] ds[x] = '' elif ds[x] is None: ds[x] = '' if not isinstance(ds[x], basestring): raise errors.AnsibleError("action specified for task %s has invalid type %s" % (ds.get('name', "%s: %s" % (x, ds[x])), type(ds[x]))) ds['action'] = x + " " + ds[x] ds.pop(x) # code to allow "with_glob" and to reference a lookup plugin named glob elif x.startswith("with_"): if isinstance(ds[x], basestring) and ds[x].lstrip().startswith("{{"): utils.warning("It is unneccessary to use '{{' in loops, leave variables in loop expressions bare.") plugin_name = x.replace("with_","") if plugin_name in utils.plugins.lookup_loader: ds['items_lookup_plugin'] = plugin_name ds['items_lookup_terms'] = ds[x] ds.pop(x) else: raise errors.AnsibleError("cannot find lookup plugin named %s for usage in with_%s" % (plugin_name, plugin_name)) elif x in [ 'changed_when', 'failed_when', 'when']: if isinstance(ds[x], basestring) and ds[x].lstrip().startswith("{{"): utils.warning("It is unneccessary to use '{{' in conditionals, leave variables in loop expressions bare.") ds[x] = "jinja2_compare %s" % (ds[x]) elif x.startswith("when_"): utils.deprecated("The 'when_' conditional is a deprecated syntax as of 1.2. Switch to using the regular unified 'when' statements as described in ansibleworks.com/docs/.","1.5") if 'when' in ds: raise errors.AnsibleError("multiple when_* statements specified in task %s" % (ds.get('name', ds['action']))) when_name = x.replace("when_","") ds['when'] = "%s %s" % (when_name, ds[x]) ds.pop(x) elif not x in Task.VALID_KEYS: raise errors.AnsibleError("%s is not a legal parameter in an Ansible task or handler" % x) self.module_vars = module_vars self.default_vars = default_vars self.play = play # load various attributes self.name = ds.get('name', None) self.tags = [ 'all' ] self.register = ds.get('register', None) self.sudo = utils.boolean(ds.get('sudo', play.sudo)) self.environment = ds.get('environment', {}) self.role_name = role_name #Code to allow do until feature in a Task if 'until' in ds: if not ds.get('register'): raise errors.AnsibleError("register keyword is mandatory when using do until feature") self.module_vars['delay'] = ds.get('delay', 5) self.module_vars['retries'] = ds.get('retries', 3) self.module_vars['register'] = ds.get('register', None) self.until = "jinja2_compare %s" % (ds.get('until')) self.module_vars['until'] = utils.compile_when_to_only_if(self.until) # rather than simple key=value args on the options line, these represent structured data and the values # can be hashes and lists, not just scalars self.args = ds.get('args', {}) # get remote_user for task, then play, then playbook if ds.get('remote_user') is not None: self.remote_user = ds.get('remote_user') elif ds.get('remote_user', play.remote_user) is not None: self.remote_user = ds.get('remote_user', play.remote_user) else: self.remote_user = ds.get('remote_user', play.playbook.remote_user) if self.sudo: self.sudo_user = ds.get('sudo_user', play.sudo_user) self.sudo_pass = ds.get('sudo_pass', play.playbook.sudo_pass) else: self.sudo_user = None self.sudo_pass = None # Both are defined if ('action' in ds) and ('local_action' in ds): raise errors.AnsibleError("the 'action' and 'local_action' attributes can not be used together") # Both are NOT defined elif (not 'action' in ds) and (not 'local_action' in ds): raise errors.AnsibleError("'action' or 'local_action' attribute missing in task \"%s\"" % ds.get('name', '<Unnamed>')) # Only one of them is defined elif 'local_action' in ds: self.action = ds.get('local_action', '') self.delegate_to = '127.0.0.1' else: self.action = ds.get('action', '') self.delegate_to = ds.get('delegate_to', None) self.transport = ds.get('connection', ds.get('transport', play.transport)) if isinstance(self.action, dict): if 'module' not in self.action: raise errors.AnsibleError("'module' attribute missing from action in task \"%s\"" % ds.get('name', '%s' % self.action)) if self.args: raise errors.AnsibleError("'args' cannot be combined with dict 'action' in task \"%s\"" % ds.get('name', '%s' % self.action)) self.args = self.action self.action = self.args.pop('module') # delegate_to can use variables if not (self.delegate_to is None): # delegate_to: localhost should use local transport if self.delegate_to in ['127.0.0.1', 'localhost']: self.transport = 'local' # notified by is used by Playbook code to flag which hosts # need to run a notifier self.notified_by = [] # if no name is specified, use the action line as the name if self.name is None: self.name = self.action # load various attributes self.only_if = ds.get('only_if', 'True') if self.only_if != 'True': utils.deprecated("only_if is a very old feature and has been obsolete since 0.9, please switch to the 'when' conditional as described at http://ansibleworks.com/docs","1.5") self.when = ds.get('when', None) self.changed_when = ds.get('changed_when', None) if self.changed_when is not None: self.changed_when = utils.compile_when_to_only_if(self.changed_when) self.failed_when = ds.get('failed_when', None) if self.failed_when is not None: self.failed_when = utils.compile_when_to_only_if(self.failed_when) self.async_seconds = int(ds.get('async', 0)) # not async by default self.async_poll_interval = int(ds.get('poll', 10)) # default poll = 10 seconds self.notify = ds.get('notify', []) self.first_available_file = ds.get('first_available_file', None) self.items_lookup_plugin = ds.get('items_lookup_plugin', None) self.items_lookup_terms = ds.get('items_lookup_terms', None) self.ignore_errors = ds.get('ignore_errors', False) self.any_errors_fatal = ds.get('any_errors_fatal', play.any_errors_fatal) self.always_run = ds.get('always_run', False) # action should be a string if not isinstance(self.action, basestring): raise errors.AnsibleError("action is of type '%s' and not a string in task. name: %s" % (type(self.action).__name__, self.name)) # notify can be a string or a list, store as a list if isinstance(self.notify, basestring): self.notify = [ self.notify ] # split the action line into a module name + arguments tokens = self.action.split(None, 1) if len(tokens) < 1: raise errors.AnsibleError("invalid/missing action in task. name: %s" % self.name) self.module_name = tokens[0] self.module_args = '' if len(tokens) > 1: self.module_args = tokens[1] import_tags = self.module_vars.get('tags',[]) if type(import_tags) in [int,float]: import_tags = str(import_tags) elif type(import_tags) in [str,unicode]: # allow the user to list comma delimited tags import_tags = import_tags.split(",") # handle mutually incompatible options incompatibles = [ x for x in [ self.first_available_file, self.items_lookup_plugin ] if x is not None ] if len(incompatibles) > 1: raise errors.AnsibleError("with_(plugin), and first_available_file are mutually incompatible in a single task") # make first_available_file accessable to Runner code if self.first_available_file: self.module_vars['first_available_file'] = self.first_available_file if self.items_lookup_plugin is not None: self.module_vars['items_lookup_plugin'] = self.items_lookup_plugin self.module_vars['items_lookup_terms'] = self.items_lookup_terms # allow runner to see delegate_to option self.module_vars['delegate_to'] = self.delegate_to # make some task attributes accessible to Runner code self.module_vars['ignore_errors'] = self.ignore_errors self.module_vars['register'] = self.register self.module_vars['changed_when'] = self.changed_when self.module_vars['failed_when'] = self.failed_when self.module_vars['always_run'] = self.always_run # tags allow certain parts of a playbook to be run without running the whole playbook apply_tags = ds.get('tags', None) if apply_tags is not None: if type(apply_tags) in [ str, unicode ]: self.tags.append(apply_tags) elif type(apply_tags) in [ int, float ]: self.tags.append(str(apply_tags)) elif type(apply_tags) == list: self.tags.extend(apply_tags) self.tags.extend(import_tags) if self.when is not None: if self.only_if != 'True': raise errors.AnsibleError('when obsoletes only_if, only use one or the other') self.only_if = utils.compile_when_to_only_if(self.when) if additional_conditions: new_conditions = additional_conditions new_conditions.append(self.only_if) self.only_if = new_conditions
def legacy_varReplace(basedir, raw, vars, lookup_fatal=True, depth=0, expand_lists=False): ''' Perform variable replacement of $variables in string raw using vars dictionary DEPRECATED LEGACY VARIABLES ARE SLATED FOR REMOVAL IN ANSIBLE 1.5 use {{ foo }} INSTEAD ''' if not C.DEFAULT_LEGACY_PLAYBOOK_VARIABLES: raise Exception("we should not be here") # this code originally from yum (and later modified a lot) orig = raw if not isinstance(raw, unicode): raw = raw.decode("utf-8") #if (depth > 20): # raise errors.AnsibleError("template recursion depth exceeded") done = [] # Completed chunks to return while raw: m = _legacy_varFind(basedir, raw, vars, lookup_fatal, depth, expand_lists) 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([str(x) for x in replacement]) if isinstance(replacement, (str, unicode)): replacement = legacy_varReplace(basedir, replacement, vars, lookup_fatal, 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(unicode(replacement)) # Append replacement value raw = raw[end:] # Continue with remainder of string result = ''.join(done) previous_old_style_vars = orig.count('$') new_old_style_vars = result.count('$') if previous_old_style_vars != new_old_style_vars: from ansible import utils utils.deprecated( "Legacy variable substitution, such as using ${foo} or $foo instead of {{ foo }} is currently valid but will be phased out and has been out of favor since version 1.2. This is the last of legacy features on our deprecation list. You may continue to use this if you have specific needs for now", "1.5") return result