summaryrefslogtreecommitdiff
path: root/lib/ansible/template/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/template/__init__.py')
-rw-r--r--lib/ansible/template/__init__.py109
1 files changed, 50 insertions, 59 deletions
diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py
index 05aab631..c45cfe35 100644
--- a/lib/ansible/template/__init__.py
+++ b/lib/ansible/template/__init__.py
@@ -45,8 +45,8 @@ from ansible.errors import (
AnsibleOptionsError,
AnsibleUndefinedVariable,
)
-from ansible.module_utils.six import string_types
-from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
+from ansible.module_utils.six import string_types, text_type
+from ansible.module_utils._text import to_native, to_text, to_bytes
from ansible.module_utils.common.collections import is_sequence
from ansible.plugins.loader import filter_loader, lookup_loader, test_loader
from ansible.template.native_helpers import ansible_native_concat, ansible_eval_concat, ansible_concat
@@ -55,7 +55,7 @@ from ansible.template.vars import AnsibleJ2Vars
from ansible.utils.display import Display
from ansible.utils.listify import listify_lookup_plugin_terms
from ansible.utils.native_jinja import NativeJinjaText
-from ansible.utils.unsafe_proxy import to_unsafe_text, wrap_var, AnsibleUnsafeText, AnsibleUnsafeBytes, NativeJinjaUnsafeText
+from ansible.utils.unsafe_proxy import wrap_var, AnsibleUnsafeText, AnsibleUnsafeBytes, NativeJinjaUnsafeText
display = Display()
@@ -103,9 +103,9 @@ def generate_ansible_template_vars(path, fullpath=None, dest_path=None):
managed_str = managed_default.format(
host=temp_vars['template_host'],
uid=temp_vars['template_uid'],
- file=temp_vars['template_path'].replace('%', '%%'),
+ file=temp_vars['template_path'],
)
- temp_vars['ansible_managed'] = to_unsafe_text(time.strftime(to_native(managed_str), time.localtime(os.path.getmtime(b_path))))
+ temp_vars['ansible_managed'] = to_text(time.strftime(to_native(managed_str), time.localtime(os.path.getmtime(b_path))))
return temp_vars
@@ -130,7 +130,7 @@ def _escape_backslashes(data, jinja_env):
backslashes inside of a jinja2 expression.
"""
- if '\\' in data and jinja_env.variable_start_string in data:
+ if '\\' in data and '{{' in data:
new_data = []
d2 = jinja_env.preprocess(data)
in_var = False
@@ -153,39 +153,6 @@ def _escape_backslashes(data, jinja_env):
return data
-def _create_overlay(data, overrides, jinja_env):
- if overrides is None:
- overrides = {}
-
- try:
- has_override_header = data.startswith(JINJA2_OVERRIDE)
- except (TypeError, AttributeError):
- has_override_header = False
-
- if overrides or has_override_header:
- overlay = jinja_env.overlay(**overrides)
- else:
- overlay = jinja_env
-
- # Get jinja env overrides from template
- if has_override_header:
- eol = data.find('\n')
- line = data[len(JINJA2_OVERRIDE):eol]
- data = data[eol + 1:]
- for pair in line.split(','):
- if ':' not in pair:
- raise AnsibleError("failed to parse jinja2 override '%s'."
- " Did you use something different from colon as key-value separator?" % pair.strip())
- (key, val) = pair.split(':', 1)
- key = key.strip()
- if hasattr(overlay, key):
- setattr(overlay, key, ast.literal_eval(val.strip()))
- else:
- display.warning(f"Could not find Jinja2 environment setting to override: '{key}'")
-
- return data, overlay
-
-
def is_possibly_template(data, jinja_env):
"""Determines if a string looks like a template, by seeing if it
contains a jinja2 start delimiter. Does not guarantee that the string
@@ -565,7 +532,7 @@ class AnsibleEnvironment(NativeEnvironment):
'''
context_class = AnsibleContext
template_class = AnsibleJ2Template
- concat = staticmethod(ansible_eval_concat) # type: ignore[assignment]
+ concat = staticmethod(ansible_eval_concat)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -580,7 +547,7 @@ class AnsibleEnvironment(NativeEnvironment):
class AnsibleNativeEnvironment(AnsibleEnvironment):
- concat = staticmethod(ansible_native_concat) # type: ignore[assignment]
+ concat = staticmethod(ansible_native_concat)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -592,7 +559,14 @@ class Templar:
The main class for templating, with the main entry-point of template().
'''
- def __init__(self, loader, variables=None):
+ def __init__(self, loader, shared_loader_obj=None, variables=None):
+ if shared_loader_obj is not None:
+ display.deprecated(
+ "The `shared_loader_obj` option to `Templar` is no longer functional, "
+ "ansible.plugins.loader is used directly instead.",
+ version='2.16',
+ )
+
self._loader = loader
self._available_variables = {} if variables is None else variables
@@ -606,6 +580,9 @@ class Templar:
)
self.environment.template_class.environment_class = environment_class
+ # jinja2 global is inconsistent across versions, this normalizes them
+ self.environment.globals['dict'] = dict
+
# Custom globals
self.environment.globals['lookup'] = self._lookup
self.environment.globals['query'] = self.environment.globals['q'] = self._query_lookup
@@ -615,14 +592,11 @@ class Templar:
# the current rendering context under which the templar class is working
self.cur_context = None
- # this regex is re-compiled each time variable_start_string and variable_end_string are possibly changed
- self._compile_single_var(self.environment)
+ # FIXME this regex should be re-compiled each time variable_start_string and variable_end_string are changed
+ self.SINGLE_VAR = re.compile(r"^%s\s*(\w*)\s*%s$" % (self.environment.variable_start_string, self.environment.variable_end_string))
self.jinja2_native = C.DEFAULT_JINJA2_NATIVE
- def _compile_single_var(self, env):
- self.SINGLE_VAR = re.compile(r"^%s\s*(\w*)\s*%s$" % (env.variable_start_string, env.variable_end_string))
-
def copy_with_new_env(self, environment_class=AnsibleEnvironment, **kwargs):
r"""Creates a new copy of Templar with a new environment.
@@ -745,7 +719,7 @@ class Templar:
variable = self._convert_bare_variable(variable)
if isinstance(variable, string_types):
- if not self.is_possibly_template(variable, overrides):
+ if not self.is_possibly_template(variable):
return variable
# Check to see if the string we are trying to render is just referencing a single
@@ -770,7 +744,6 @@ class Templar:
disable_lookups=disable_lookups,
convert_data=convert_data,
)
- self._compile_single_var(self.environment)
return result
@@ -817,9 +790,8 @@ class Templar:
templatable = is_template
- def is_possibly_template(self, data, overrides=None):
- data, env = _create_overlay(data, overrides, self.environment)
- return is_possibly_template(data, env)
+ def is_possibly_template(self, data):
+ return is_possibly_template(data, self.environment)
def _convert_bare_variable(self, variable):
'''
@@ -843,7 +815,7 @@ class Templar:
def _now_datetime(self, utc=False, fmt=None):
'''jinja2 global function to return current datetime, potentially formatted via strftime'''
if utc:
- now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
+ now = datetime.datetime.utcnow()
else:
now = datetime.datetime.now()
@@ -852,12 +824,12 @@ class Templar:
return now
- def _query_lookup(self, name, /, *args, **kwargs):
+ def _query_lookup(self, name, *args, **kwargs):
''' wrapper for lookup, force wantlist true'''
kwargs['wantlist'] = True
return self._lookup(name, *args, **kwargs)
- def _lookup(self, name, /, *args, **kwargs):
+ def _lookup(self, name, *args, **kwargs):
instance = lookup_loader.get(name, loader=self._loader, templar=self)
if instance is None:
@@ -960,12 +932,31 @@ class Templar:
if fail_on_undefined is None:
fail_on_undefined = self._fail_on_undefined_errors
+ has_template_overrides = data.startswith(JINJA2_OVERRIDE)
+
try:
# NOTE Creating an overlay that lives only inside do_template means that overrides are not applied
# when templating nested variables in AnsibleJ2Vars where Templar.environment is used, not the overlay.
- data, myenv = _create_overlay(data, overrides, self.environment)
- # in case delimiters change
- self._compile_single_var(myenv)
+ # This is historic behavior that is kept for backwards compatibility.
+ if overrides:
+ myenv = self.environment.overlay(overrides)
+ elif has_template_overrides:
+ myenv = self.environment.overlay()
+ else:
+ myenv = self.environment
+
+ # Get jinja env overrides from template
+ if has_template_overrides:
+ eol = data.find('\n')
+ line = data[len(JINJA2_OVERRIDE):eol]
+ data = data[eol + 1:]
+ for pair in line.split(','):
+ if ':' not in pair:
+ raise AnsibleError("failed to parse jinja2 override '%s'."
+ " Did you use something different from colon as key-value separator?" % pair.strip())
+ (key, val) = pair.split(':', 1)
+ key = key.strip()
+ setattr(myenv, key, ast.literal_eval(val.strip()))
if escape_backslashes:
# Allow users to specify backslashes in playbooks as "\\" instead of as "\\\\".
@@ -973,7 +964,7 @@ class Templar:
try:
t = myenv.from_string(data)
- except (TemplateSyntaxError, SyntaxError) as e:
+ except TemplateSyntaxError as e:
raise AnsibleError("template error while templating string: %s. String: %s" % (to_native(e), to_native(data)), orig_exc=e)
except Exception as e:
if 'recursion' in to_native(e):