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 _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 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: 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 _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: fail = True 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. fail = False loop_terms = listify_lookup_plugin_terms( terms=self._task.loop_args, 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, 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: 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 test_UnsafeProxy(): assert isinstance(UnsafeProxy({}), dict) assert not isinstance(UnsafeProxy({}), AnsibleUnsafe) assert isinstance(UnsafeProxy('foo'), AnsibleUnsafeText)