def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # save the play context variables to a temporary dictionary, # so that we can modify the job vars without doing a full copy # and later restore them to avoid modifying things too early play_context_vars = dict() self._play_context.update_vars(play_context_vars) old_vars = dict() for k in play_context_vars.keys(): if k in self._job_vars: old_vars[k] = self._job_vars[k] self._job_vars[k] = play_context_vars[k] templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars) items = None if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: #TODO: remove convert_bare true and deprecate this in with_ if self._task.loop == 'first_found': # first_found loops are special. If the item is undefined # then we want to fall through to the next value rather # than failing. loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=False, convert_bare=True) loop_terms = [t for t in loop_terms if not templar._contains_vars(t)] else: try: loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=True) except AnsibleUndefinedVariable as e: if u'has no attribute' in to_unicode(e): loop_terms = [] display.deprecated("Skipping task due to undefined attribute, in the future this will be a fatal error.") else: raise items = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=self._job_vars) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) # now we restore any old job variables that may have been modified, # and delete them if they were in the play context vars but not in # the old variables dictionary for k in play_context_vars.keys(): if k in old_vars: self._job_vars[k] = old_vars[k] else: del self._job_vars[k] if items: from ansible.vars.unsafe_proxy import UnsafeProxy for idx, item in enumerate(items): if item is not None and not isinstance(item, UnsafeProxy): items[idx] = UnsafeProxy(item) return items
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # save the play context variables to a temporary dictionary, # so that we can modify the job vars without doing a full copy # and later restore them to avoid modifying things too early play_context_vars = dict() self._play_context.update_vars(play_context_vars) old_vars = dict() for k in play_context_vars: if k in self._job_vars: old_vars[k] = self._job_vars[k] self._job_vars[k] = play_context_vars[k] templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars) items = None if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: if self._task.loop == 'first_found': # first_found loops are special. If the item is undefined then we want to fall through to the next value rather than failing. loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=False, convert_bare=False) loop_terms = [t for t in loop_terms if not templar._contains_vars(t)] else: loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=False) # get lookup mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar) # give lookup task 'context' for subdir (mostly needed for first_found) for subdir in ['template', 'var', 'file']: # TODO: move this to constants? if subdir in self._task.action: break setattr(mylookup,'_subdir', subdir + 's') # run lookup items = mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) # now we restore any old job variables that may have been modified, # and delete them if they were in the play context vars but not in # the old variables dictionary for k in play_context_vars: if k in old_vars: self._job_vars[k] = old_vars[k] else: del self._job_vars[k] if items: from ansible.vars.unsafe_proxy import UnsafeProxy for idx, item in enumerate(items): if item is not None and not isinstance(item, UnsafeProxy): items[idx] = UnsafeProxy(item) return items
def __lookup_injects(self, terms, inject): results = [] for x in terms: intermediate = listify_lookup_plugin_terms( x, self.basedir, inject) results.append(intermediate) return results
def run_v2(self, terms, variables=None, **kwargs): """ Implements LookupModule run method for ansible v2. """ self.basedir = self.get_basedir(variables) # flatten the terms if it's passed from with_yaml_file syntax terms = listify_lookup_plugin_terms(terms, templar=self._templar, loader=self._loader, fail_on_undefined=True) ret = [] # Check if it's basestring as ansible 1.9 supports badly on unicode if isinstance(terms, basestring): terms = [terms] for term in terms: params = term.split() yaml_file = params[0] paramvals = self._build_params(params[1:]) # make relative paths to absoluate path path = self._loader.path_dwim_relative(self.basedir, '', yaml_file) data = self.read_yaml(path, **paramvals) if data is not None: if isinstance(data, list): ret.extend(data) else: ret.append(data) return ret
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # create a copy of the job vars here so that we can modify # them temporarily without changing them too early for other # parts of the code that might still need a pristine version vars_copy = self._job_vars.copy() # now we update them with the play context vars self._play_context.update_vars(vars_copy) templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=vars_copy) items = None if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: #TODO: remove convert_bare true and deprecate this in with_ try: loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=True) except AnsibleUndefinedVariable as e: if 'has no attribute' in str(e): loop_terms = [] self._display.deprecated("Skipping task due to undefined attribute, in the future this will be a fatal error.") else: raise items = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) return items
def _do_flatten(self, terms, variables): ret = [] for term in terms: term = self._check_list_of_one_list(term) if term == 'None' or term == 'null': # ignore undefined items break if isinstance(term, string_types): # convert a variable to a list term2 = listify_lookup_plugin_terms(term, templar=self._templar, loader=self._loader) # but avoid converting a plain string to a list of one string if term2 != [term]: term = term2 if isinstance(term, list): # if it's a list, check recursively for items that are a list term = self._do_flatten(term, variables) ret.extend(term) else: ret.append(term) return ret
def run(self, terms, **kwargs): items = [] domain_entries = listify_lookup_plugin_terms(self._flatten(terms), templar=self._templar, loader=self._loader) print(sys.path) for domain_entry in domain_entries: domain = domain_entry['domain'] for record in domain_entry['entries']: new_item = { 'domain': domain, 'record': record['record'], 'value': record['value'], 'type': record['type'], 'state': record['state'] if record.has_key('state') else "present", } for configKey in ['priority', 'port', 'proto', 'service', 'ttl', 'weight']: if record.has_key(configKey): new_item[configKey] = record[configKey] items.append(new_item) return items
def _do_flatten(self, terms, variables): ret = [] for term in terms: term = self._check_list_of_one_list(term) if term == 'None' or term == 'null': # ignore undefined items break if isinstance(term, basestring): # convert a variable to a list term2 = listify_lookup_plugin_terms(term, variables, loader=self._loader) # but avoid converting a plain string to a list of one string if term2 != [ term ]: term = term2 if isinstance(term, list): # if it's a list, check recursively for items that are a list term = self._do_flatten(term, variables) ret.extend(term) else: ret.append(term) return ret
def _lookup(self, name, *args, **kwargs): instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self) if instance is not None: wantlist = kwargs.pop('wantlist', False) from ansible.utils.listify import listify_lookup_plugin_terms loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) except (AnsibleUndefinedVariable, UndefinedError) as e: raise AnsibleUndefinedVariable(e) except Exception as e: if self._fail_on_lookup_errors: raise ran = None if ran: from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var if wantlist: ran = wrap_var(ran) else: try: ran = UnsafeProxy(",".join(ran)) except TypeError: if isinstance(ran, list) and len(ran) == 1: ran = wrap_var(ran[0]) else: ran = wrap_var(ran) return ran else: raise AnsibleError("lookup plugin (%s) not found" % name)
def _lookup(self, name, *args, **kwargs): instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self) if instance is not None: from ansible.utils.listify import listify_lookup_plugin_terms loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) except (AnsibleUndefinedVariable, UndefinedError) as e: raise AnsibleUndefinedVariable(e) except Exception as e: if self._fail_on_lookup_errors: raise ran = None if ran: ran = ",".join(ran) return ran else: raise AnsibleError("lookup plugin (%s) not found" % name)
def run(self, terms, variables, **kwargs): terms[0] = listify_lookup_plugin_terms(terms[0], variables, loader=self._loader) if not isinstance(terms, list) or not len(terms) == 2: raise AnsibleError("subelements lookup expects a list of two items, first a dict or a list, and second a string") if isinstance(terms[0], dict): # convert to list: if terms[0].get('skipped',False) != False: # the registered result was completely skipped return [] elementlist = [] for key in terms[0].iterkeys(): elementlist.append(terms[0][key]) else: elementlist = terms[0] subelement = terms[1] ret = [] for item0 in elementlist: if not isinstance(item0, dict): raise AnsibleError("subelements lookup expects a dictionary, got '%s'" %item0) if item0.get('skipped', False) != False: # this particular item is to be skipped continue if not subelement in item0: raise AnsibleError("could not find '%s' key in iterated item '%s'" % (subelement, item0)) if not isinstance(item0[subelement], list): raise AnsibleError("the key %s should point to a list, got '%s'" % (subelement, item0[subelement])) sublist = item0.pop(subelement, []) for item1 in sublist: ret.append((item0, item1)) return ret
def __lookup_variables(self, terms): results = [] for x in terms: intermediate = listify_lookup_plugin_terms(x, templar=self._templar, loader=self._loader) results.append(intermediate) return results
def _lookup_variables(self, terms, variables): results = [] for x in terms: try: intermediate = listify_lookup_plugin_terms(x, templar=self._templar, loader=self._loader, fail_on_undefined=True) except UndefinedError as e: raise AnsibleUndefinedVariable("One of the nested variables was undefined. The error was: %s" % e) results.append(intermediate) return results
def run(self, terms, variables=None, **kwargs): basedir = self.get_basedir(variables) escape = variables.get('escape', False) # XXX: https://github.com/ansible/ansible/issues/7370 terms = listify.listify_lookup_plugin_terms(terms, self._templar, self._loader) ret = [] inject = variables.get('vars', {}) defaults = self.options(inject) for term in terms: params = term.split() key_name = params[0] options = defaults.copy() try: for param in params[1:]: name, value = param.split('=') assert(name in options) options[name] = value except (ValueError, AssertionError), e: raise AnsibleError(e) # cache if self.cache is not None: cache_key = self.cache_key(options['bucket'], key_name) if cache_key in self.cache: contents = self.cache[cache_key] ret.append(contents) continue # connect profile_name = options['profile'] if not profile_name: for env_var in ('AWS_DEFAULT_PROFILE', 'AWS_PROFILE'): profile_name = os.environ.get(env_var) if profile_name: break cxn = None while cxn is None: try: if options['region']: cxn = boto.s3.connect_to_region( options['region'], profile_name=profile_name, ) else: cxn = boto.connect_s3(profile_name=profile_name) except boto.provider.ProfileNotFoundError, e: if profile_name is None: raise AnsibleError('Unable to connect to s3') profile_name = None except (boto.exception.BotoClientError, boto.exception.S3ResponseError), e: raise AnsibleError('Unable to connect to s3')
def _lookup(self, name, *args, **kwargs): instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self) if instance is not None: wantlist = kwargs.pop('wantlist', False) allow_unsafe = kwargs.pop('allow_unsafe', C.DEFAULT_ALLOW_UNSAFE_LOOKUPS) from ansible.utils.listify import listify_lookup_plugin_terms loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) except (AnsibleUndefinedVariable, UndefinedError) as e: raise AnsibleUndefinedVariable(e) except Exception as e: if self._fail_on_lookup_errors: raise AnsibleError( "An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, " "original message: %s" % (name, type(e), e)) ran = None if ran and not allow_unsafe: if wantlist: ran = wrap_var(ran) else: try: ran = UnsafeProxy(",".join(ran)) except TypeError: # Lookup Plugins should always return lists. Throw an error if that's not # the case: if not isinstance(ran, Sequence): raise AnsibleError( "The lookup plugin '%s' did not return a list." % name) # The TypeError we can recover from is when the value *inside* of the list # is not a string if len(ran) == 1: ran = wrap_var(ran[0]) else: ran = wrap_var(ran) if self.cur_context: self.cur_context.unsafe = True return ran else: raise AnsibleError("lookup plugin (%s) not found" % name)
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # get search path for this task to pass to lookup plugins self._job_vars['ansible_search_path'] = self._task.get_search_path() # ensure basedir is always in (dwim already searches here but we need to display it) if self._loader.get_basedir() not in self._job_vars['ansible_search_path']: self._job_vars['ansible_search_path'].append(self._loader.get_basedir()) templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars) items = None loop_cache = self._job_vars.get('_ansible_loop_cache') if loop_cache is not None: # _ansible_loop_cache may be set in `get_vars` when calculating `delegate_to` # to avoid reprocessing the loop items = loop_cache elif self._task.loop_with: if self._task.loop_with in self._shared_loader_obj.lookup_loader: fail = True if self._task.loop_with == 'first_found': # first_found loops are special. If the item is undefined then we want to fall through to the next value rather than failing. fail = False loop_terms = listify_lookup_plugin_terms(terms=self._task.loop, templar=templar, loader=self._loader, fail_on_undefined=fail, convert_bare=False) if not fail: loop_terms = [t for t in loop_terms if not templar.is_template(t)] # get lookup mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop_with, loader=self._loader, templar=templar) # give lookup task 'context' for subdir (mostly needed for first_found) for subdir in ['template', 'var', 'file']: # TODO: move this to constants? if subdir in self._task.action: break setattr(mylookup, '_subdir', subdir + 's') # run lookup items = wrap_var(mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True)) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop_with) elif self._task.loop is not None: items = templar.template(self._task.loop) if not isinstance(items, list): raise AnsibleError( "Invalid data passed to 'loop', it requires a list, got this instead: %s." " Hint: If you passed a list/dict of just one element," " try adding wantlist=True to your lookup invocation or use q/query instead of lookup." % items ) return items
def run(self, terms, inject=None, **kwargs): terms = listify_lookup_plugin_terms(terms, self.basedir, inject) terms = self.__lookup_injects(terms, inject) my_list = terms[:] if len(my_list) != 2: raise errors.AnsibleError( "with_zip_cycle requires exactly two lists") res = [flatten(x) for x in izip(my_list[0], cycle(my_list[1]))] print("res: {}".format(res)) return res
def _lookup(self, name, *args, **kwargs): instance = lookup_loader.get(name, loader=self._loader, templar=self) if instance is None: raise AnsibleError("lookup plugin (%s) not found" % name) wantlist = kwargs.pop('wantlist', False) allow_unsafe = kwargs.pop('allow_unsafe', C.DEFAULT_ALLOW_UNSAFE_LOOKUPS) errors = kwargs.pop('errors', 'strict') loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) except (AnsibleUndefinedVariable, UndefinedError) as e: raise AnsibleUndefinedVariable(e) except Exception as e: if self._fail_on_lookup_errors: msg = u"An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, original message: %s" % \ (name, type(e), to_text(e)) if errors == 'warn': display.warning(msg) elif errors == 'ignore': display.display(msg, log_only=True) else: raise AnsibleError(to_native(msg)) return [] if wantlist else None if ran and allow_unsafe is False: if self.cur_context: self.cur_context.unsafe = True if wantlist: return wrap_var(ran) try: if self.jinja2_native and isinstance(ran[0], NativeJinjaText): ran = wrap_var(NativeJinjaText(",".join(ran))) else: ran = wrap_var(",".join(ran)) except TypeError: # Lookup Plugins should always return lists. Throw an error if that's not # the case: if not isinstance(ran, Sequence): raise AnsibleError("The lookup plugin '%s' did not return a list." % name) # The TypeError we can recover from is when the value *inside* of the list # is not a string if len(ran) == 1: ran = wrap_var(ran[0]) else: ran = wrap_var(ran) return ran
def _lookup_variables(self, terms): """ Turn this: terms == ["1,2,3", "a,b"] into this: terms == [[1,2,3], [a, b]] """ results = [] for x in terms: intermediate = listify_lookup_plugin_terms(x, templar=self._templar, loader=self._loader) results.append(intermediate) return results
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' items = None if self._task.loop and self._task.loop in lookup_loader: loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, variables=self._job_vars, loader=self._loader) items = lookup_loader.get(self._task.loop, loader=self._loader).run(terms=loop_terms, variables=self._job_vars) return items
def _lookup(self, name, *args, **kwargs): instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self) if instance is not None: wantlist = kwargs.pop('wantlist', False) allow_unsafe = kwargs.pop('allow_unsafe', C.DEFAULT_ALLOW_UNSAFE_LOOKUPS) errors = kwargs.pop('errors', 'strict') from ansible.utils.listify import listify_lookup_plugin_terms loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) except (AnsibleUndefinedVariable, UndefinedError) as e: raise AnsibleUndefinedVariable(e) except Exception as e: if self._fail_on_lookup_errors: msg = u"An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, original message: %s" % \ (name, type(e), to_text(e)) if errors == 'warn': display.warning(msg) elif errors == 'ignore': display.display(msg, log_only=True) else: raise AnsibleError(to_native(msg)) ran = None if ran and not allow_unsafe: if wantlist: ran = wrap_var(ran) else: try: ran = UnsafeProxy(",".join(ran)) except TypeError: # Lookup Plugins should always return lists. Throw an error if that's not # the case: if not isinstance(ran, Sequence): raise AnsibleError("The lookup plugin '%s' did not return a list." % name) # The TypeError we can recover from is when the value *inside* of the list # is not a string if len(ran) == 1: ran = wrap_var(ran[0]) else: ran = wrap_var(ran) if self.cur_context: self.cur_context.unsafe = True return ran else: raise AnsibleError("lookup plugin (%s) not found" % name)
def _get_loop_items(self, task, templar, task_vars): items = None if task.loop_with: if task.loop_with in self._shared_loader_obj.lookup_loader: try: loop_terms = listify_lookup_plugin_terms(terms=task.loop, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=False) mylookup = self._shared_loader_obj.lookup_loader.get(task.loop_with, loader=self._loader, templar=templar) items = mylookup.run(terms=loop_terms, variables=task_vars, wantlist=True) except AnsibleUndefinedVariable as e: display.warning('Processing %s caused an AnsibleUndefinedVariable error: %s' % (task, e)) elif task.loop: items = templar.template(task.loop) return items
def _lookup(self, name, *args, **kwargs): instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self) if instance is not None: from ansible.utils.listify import listify_lookup_plugin_terms loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: if convert_bare: variable = self._convert_bare_variable(variable) if isinstance(variable, string_types): result = variable if self._contains_vars(variable): # Check to see if the string we are trying to render is just referencing a single # var. In this case we don't want to accidentally change the type of the variable # to a string by using the jinja template renderer. We just want to pass it. only_one = self.SINGLE_VAR.match(variable) if only_one: var_name = only_one.group(1) if var_name in self._available_variables: resolved_val = self._available_variables[var_name] if isinstance(resolved_val, NON_TEMPLATED_TYPES): return resolved_val elif resolved_val is None: return C.DEFAULT_NULL_REPRESENTATION # Using a cache in order to prevent template calls with already templated variables variable_hash = sha1(text_type(variable).encode('utf-8')) options_hash = sha1((text_type(preserve_trailing_newlines) + text_type(escape_backslashes) + text_type(fail_on_undefined) + text_type(overrides)).encode('utf-8')) sha1_hash = variable_hash.hexdigest() + options_hash.hexdigest() if sha1_hash in self._cached_result: result = self._cached_result[sha1_hash] result = self._cached_result[sha1_hash] #return self._clean_data(result) return result elif isinstance(variable, (list, tuple)): return [self.template(v, preserve_trailing_newlines=preserve_trailing_newlines, fail_on_undefined=fail_on_undefined, overrides=overrides) for v in variable] elif isinstance(variable, dict): d = {} # we don't use iteritems() here to avoid problems if the underlying dict # changes sizes due to the templating, which can happen with hostvars for k in variable.keys(): if k not in static_vars: d[k] = self.template(variable[k], preserve_trailing_newlines=preserve_trailing_newlines, fail_on_undefined=fail_on_undefined, overrides=overrides) d[k] = self.template(variable[k], preserve_trailing_newlines=preserve_trailing_newlines, fail_on_undefined=fail_on_undefined, overrides=overrides) return d else: return variable raise AnsibleError("lookup plugin (%s) not found" % name) ran = instance.run(loop_terms, variables=self._available_variables, **kwargs)
def _lookup(self, name, *args, **kwargs): instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self) if instance is not None: wantlist = kwargs.pop('wantlist', False) allow_unsafe = kwargs.pop('allow_unsafe', C.DEFAULT_ALLOW_UNSAFE_LOOKUPS) from ansible.utils.listify import listify_lookup_plugin_terms loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) except (AnsibleUndefinedVariable, UndefinedError) as e: raise AnsibleUndefinedVariable(e) except Exception as e: if self._fail_on_lookup_errors: raise AnsibleError( "An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, original message: %s" % (name, type(e), e)) ran = None if ran and not allow_unsafe: from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var if wantlist: ran = wrap_var(ran) else: try: ran = UnsafeProxy(",".join(ran)) except TypeError: if isinstance(ran, list) and len(ran) == 1: ran = wrap_var(ran[0]) else: ran = wrap_var(ran) if self.cur_context: self.cur_context.unsafe = True return ran else: raise AnsibleError("lookup plugin (%s) not found" % name)
def run(self, terms, variables, **kwargs): terms[0] = listify_lookup_plugin_terms(terms[0], variables, loader=self._loader) if not isinstance(terms, list) or not len(terms) == 2: raise AnsibleError( "subelements lookup expects a list of two items, first a dict or a list, and second a string" ) if isinstance(terms[0], dict): # convert to list: if terms[0].get('skipped', False) != False: # the registered result was completely skipped return [] elementlist = [] for key in terms[0].iterkeys(): elementlist.append(terms[0][key]) else: elementlist = terms[0] subelement = terms[1] ret = [] for item0 in elementlist: if not isinstance(item0, dict): raise AnsibleError( "subelements lookup expects a dictionary, got '%s'" % item0) if item0.get('skipped', False) != False: # this particular item is to be skipped continue if not subelement in item0: raise AnsibleError( "could not find '%s' key in iterated item '%s'" % (subelement, item0)) if not isinstance(item0[subelement], list): raise AnsibleError( "the key %s should point to a list, got '%s'" % (subelement, item0[subelement])) sublist = item0.pop(subelement, []) for item1 in sublist: ret.append((item0, item1)) return ret
def run(self, terms, variables, **kwargs): basedir = self._loader.get_basedir() terms = listify_lookup_plugin_terms(terms, templar=self._templar, loader=self._loader) if isinstance(terms, basestring): terms = [terms] ret = [] for term in terms: params = term.split() key = params[0] paramvals = { 'file': 'ansible.xml', 'default': None, 'xpath': None, } # parameters specified? try: for param in params: name, value = param.split('=', 1) assert (name in paramvals) paramvals[name] = value except (ValueError, AssertionError), e: raise AnsibleError(e) path = self._loader.path_dwim_relative( basedir, 'files', paramvals['file']) # noqa: E501 var = self.read_xml(path, paramvals['default'], paramvals['xpath']) if var is not None: if type(var) is list: for v in var: ret.append(v) else: ret.append(var)
def run(self, terms, variables, **kwargs): if not HAS_DOCKERFILE: raise errors.AnsibleError('dockerfile module is missing') if len(terms) == 2: terms[1] = listify_lookup_plugin_terms(terms[1], templar=self._templar, loader=self._loader) terms[1] = map(lambda cmd: unicode(cmd.lower()), terms[1]) if not isinstance(terms, list) or not 1 <= len(terms) <= 2: raise errores.AnsibleError('dockerfile lookup expects a list of one or two items'); try: df = dockerfile.parse_string(unicode(terms[0])) except (dockerfile.GoIOError, dockerfile.GoParseError) as e: if isinstance(e, dockerfile.GoIOError): raise_from(errors.AnsibleError("Dockerfile couldn't be opened"), e) else: raise_from( errors.AnsibleError("Dockerfile couldn't be parsed"), e) return [command._asdict() for command in df if len(terms) == 1 or command.cmd in terms[1]]
def _lookup(self, name, *args, **kwargs): instance = self._lookup_loader.get(name.lower(), loader=self._loader, templar=self) if instance is not None: wantlist = kwargs.pop('wantlist', False) allow_unsafe = kwargs.pop('allow_unsafe', C.DEFAULT_ALLOW_UNSAFE_LOOKUPS) from ansible.utils.listify import listify_lookup_plugin_terms loop_terms = listify_lookup_plugin_terms(terms=args, templar=self, loader=self._loader, fail_on_undefined=True, convert_bare=False) # safely catch run failures per #5059 try: ran = instance.run(loop_terms, variables=self._available_variables, **kwargs) except (AnsibleUndefinedVariable, UndefinedError) as e: raise AnsibleUndefinedVariable(e) except Exception as e: if self._fail_on_lookup_errors: raise AnsibleError("An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, " "original message: %s" % (name, type(e), e)) ran = None if ran and not allow_unsafe: if wantlist: ran = wrap_var(ran) else: try: ran = UnsafeProxy(",".join(ran)) except TypeError: if isinstance(ran, list) and len(ran) == 1: ran = wrap_var(ran[0]) else: ran = wrap_var(ran) if self.cur_context: self.cur_context.unsafe = True return ran else: raise AnsibleError("lookup plugin (%s) not found" % name)
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # create a copy of the job vars here so that we can modify # them temporarily without changing them too early for other # parts of the code that might still need a pristine version vars_copy = self._job_vars.copy() # now we update them with the play context vars self._play_context.update_vars(vars_copy) templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=vars_copy) items = None if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: #TODO: remove convert_bare true and deprecate this in with_ try: loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=True) except AnsibleUndefinedVariable as e: if 'has no attribute' in str(e): loop_terms = [] self._display.deprecated("Skipping task due to undefined attribute, in the future this will be a fatal error.") else: raise items = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) if items: from ansible.vars.unsafe_proxy import UnsafeProxy for idx, item in enumerate(items): if item is not None and not isinstance(item, UnsafeProxy): items[idx] = UnsafeProxy(item) return items
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # create a copy of the job vars here so that we can modify # them temporarily without changing them too early for other # parts of the code that might still need a pristine version vars_copy = self._job_vars.copy() # now we update them with the play context vars self._play_context.update_vars(vars_copy) templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=vars_copy) items = None if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True) items = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) return items
def _get_delegated_vars(self, loader, play, task, existing_variables): # we unfortunately need to template the delegate_to field here, # as we're fetching vars before post_validate has been called on # the task that has been passed in vars_copy = existing_variables.copy() templar = Templar(loader=loader, variables=vars_copy) items = [] if task.loop is not None: if task.loop in lookup_loader: #TODO: remove convert_bare true and deprecate this in with_ try: loop_terms = listify_lookup_plugin_terms( terms=task.loop_args, templar=templar, loader=loader, fail_on_undefined=True, convert_bare=True) except AnsibleUndefinedVariable as e: if 'has no attribute' in str(e): loop_terms = [] self._display.deprecated( "Skipping task due to undefined attribute, in the future this will be a fatal error." ) else: raise items = lookup_loader.get(task.loop, loader=loader, templar=templar).run( terms=loop_terms, variables=vars_copy) else: raise AnsibleError( "Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % task.loop) else: items = [None] delegated_host_vars = dict() for item in items: # update the variables with the item value for templating, in case we need it if item is not None: vars_copy['item'] = item templar.set_available_variables(vars_copy) delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) if delegated_host_name in delegated_host_vars: # no need to repeat ourselves, as the delegate_to value # does not appear to be tied to the loop item variable continue # a dictionary of variables to use if we have to create a new host below new_delegated_host_vars = dict( ansible_host=delegated_host_name, ansible_user=C.DEFAULT_REMOTE_USER, ansible_connection=C.DEFAULT_TRANSPORT, ) # now try to find the delegated-to host in inventory, or failing that, # create a new host on the fly so we can fetch variables for it delegated_host = None if self._inventory is not None: delegated_host = self._inventory.get_host(delegated_host_name) # try looking it up based on the address field, and finally # fall back to creating a host on the fly to use for the var lookup if delegated_host is None: for h in self._inventory.get_hosts( ignore_limits_and_restrictions=True): # check if the address matches, or if both the delegated_to host # and the current host are in the list of localhost aliases if h.address == delegated_host_name or h.name in C.LOCALHOST and delegated_host_name in C.LOCALHOST: delegated_host = h break else: delegated_host = Host(name=delegated_host_name) delegated_host.vars.update(new_delegated_host_vars) else: delegated_host = Host(name=delegated_host_name) delegated_host.vars.update(new_delegated_host_vars) # now we go fetch the vars for the delegated-to host and save them in our # master dictionary of variables to be used later in the TaskExecutor/PlayContext delegated_host_vars[delegated_host_name] = self.get_vars( loader=loader, play=play, host=delegated_host, task=task, include_delegate_to=False, include_hostvars=False, ) return delegated_host_vars
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # create a copy of the job vars here so that we can modify # them temporarily without changing them too early for other # parts of the code that might still need a pristine version #vars_copy = self._job_vars.copy() vars_copy = self._job_vars # now we update them with the play context vars self._play_context.update_vars(vars_copy) templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=vars_copy) items = None if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: #TODO: remove convert_bare true and deprecate this in with_ if self._task.loop == 'first_found': # first_found loops are special. If the item is undefined # then we want to fall through to the next value rather # than failing. loop_terms = listify_lookup_plugin_terms( terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=False, convert_bare=True) loop_terms = [ t for t in loop_terms if not templar._contains_vars(t) ] else: try: loop_terms = listify_lookup_plugin_terms( terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=True) except AnsibleUndefinedVariable as e: if 'has no attribute' in str(e): loop_terms = [] display.deprecated( "Skipping task due to undefined attribute, in the future this will be a fatal error." ) else: raise items = self._shared_loader_obj.lookup_loader.get( self._task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy) else: raise AnsibleError( "Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) if items: from ansible.vars.unsafe_proxy import UnsafeProxy for idx, item in enumerate(items): if item is not None and not isinstance(item, UnsafeProxy): items[idx] = UnsafeProxy(item) return items
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # save the play context variables to a temporary dictionary, # so that we can modify the job vars without doing a full copy # and later restore them to avoid modifying things too early play_context_vars = dict() self._play_context.update_vars(play_context_vars) old_vars = dict() for k in play_context_vars: if k in self._job_vars: old_vars[k] = self._job_vars[k] self._job_vars[k] = play_context_vars[k] # get search path for this task to pass to lookup plugins self._job_vars['ansible_search_path'] = self._task.get_search_path() templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars) items = None if self._task.loop_with: if self._task.loop_with in self._shared_loader_obj.lookup_loader: fail = True if self._task.loop_with == 'first_found': # first_found loops are special. If the item is undefined then we want to fall through to the next value rather than failing. fail = False loop_terms = listify_lookup_plugin_terms(terms=self._task.loop, templar=templar, loader=self._loader, fail_on_undefined=fail, convert_bare=False) if not fail: loop_terms = [t for t in loop_terms if not templar._contains_vars(t)] # get lookup mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop_with, loader=self._loader, templar=templar) # give lookup task 'context' for subdir (mostly needed for first_found) for subdir in ['template', 'var', 'file']: # TODO: move this to constants? if subdir in self._task.action: break setattr(mylookup, '_subdir', subdir + 's') # run lookup items = mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop_with) elif self._task.loop: items = templar.template(self._task.loop) if not isinstance(items, list): raise AnsibleError( "Invalid data passed to 'loop', it requires a list, got this instead: %s." " Hint: If you passed a list/dict of just one element," " try adding wantlist=True to your lookup invocation or use q/query instead of lookup." % items ) # now we restore any old job variables that may have been modified, # and delete them if they were in the play context vars but not in # the old variables dictionary for k in play_context_vars: if k in old_vars: self._job_vars[k] = old_vars[k] else: del self._job_vars[k] if items: for idx, item in enumerate(items): if item is not None and not isinstance(item, UnsafeProxy): items[idx] = UnsafeProxy(item) # ensure basedir is always in (dwim already searches here but we need to display it) if self._loader.get_basedir() not in self._job_vars['ansible_search_path']: self._job_vars['ansible_search_path'].append(self._loader.get_basedir()) return items
def _get_delegated_vars(self, loader, play, task, existing_variables): # we unfortunately need to template the delegate_to field here, # as we're fetching vars before post_validate has been called on # the task that has been passed in vars_copy = existing_variables.copy() templar = Templar(loader=loader, variables=vars_copy) items = [] if task.loop is not None: if task.loop in lookup_loader: #TODO: remove convert_bare true and deprecate this in with_ try: loop_terms = listify_lookup_plugin_terms(terms=task.loop_args, templar=templar, loader=loader, fail_on_undefined=True, convert_bare=True) except AnsibleUndefinedVariable as e: if 'has no attribute' in str(e): loop_terms = [] display.deprecated("Skipping task due to undefined attribute, in the future this will be a fatal error.") else: raise items = lookup_loader.get(task.loop, loader=loader, templar=templar).run(terms=loop_terms, variables=vars_copy) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % task.loop) else: items = [None] delegated_host_vars = dict() for item in items: # update the variables with the item value for templating, in case we need it if item is not None: vars_copy['item'] = item templar.set_available_variables(vars_copy) delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) if delegated_host_name in delegated_host_vars: # no need to repeat ourselves, as the delegate_to value # does not appear to be tied to the loop item variable continue # a dictionary of variables to use if we have to create a new host below # we set the default port based on the default transport here, to make sure # we use the proper default for windows new_port = C.DEFAULT_REMOTE_PORT if C.DEFAULT_TRANSPORT == 'winrm': new_port = 5986 new_delegated_host_vars = dict( ansible_host=delegated_host_name, ansible_port=new_port, ansible_user=C.DEFAULT_REMOTE_USER, ansible_connection=C.DEFAULT_TRANSPORT, ) # now try to find the delegated-to host in inventory, or failing that, # create a new host on the fly so we can fetch variables for it delegated_host = None if self._inventory is not None: delegated_host = self._inventory.get_host(delegated_host_name) # try looking it up based on the address field, and finally # fall back to creating a host on the fly to use for the var lookup if delegated_host is None: for h in self._inventory.get_hosts(ignore_limits_and_restrictions=True): # check if the address matches, or if both the delegated_to host # and the current host are in the list of localhost aliases if h.address == delegated_host_name or h.name in C.LOCALHOST and delegated_host_name in C.LOCALHOST: delegated_host = h break else: delegated_host = Host(name=delegated_host_name) delegated_host.vars.update(new_delegated_host_vars) else: delegated_host = Host(name=delegated_host_name) delegated_host.vars.update(new_delegated_host_vars) # now we go fetch the vars for the delegated-to host and save them in our # master dictionary of variables to be used later in the TaskExecutor/PlayContext delegated_host_vars[delegated_host_name] = self.get_vars( loader=loader, play=play, host=delegated_host, task=task, include_delegate_to=False, include_hostvars=False, ) return delegated_host_vars
def _lookup_variables(self, terms): results = [] for x in terms: intermediate = listify_lookup_plugin_terms(x, templar=self._templar, loader=self._loader) results.append(intermediate) return results
def _get_delegated_vars(self, play, task, existing_variables): # we unfortunately need to template the delegate_to field here, # as we're fetching vars before post_validate has been called on # the task that has been passed in vars_copy = existing_variables.copy() templar = Templar(loader=self._loader, variables=vars_copy) items = [] if task.loop is not None: if task.loop in lookup_loader: try: loop_terms = listify_lookup_plugin_terms(terms=task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=False) items = lookup_loader.get(task.loop, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy) except AnsibleUndefinedVariable: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail items = [None] else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % task.loop) else: items = [None] delegated_host_vars = dict() for item in items: # update the variables with the item value for templating, in case we need it if item is not None: vars_copy['item'] = item templar.set_available_variables(vars_copy) delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) if delegated_host_name is None: raise AnsibleError(message="Undefined delegate_to host for task:", obj=task._ds) if delegated_host_name in delegated_host_vars: # no need to repeat ourselves, as the delegate_to value # does not appear to be tied to the loop item variable continue # a dictionary of variables to use if we have to create a new host below # we set the default port based on the default transport here, to make sure # we use the proper default for windows new_port = C.DEFAULT_REMOTE_PORT if C.DEFAULT_TRANSPORT == 'winrm': new_port = 5986 new_delegated_host_vars = dict( ansible_delegated_host=delegated_host_name, ansible_host=delegated_host_name, # not redundant as other sources can change ansible_host ansible_port=new_port, ansible_user=C.DEFAULT_REMOTE_USER, ansible_connection=C.DEFAULT_TRANSPORT, ) # now try to find the delegated-to host in inventory, or failing that, # create a new host on the fly so we can fetch variables for it delegated_host = None if self._inventory is not None: delegated_host = self._inventory.get_host(delegated_host_name) # try looking it up based on the address field, and finally # fall back to creating a host on the fly to use for the var lookup if delegated_host is None: if delegated_host_name in C.LOCALHOST: delegated_host = self._inventory.localhost else: for h in self._inventory.get_hosts(ignore_limits=True, ignore_restrictions=True): # check if the address matches, or if both the delegated_to host # and the current host are in the list of localhost aliases if h.address == delegated_host_name: delegated_host = h break else: delegated_host = Host(name=delegated_host_name) delegated_host.vars = combine_vars(delegated_host.vars, new_delegated_host_vars) else: delegated_host = Host(name=delegated_host_name) delegated_host.vars = combine_vars(delegated_host.vars, new_delegated_host_vars) # now we go fetch the vars for the delegated-to host and save them in our # master dictionary of variables to be used later in the TaskExecutor/PlayContext delegated_host_vars[delegated_host_name] = self.get_vars( play=play, host=delegated_host, task=task, include_delegate_to=False, include_hostvars=False, ) return delegated_host_vars
def run(self, terms, variables, **kwargs): def _raise_terms_error(msg=""): raise AnsibleError( "subelements lookup expects a list of two or three items, " + msg) terms[0] = listify_lookup_plugin_terms(terms[0], templar=self._templar, loader=self._loader) # check lookup terms - check number of terms if not isinstance(terms, list) or not 2 <= len(terms) <= 3: _raise_terms_error() # first term should be a list (or dict), second a string holding the subkey if not isinstance(terms[0], (list, dict)) or not isinstance(terms[1], string_types): _raise_terms_error("first a dict or a list, second a string pointing to the subkey") subelements = terms[1].split(".") if isinstance(terms[0], dict): # convert to list: if terms[0].get('skipped', False) is not False: # the registered result was completely skipped return [] elementlist = [] for key in terms[0]: elementlist.append(terms[0][key]) else: elementlist = terms[0] # check for optional flags in third term flags = {} if len(terms) == 3: flags = terms[2] if not isinstance(flags, dict) and not all([isinstance(key, string_types) and key in FLAGS for key in flags]): _raise_terms_error("the optional third item must be a dict with flags %s" % FLAGS) # build_items ret = [] for item0 in elementlist: if not isinstance(item0, dict): raise AnsibleError("subelements lookup expects a dictionary, got '%s'" % item0) if item0.get('skipped', False) is not False: # this particular item is to be skipped continue skip_missing = boolean(flags.get('skip_missing', False)) subvalue = item0 lastsubkey = False sublist = [] for subkey in subelements: if subkey == subelements[-1]: lastsubkey = True if not subkey in subvalue: if skip_missing: continue else: raise AnsibleError("could not find '%s' key in iterated item '%s'" % (subkey, subvalue)) if not lastsubkey: if not isinstance(subvalue[subkey], dict): if skip_missing: continue else: raise AnsibleError("the key %s should point to a dictionary, got '%s'" % (subkey, subvalue[subkey])) else: subvalue = subvalue[subkey] else: # lastsubkey if not isinstance(subvalue[subkey], list): raise AnsibleError("the key %s should point to a list, got '%s'" % (subkey, subvalue[subkey])) else: sublist = subvalue.pop(subkey, []) for item1 in sublist: ret.append((item0, item1)) return ret
def _get_loop_items(self): ''' Loads a lookup plugin to handle the with_* portion of a task (if specified), and returns the items result. ''' # save the play context variables to a temporary dictionary, # so that we can modify the job vars without doing a full copy # and later restore them to avoid modifying things too early play_context_vars = dict() self._play_context.update_vars(play_context_vars) old_vars = dict() for k in play_context_vars: if k in self._job_vars: old_vars[k] = self._job_vars[k] self._job_vars[k] = play_context_vars[k] # get search path for this task to pass to lookup plugins self._job_vars['ansible_search_path'] = self._task.get_search_path() templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars) items = None if self._task.loop: if self._task.loop in self._shared_loader_obj.lookup_loader: if self._task.loop == 'first_found': # first_found loops are special. If the item is undefined then we want to fall through to the next value rather than failing. loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=False, convert_bare=False) loop_terms = [t for t in loop_terms if not templar._contains_vars(t)] else: loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=False) # get lookup mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar) # give lookup task 'context' for subdir (mostly needed for first_found) for subdir in ['template', 'var', 'file']: # TODO: move this to constants? if subdir in self._task.action: break setattr(mylookup,'_subdir', subdir + 's') # run lookup items = mylookup.run(terms=loop_terms, variables=self._job_vars, wantlist=True) else: raise AnsibleError("Unexpected failure in finding the lookup named '%s' in the available lookup plugins" % self._task.loop) # now we restore any old job variables that may have been modified, # and delete them if they were in the play context vars but not in # the old variables dictionary for k in play_context_vars: if k in old_vars: self._job_vars[k] = old_vars[k] else: del self._job_vars[k] if items: from ansible.vars.unsafe_proxy import UnsafeProxy for idx, item in enumerate(items): if item is not None and not isinstance(item, UnsafeProxy): items[idx] = UnsafeProxy(item) # ensure basedir is always in (dwim already searches here but we need to display it) if self._loader.get_basedir() not in self._job_vars['ansible_search_path']: self._job_vars['ansible_search_path'].append(self._loader.get_basedir()) return items
def _get_delegated_vars(self, play, task, existing_variables): if not hasattr(task, 'loop'): # This "task" is not a Task, so we need to skip it return {}, None # we unfortunately need to template the delegate_to field here, # as we're fetching vars before post_validate has been called on # the task that has been passed in vars_copy = existing_variables.copy() templar = Templar(loader=self._loader, variables=vars_copy) items = [] has_loop = True if task.loop_with is not None: if task.loop_with in lookup_loader: try: loop_terms = listify_lookup_plugin_terms( terms=task.loop, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=False) items = wrap_var( lookup_loader.get(task.loop_with, loader=self._loader, templar=templar).run( terms=loop_terms, variables=vars_copy)) except AnsibleTemplateError: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail items = [None] else: raise AnsibleError( "Failed to find the lookup named '%s' in the available lookup plugins" % task.loop_with) elif task.loop is not None: try: items = templar.template(task.loop) except AnsibleTemplateError: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail items = [None] else: has_loop = False items = [None] # since host can change per loop, we keep dict per host name resolved delegated_host_vars = dict() item_var = getattr(task.loop_control, 'loop_var', 'item') cache_items = False for item in items: # update the variables with the item value for templating, in case we need it if item is not None: vars_copy[item_var] = item templar.available_variables = vars_copy delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) if delegated_host_name != task.delegate_to: cache_items = True if delegated_host_name is None: raise AnsibleError( message="Undefined delegate_to host for task:", obj=task._ds) if not isinstance(delegated_host_name, string_types): raise AnsibleError( message= "the field 'delegate_to' has an invalid type (%s), and could not be" " converted to a string type." % type(delegated_host_name), obj=task._ds) if delegated_host_name in delegated_host_vars: # no need to repeat ourselves, as the delegate_to value # does not appear to be tied to the loop item variable continue # now try to find the delegated-to host in inventory, or failing that, # create a new host on the fly so we can fetch variables for it delegated_host = None if self._inventory is not None: delegated_host = self._inventory.get_host(delegated_host_name) # try looking it up based on the address field, and finally # fall back to creating a host on the fly to use for the var lookup if delegated_host is None: for h in self._inventory.get_hosts( ignore_limits=True, ignore_restrictions=True): # check if the address matches, or if both the delegated_to host # and the current host are in the list of localhost aliases if h.address == delegated_host_name: delegated_host = h break else: delegated_host = Host(name=delegated_host_name) else: delegated_host = Host(name=delegated_host_name) # now we go fetch the vars for the delegated-to host and save them in our # master dictionary of variables to be used later in the TaskExecutor/PlayContext delegated_host_vars[delegated_host_name] = self.get_vars( play=play, host=delegated_host, task=task, include_delegate_to=False, include_hostvars=False, ) _ansible_loop_cache = None if has_loop and cache_items: # delegate_to templating produced a change, so we will cache the templated items # in a special private hostvar # this ensures that delegate_to+loop doesn't produce different results than TaskExecutor # which may reprocess the loop _ansible_loop_cache = items return delegated_host_vars, _ansible_loop_cache
def _get_delegated_vars(self, play, task, existing_variables): # This method has a lot of code copied from ``TaskExecutor._get_loop_items`` # if this is failing, and ``TaskExecutor._get_loop_items`` is not # then more will have to be copied here. # TODO: dedupe code here and with ``TaskExecutor._get_loop_items`` # this may be possible once we move pre-processing pre fork if not hasattr(task, 'loop'): # This "task" is not a Task, so we need to skip it return {}, None # we unfortunately need to template the delegate_to field here, # as we're fetching vars before post_validate has been called on # the task that has been passed in vars_copy = existing_variables.copy() # get search path for this task to pass to lookup plugins vars_copy['ansible_search_path'] = task.get_search_path() # ensure basedir is always in (dwim already searches here but we need to display it) if self._loader.get_basedir() not in vars_copy['ansible_search_path']: vars_copy['ansible_search_path'].append(self._loader.get_basedir()) templar = Templar(loader=self._loader, variables=vars_copy) items = [] has_loop = True if task.loop_with is not None: if task.loop_with in lookup_loader: fail = True if task.loop_with == 'first_found': # first_found loops are special. If the item is undefined then we want to fall through to the next fail = False try: loop_terms = listify_lookup_plugin_terms( terms=task.loop, templar=templar, fail_on_undefined=fail, convert_bare=False) if not fail: loop_terms = [ t for t in loop_terms if not templar.is_template(t) ] mylookup = lookup_loader.get(task.loop_with, loader=self._loader, templar=templar) # give lookup task 'context' for subdir (mostly needed for first_found) for subdir in ['template', 'var', 'file']: # TODO: move this to constants? if subdir in task.action: break setattr(mylookup, '_subdir', subdir + 's') items = wrap_var( mylookup.run(terms=loop_terms, variables=vars_copy)) except AnsibleTemplateError: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail items = [None] else: raise AnsibleError( "Failed to find the lookup named '%s' in the available lookup plugins" % task.loop_with) elif task.loop is not None: try: items = templar.template(task.loop) except AnsibleTemplateError: # This task will be skipped later due to this, so we just setup # a dummy array for the later code so it doesn't fail items = [None] else: has_loop = False items = [None] # since host can change per loop, we keep dict per host name resolved delegated_host_vars = dict() item_var = getattr(task.loop_control, 'loop_var', 'item') cache_items = False for item in items: # update the variables with the item value for templating, in case we need it if item is not None: vars_copy[item_var] = item templar.available_variables = vars_copy delegated_host_name = templar.template(task.delegate_to, fail_on_undefined=False) if delegated_host_name != task.delegate_to: cache_items = True if delegated_host_name is None: raise AnsibleError( message="Undefined delegate_to host for task:", obj=task._ds) if not isinstance(delegated_host_name, string_types): raise AnsibleError( message= "the field 'delegate_to' has an invalid type (%s), and could not be" " converted to a string type." % type(delegated_host_name), obj=task._ds) if delegated_host_name in delegated_host_vars: # no need to repeat ourselves, as the delegate_to value # does not appear to be tied to the loop item variable continue # now try to find the delegated-to host in inventory, or failing that, # create a new host on the fly so we can fetch variables for it delegated_host = None if self._inventory is not None: delegated_host = self._inventory.get_host(delegated_host_name) # try looking it up based on the address field, and finally # fall back to creating a host on the fly to use for the var lookup if delegated_host is None: for h in self._inventory.get_hosts( ignore_limits=True, ignore_restrictions=True): # check if the address matches, or if both the delegated_to host # and the current host are in the list of localhost aliases if h.address == delegated_host_name: delegated_host = h break else: delegated_host = Host(name=delegated_host_name) else: delegated_host = Host(name=delegated_host_name) # now we go fetch the vars for the delegated-to host and save them in our # master dictionary of variables to be used later in the TaskExecutor/PlayContext delegated_host_vars[delegated_host_name] = self.get_vars( play=play, host=delegated_host, task=task, include_delegate_to=False, include_hostvars=True, ) delegated_host_vars[delegated_host_name][ 'inventory_hostname'] = vars_copy.get('inventory_hostname') _ansible_loop_cache = None if has_loop and cache_items: # delegate_to templating produced a change, so we will cache the templated items # in a special private hostvar # this ensures that delegate_to+loop doesn't produce different results than TaskExecutor # which may reprocess the loop _ansible_loop_cache = items return delegated_host_vars, _ansible_loop_cache
def run(self, terms, variables, **kwargs): def _raise_terms_error(msg=""): raise AnsibleError( "subelements lookup expects a list of two or three items, " + msg) terms[0] = listify_lookup_plugin_terms(terms[0], templar=self._templar, loader=self._loader) # check lookup terms - check number of terms if not isinstance(terms, list) or not 2 <= len(terms) <= 3: _raise_terms_error() # first term should be a list (or dict), second a string holding the subkey if not isinstance(terms[0], (list, dict)) or not isinstance( terms[1], string_types): _raise_terms_error( "first a dict or a list, second a string pointing to the subkey" ) subelements = terms[1].split(".") if isinstance(terms[0], dict): # convert to list: if terms[0].get('skipped', False) is not False: # the registered result was completely skipped return [] elementlist = [] for key in terms[0]: elementlist.append(terms[0][key]) else: elementlist = terms[0] # check for optional flags in third term flags = {} if len(terms) == 3: flags = terms[2] if not isinstance(flags, dict) and not all( [isinstance(key, string_types) and key in FLAGS for key in flags]): _raise_terms_error( "the optional third item must be a dict with flags %s" % FLAGS) # build_items ret = [] for item0 in elementlist: if not isinstance(item0, dict): raise AnsibleError( "subelements lookup expects a dictionary, got '%s'" % item0) if item0.get('skipped', False) is not False: # this particular item is to be skipped continue skip_missing = boolean(flags.get('skip_missing', False), strict=False) subvalue = item0 lastsubkey = False sublist = [] for subkey in subelements: if subkey == subelements[-1]: lastsubkey = True if subkey not in subvalue: if skip_missing: continue else: raise AnsibleError( "could not find '%s' key in iterated item '%s'" % (subkey, subvalue)) if not lastsubkey: if not isinstance(subvalue[subkey], dict): if skip_missing: continue else: raise AnsibleError( "the key %s should point to a dictionary, got '%s'" % (subkey, subvalue[subkey])) else: subvalue = subvalue[subkey] else: # lastsubkey if not isinstance(subvalue[subkey], list): raise AnsibleError( "the key %s should point to a list, got '%s'" % (subkey, subvalue[subkey])) else: sublist = subvalue.pop(subkey, []) for item1 in sublist: ret.append((item0, item1)) return ret