Templar: encapsulate _available_variables (#55435)
Ensure variables are reset between iterations
This commit is contained in:
parent
bd061fd632
commit
34e9d6781b
14 changed files with 47 additions and 30 deletions
|
@ -345,7 +345,7 @@ class TaskExecutor:
|
||||||
task_vars['ansible_loop']['previtem'] = items[item_index - 1]
|
task_vars['ansible_loop']['previtem'] = items[item_index - 1]
|
||||||
|
|
||||||
# Update template vars to reflect current loop iteration
|
# Update template vars to reflect current loop iteration
|
||||||
templar.set_available_variables(task_vars)
|
templar.available_variables = task_vars
|
||||||
|
|
||||||
# pause between loop iterations
|
# pause between loop iterations
|
||||||
if loop_pause and ran_once:
|
if loop_pause and ran_once:
|
||||||
|
|
|
@ -342,7 +342,7 @@ class FieldAttributeBase(with_metaclass(BaseMeta, object)):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# save the omit value for later checking
|
# save the omit value for later checking
|
||||||
omit_value = templar._available_variables.get('omit')
|
omit_value = templar.available_variables.get('omit')
|
||||||
|
|
||||||
for (name, attribute) in iteritems(self._valid_attrs):
|
for (name, attribute) in iteritems(self._valid_attrs):
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ class Conditional:
|
||||||
'templating delimiters such as {{ }} or {%% %%}. '
|
'templating delimiters such as {{ }} or {%% %%}. '
|
||||||
'Found: %s' % conditional)
|
'Found: %s' % conditional)
|
||||||
# make sure the templar is using the variables specified with this method
|
# make sure the templar is using the variables specified with this method
|
||||||
templar.set_available_variables(variables=all_vars)
|
templar.available_variables = all_vars
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# if the conditional is "unsafe", disable lookups
|
# if the conditional is "unsafe", disable lookups
|
||||||
|
|
|
@ -144,10 +144,10 @@ class ActionModule(ActionBase):
|
||||||
temp_vars = task_vars.copy()
|
temp_vars = task_vars.copy()
|
||||||
temp_vars.update(generate_ansible_template_vars(source, dest))
|
temp_vars.update(generate_ansible_template_vars(source, dest))
|
||||||
|
|
||||||
old_vars = self._templar._available_variables
|
old_vars = self._templar.available_variables
|
||||||
self._templar.set_available_variables(temp_vars)
|
self._templar.available_variables = temp_vars
|
||||||
resultant = self._templar.do_template(template_data, preserve_trailing_newlines=True, escape_backslashes=False)
|
resultant = self._templar.do_template(template_data, preserve_trailing_newlines=True, escape_backslashes=False)
|
||||||
self._templar.set_available_variables(old_vars)
|
self._templar.available_variables = old_vars
|
||||||
except AnsibleAction:
|
except AnsibleAction:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -349,7 +349,7 @@ class Constructable(object):
|
||||||
def _compose(self, template, variables):
|
def _compose(self, template, variables):
|
||||||
''' helper method for plugins to compose variables for Ansible based on jinja2 expression and inventory vars'''
|
''' helper method for plugins to compose variables for Ansible based on jinja2 expression and inventory vars'''
|
||||||
t = self.templar
|
t = self.templar
|
||||||
t.set_available_variables(variables)
|
t.available_variables = variables
|
||||||
return t.template('%s%s%s' % (t.environment.variable_start_string, template, t.environment.variable_end_string), disable_lookups=True)
|
return t.template('%s%s%s' % (t.environment.variable_start_string, template, t.environment.variable_end_string), disable_lookups=True)
|
||||||
|
|
||||||
def _set_composite_vars(self, compose, variables, host, strict=False):
|
def _set_composite_vars(self, compose, variables, host, strict=False):
|
||||||
|
@ -369,7 +369,7 @@ class Constructable(object):
|
||||||
# process each 'group entry'
|
# process each 'group entry'
|
||||||
if groups and isinstance(groups, dict):
|
if groups and isinstance(groups, dict):
|
||||||
variables = combine_vars(variables, self.inventory.get_host(host).get_vars())
|
variables = combine_vars(variables, self.inventory.get_host(host).get_vars())
|
||||||
self.templar.set_available_variables(variables)
|
self.templar.available_variables = variables
|
||||||
for group_name in groups:
|
for group_name in groups:
|
||||||
conditional = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % groups[group_name]
|
conditional = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % groups[group_name]
|
||||||
group_name = self._sanitize_group_name(group_name)
|
group_name = self._sanitize_group_name(group_name)
|
||||||
|
|
|
@ -348,7 +348,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||||
|
|
||||||
# FUTURE: fix underlying inventory stuff to allow us to quickly access known groupvars from reconciled host
|
# FUTURE: fix underlying inventory stuff to allow us to quickly access known groupvars from reconciled host
|
||||||
def _filter_host(self, inventory_hostname, hostvars):
|
def _filter_host(self, inventory_hostname, hostvars):
|
||||||
self.templar.set_available_variables(hostvars)
|
self.templar.available_variables = hostvars
|
||||||
|
|
||||||
for condition in self._filters:
|
for condition in self._filters:
|
||||||
# FUTURE: should warn/fail if conditional doesn't return True or False
|
# FUTURE: should warn/fail if conditional doesn't return True or False
|
||||||
|
|
|
@ -101,9 +101,8 @@ class InventoryModule(BaseInventoryPlugin):
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
def template(self, pattern, variables):
|
def template(self, pattern, variables):
|
||||||
t = self.templar
|
self.templar.available_variables = variables
|
||||||
t.set_available_variables(variables)
|
return self.templar.do_template(pattern)
|
||||||
return t.do_template(pattern)
|
|
||||||
|
|
||||||
def add_parents(self, inventory, child, parents, template_vars):
|
def add_parents(self, inventory, child, parents, template_vars):
|
||||||
for parent in parents:
|
for parent in parents:
|
||||||
|
|
|
@ -68,7 +68,7 @@ class LookupModule(LookupBase):
|
||||||
variable_start_string = kwargs.get('variable_start_string', None)
|
variable_start_string = kwargs.get('variable_start_string', None)
|
||||||
variable_end_string = kwargs.get('variable_end_string', None)
|
variable_end_string = kwargs.get('variable_end_string', None)
|
||||||
|
|
||||||
old_vars = self._templar._available_variables
|
old_vars = self._templar.available_variables
|
||||||
|
|
||||||
for term in terms:
|
for term in terms:
|
||||||
display.debug("File lookup term: %s" % term)
|
display.debug("File lookup term: %s" % term)
|
||||||
|
@ -105,7 +105,7 @@ class LookupModule(LookupBase):
|
||||||
vars = deepcopy(variables)
|
vars = deepcopy(variables)
|
||||||
vars.update(generate_ansible_template_vars(lookupfile))
|
vars.update(generate_ansible_template_vars(lookupfile))
|
||||||
vars.update(lookup_template_vars)
|
vars.update(lookup_template_vars)
|
||||||
self._templar.set_available_variables(vars)
|
self._templar.available_variables = vars
|
||||||
|
|
||||||
# do the templating
|
# do the templating
|
||||||
res = self._templar.template(template_data, preserve_trailing_newlines=True,
|
res = self._templar.template(template_data, preserve_trailing_newlines=True,
|
||||||
|
@ -116,6 +116,6 @@ class LookupModule(LookupBase):
|
||||||
raise AnsibleError("the template file %s could not be found for the lookup" % term)
|
raise AnsibleError("the template file %s could not be found for the lookup" % term)
|
||||||
|
|
||||||
# restore old variables
|
# restore old variables
|
||||||
self._templar.set_available_variables(old_vars)
|
self._templar.available_variables = old_vars
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -66,7 +66,7 @@ class LookupModule(LookupBase):
|
||||||
|
|
||||||
def run(self, terms, variables=None, **kwargs):
|
def run(self, terms, variables=None, **kwargs):
|
||||||
if variables is not None:
|
if variables is not None:
|
||||||
self._templar.set_available_variables(variables)
|
self._templar.available_variables = variables
|
||||||
myvars = getattr(self._templar, '_available_variables', {})
|
myvars = getattr(self._templar, '_available_variables', {})
|
||||||
|
|
||||||
self.set_options(direct=kwargs)
|
self.set_options(direct=kwargs)
|
||||||
|
|
|
@ -451,7 +451,12 @@ class Templar:
|
||||||
|
|
||||||
return jinja_exts
|
return jinja_exts
|
||||||
|
|
||||||
def set_available_variables(self, variables):
|
@property
|
||||||
|
def available_variables(self):
|
||||||
|
return self._available_variables
|
||||||
|
|
||||||
|
@available_variables.setter
|
||||||
|
def available_variables(self, variables):
|
||||||
'''
|
'''
|
||||||
Sets the list of template variables this Templar instance will use
|
Sets the list of template variables this Templar instance will use
|
||||||
to template things, so we don't have to pass them around between
|
to template things, so we don't have to pass them around between
|
||||||
|
@ -464,6 +469,13 @@ class Templar:
|
||||||
self._available_variables = variables
|
self._available_variables = variables
|
||||||
self._cached_result = {}
|
self._cached_result = {}
|
||||||
|
|
||||||
|
def set_available_variables(self, variables):
|
||||||
|
display.deprecated(
|
||||||
|
'set_available_variables is being deprecated. Use "@available_variables.setter" instead.',
|
||||||
|
version='2.13'
|
||||||
|
)
|
||||||
|
self.available_variables = variables
|
||||||
|
|
||||||
def template(self, variable, convert_bare=False, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None,
|
def template(self, variable, convert_bare=False, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None,
|
||||||
convert_data=True, static_vars=None, cache=True, disable_lookups=False):
|
convert_data=True, static_vars=None, cache=True, disable_lookups=False):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -60,7 +60,7 @@ class AnsibleJ2Vars(Mapping):
|
||||||
self._locals[key] = val
|
self._locals[key] = val
|
||||||
|
|
||||||
def __contains__(self, k):
|
def __contains__(self, k):
|
||||||
if k in self._templar._available_variables:
|
if k in self._templar.available_variables:
|
||||||
return True
|
return True
|
||||||
if k in self._locals:
|
if k in self._locals:
|
||||||
return True
|
return True
|
||||||
|
@ -73,16 +73,16 @@ class AnsibleJ2Vars(Mapping):
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
keys = set()
|
keys = set()
|
||||||
keys.update(self._templar._available_variables, self._locals, self._globals, *self._extras)
|
keys.update(self._templar.available_variables, self._locals, self._globals, *self._extras)
|
||||||
return iter(keys)
|
return iter(keys)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
keys = set()
|
keys = set()
|
||||||
keys.update(self._templar._available_variables, self._locals, self._globals, *self._extras)
|
keys.update(self._templar.available_variables, self._locals, self._globals, *self._extras)
|
||||||
return len(keys)
|
return len(keys)
|
||||||
|
|
||||||
def __getitem__(self, varname):
|
def __getitem__(self, varname):
|
||||||
if varname not in self._templar._available_variables:
|
if varname not in self._templar.available_variables:
|
||||||
if varname in self._locals:
|
if varname in self._locals:
|
||||||
return self._locals[varname]
|
return self._locals[varname]
|
||||||
for i in self._extras:
|
for i in self._extras:
|
||||||
|
@ -93,7 +93,7 @@ class AnsibleJ2Vars(Mapping):
|
||||||
else:
|
else:
|
||||||
raise KeyError("undefined variable: %s" % varname)
|
raise KeyError("undefined variable: %s" % varname)
|
||||||
|
|
||||||
variable = self._templar._available_variables[varname]
|
variable = self._templar.available_variables[varname]
|
||||||
|
|
||||||
# HostVars is special, return it as-is, as is the special variable
|
# HostVars is special, return it as-is, as is the special variable
|
||||||
# 'vars', which contains the vars structure
|
# 'vars', which contains the vars structure
|
||||||
|
|
|
@ -318,7 +318,7 @@ class VariableManager:
|
||||||
# and magic vars so we can properly template the vars_files entries
|
# and magic vars so we can properly template the vars_files entries
|
||||||
temp_vars = combine_vars(all_vars, self._extra_vars)
|
temp_vars = combine_vars(all_vars, self._extra_vars)
|
||||||
temp_vars = combine_vars(temp_vars, magic_variables)
|
temp_vars = combine_vars(temp_vars, magic_variables)
|
||||||
self._templar.set_available_variables(temp_vars)
|
self._templar.available_variables = temp_vars
|
||||||
|
|
||||||
# we assume each item in the list is itself a list, as we
|
# we assume each item in the list is itself a list, as we
|
||||||
# support "conditional includes" for vars_files, which mimics
|
# support "conditional includes" for vars_files, which mimics
|
||||||
|
@ -498,7 +498,7 @@ class VariableManager:
|
||||||
# as we're fetching vars before post_validate has been called on
|
# as we're fetching vars before post_validate has been called on
|
||||||
# the task that has been passed in
|
# the task that has been passed in
|
||||||
vars_copy = existing_variables.copy()
|
vars_copy = existing_variables.copy()
|
||||||
self._templar.set_available_variables(vars_copy)
|
self._templar.available_variables = vars_copy
|
||||||
|
|
||||||
items = []
|
items = []
|
||||||
has_loop = True
|
has_loop = True
|
||||||
|
@ -533,7 +533,7 @@ class VariableManager:
|
||||||
if item is not None:
|
if item is not None:
|
||||||
vars_copy[item_var] = item
|
vars_copy[item_var] = item
|
||||||
|
|
||||||
self._templar.set_available_variables(vars_copy)
|
self._templar.available_variables = vars_copy
|
||||||
delegated_host_name = self._templar.template(task.delegate_to, fail_on_undefined=False)
|
delegated_host_name = self._templar.template(task.delegate_to, fail_on_undefined=False)
|
||||||
if delegated_host_name != task.delegate_to:
|
if delegated_host_name != task.delegate_to:
|
||||||
cache_items = True
|
cache_items = True
|
||||||
|
|
|
@ -214,7 +214,7 @@ class TestActionBase(unittest.TestCase):
|
||||||
self.assertEqual(env_string, "FOO=foo")
|
self.assertEqual(env_string, "FOO=foo")
|
||||||
|
|
||||||
# test environment with a variable in it
|
# test environment with a variable in it
|
||||||
templar.set_available_variables(variables=dict(the_var='bar'))
|
templar.available_variables = dict(the_var='bar')
|
||||||
mock_task.environment = [dict(FOO='{{the_var}}')]
|
mock_task.environment = [dict(FOO='{{the_var}}')]
|
||||||
env_string = action_base._compute_environment_string()
|
env_string = action_base._compute_environment_string()
|
||||||
self.assertEqual(env_string, "FOO=bar")
|
self.assertEqual(env_string, "FOO=bar")
|
||||||
|
|
|
@ -217,11 +217,17 @@ class TestTemplarMisc(BaseTemplar, unittest.TestCase):
|
||||||
# test with fail_on_undefined=False
|
# test with fail_on_undefined=False
|
||||||
self.assertEqual(templar.template("{{bad_var}}", fail_on_undefined=False), "{{bad_var}}")
|
self.assertEqual(templar.template("{{bad_var}}", fail_on_undefined=False), "{{bad_var}}")
|
||||||
|
|
||||||
# test set_available_variables()
|
# test setting available_variables
|
||||||
templar.set_available_variables(variables=dict(foo="bam"))
|
templar.available_variables = dict(foo="bam")
|
||||||
self.assertEqual(templar.template("{{foo}}"), "bam")
|
self.assertEqual(templar.template("{{foo}}"), "bam")
|
||||||
# variables must be a dict() for set_available_variables()
|
# variables must be a dict() for available_variables setter
|
||||||
self.assertRaises(AssertionError, templar.set_available_variables, "foo=bam")
|
# FIXME Use assertRaises() as a context manager (added in 2.7) once we do not run tests on Python 2.6 anymore.
|
||||||
|
try:
|
||||||
|
templar.available_variables = "foo=bam"
|
||||||
|
except AssertionError as e:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
self.fail(e)
|
||||||
|
|
||||||
def test_templar_escape_backslashes(self):
|
def test_templar_escape_backslashes(self):
|
||||||
# Rule of thumb: If escape backslashes is True you should end up with
|
# Rule of thumb: If escape backslashes is True you should end up with
|
||||||
|
|
Loading…
Reference in a new issue