def run(self, terms, variables, **kwargs): convert_data_p = kwargs.get('convert_data', True) lookup_template_vars = kwargs.get('template_vars', {}) jinja2_native = kwargs.get('jinja2_native', False) ret = [] variable_start_string = kwargs.get('variable_start_string', None) variable_end_string = kwargs.get('variable_end_string', None) if USE_JINJA2_NATIVE and not jinja2_native: templar = self._templar.copy_with_new_env(environment_class=AnsibleEnvironment) else: templar = self._templar for term in terms: display.debug("File lookup term: %s" % term) lookupfile = self.find_file_in_search_path(variables, 'templates', term) display.vvvv("File lookup using %s as file" % lookupfile) if lookupfile: b_template_data, show_data = self._loader._get_file_contents(lookupfile) template_data = to_text(b_template_data, errors='surrogate_or_strict') # set jinja2 internal search path for includes searchpath = variables.get('ansible_search_path', []) if searchpath: # our search paths aren't actually the proper ones for jinja includes. # We want to search into the 'templates' subdir of each search path in # addition to our original search paths. newsearchpath = [] for p in searchpath: newsearchpath.append(os.path.join(p, 'templates')) newsearchpath.append(p) searchpath = newsearchpath searchpath.insert(0, os.path.dirname(lookupfile)) # The template will have access to all existing variables, # plus some added by ansible (e.g., template_{path,mtime}), # plus anything passed to the lookup with the template_vars= # argument. vars = deepcopy(variables) vars.update(generate_ansible_template_vars(term, lookupfile)) vars.update(lookup_template_vars) with templar.set_temporary_context(variable_start_string=variable_start_string, variable_end_string=variable_end_string, available_variables=vars, searchpath=searchpath): res = templar.template(template_data, preserve_trailing_newlines=True, convert_data=convert_data_p, escape_backslashes=False) if USE_JINJA2_NATIVE and not jinja2_native: # jinja2_native is true globally but off for the lookup, we need this text # not to be processed by literal_eval anywhere in Ansible res = NativeJinjaText(res) ret.append(res) else: raise AnsibleError("the template file %s could not be found for the lookup" % term) return ret
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 wrapper(*args, **kwargs): ret = func(*args, **kwargs) return NativeJinjaText(ret)
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, 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 AnsibleOptionsError as e: # invalid options given to lookup, just reraise raise e except AnsibleLookupError as e: # lookup handled error but still decided to bail msg = 'Lookup failed but the error is being ignored: %s' % to_native( e) if errors == 'warn': display.warning(msg) elif errors == 'ignore': display.display(msg, log_only=True) else: raise e return [] if wantlist else None except Exception as e: # errors not handled by lookup 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: display.vvv('exception during Jinja2 execution: {0}'.format( format_exc())) raise AnsibleError(to_native(msg), orig_exc=e) return [] if wantlist else None if not is_sequence(ran): display.deprecated( f'The lookup plugin \'{name}\' was expected to return a list, got \'{type(ran)}\' instead. ' f'The lookup plugin \'{name}\' needs to be changed to return a list. ' 'This will be an error in Ansible 2.18', version='2.18') if ran and allow_unsafe is False: if self.cur_context: self.cur_context.unsafe = True if wantlist: return wrap_var(ran) try: if 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) except KeyError: # Lookup Plugin returned a dict. Return comma-separated string of keys # for backwards compat. # FIXME this can be removed when support for non-list return types is removed. # See https://github.com/ansible/ansible/pull/77789 ran = wrap_var(",".join(ran)) return ran