Do not escape backslashes when processing a template file.

Fixes #12198
Fixes #12241
pull/12256/head
Toshio Kuratomi 9 years ago
parent 21ee4b02da
commit e218bf8da9

@ -122,7 +122,7 @@ class ActionModule(ActionBase):
old_vars = self._templar._available_variables old_vars = self._templar._available_variables
self._templar.set_available_variables(temp_vars) self._templar.set_available_variables(temp_vars)
resultant = self._templar.template(template_data, preserve_trailing_newlines=True, convert_data=False) resultant = self._templar.template(template_data, preserve_trailing_newlines=True, escape_backslashes=False, convert_data=False)
self._templar.set_available_variables(old_vars) self._templar.set_available_variables(old_vars)
except Exception as e: except Exception as e:
return dict(failed=True, msg=type(e).__name__ + ": " + str(e)) return dict(failed=True, msg=type(e).__name__ + ": " + str(e))

@ -48,7 +48,7 @@ NON_TEMPLATED_TYPES = ( bool, Number )
JINJA2_OVERRIDE = '#jinja2:' JINJA2_OVERRIDE = '#jinja2:'
def _preserve_backslashes(data, jinja_env): def _escape_backslashes(data, jinja_env):
"""Double backslashes within jinja2 expressions """Double backslashes within jinja2 expressions
A user may enter something like this in a playbook:: A user may enter something like this in a playbook::
@ -206,7 +206,7 @@ class Templar:
assert isinstance(variables, dict) assert isinstance(variables, dict)
self._available_variables = variables.copy() self._available_variables = variables.copy()
def template(self, variable, convert_bare=False, preserve_trailing_newlines=True, fail_on_undefined=None, overrides=None, convert_data=True): def template(self, variable, convert_bare=False, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None, convert_data=True):
''' '''
Templates (possibly recursively) any given data as input. If convert_bare is Templates (possibly recursively) any given data as input. If convert_bare is
set to True, the given data will be wrapped as a jinja2 variable ('{{foo}}') set to True, the given data will be wrapped as a jinja2 variable ('{{foo}}')
@ -234,7 +234,7 @@ class Templar:
elif resolved_val is None: elif resolved_val is None:
return C.DEFAULT_NULL_REPRESENTATION return C.DEFAULT_NULL_REPRESENTATION
result = self._do_template(variable, preserve_trailing_newlines=preserve_trailing_newlines, fail_on_undefined=fail_on_undefined, overrides=overrides) result = self._do_template(variable, preserve_trailing_newlines=preserve_trailing_newlines, escape_backslashes=escape_backslashes, fail_on_undefined=fail_on_undefined, overrides=overrides)
if convert_data: if convert_data:
# if this looks like a dictionary or list, convert it to such using the safe_eval method # if this looks like a dictionary or list, convert it to such using the safe_eval method
@ -316,7 +316,7 @@ class Templar:
else: else:
raise AnsibleError("lookup plugin (%s) not found" % name) raise AnsibleError("lookup plugin (%s) not found" % name)
def _do_template(self, data, preserve_trailing_newlines=True, fail_on_undefined=None, overrides=None): def _do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None):
# For preserving the number of input newlines in the output (used # For preserving the number of input newlines in the output (used
# later in this method) # later in this method)
@ -346,7 +346,10 @@ class Templar:
myenv.filters.update(self._get_filters()) myenv.filters.update(self._get_filters())
myenv.tests.update(self._get_tests()) myenv.tests.update(self._get_tests())
data = _preserve_backslashes(data, myenv) if escape_backslashes:
# Allow users to specify backslashes in playbooks as "\\"
# instead of as "\\\\".
data = _escape_backslashes(data, myenv)
try: try:
t = myenv.from_string(data) t = myenv.from_string(data)

@ -33,12 +33,6 @@ from units.mock.loader import DictDataLoader
class TestTemplar(unittest.TestCase): class TestTemplar(unittest.TestCase):
def setUp(self): def setUp(self):
pass
def tearDown(self):
pass
def test_templar_simple(self):
fake_loader = DictDataLoader({ fake_loader = DictDataLoader({
"/path/to/my_file.txt": "foo\n", "/path/to/my_file.txt": "foo\n",
}) })
@ -54,8 +48,14 @@ class TestTemplar(unittest.TestCase):
var_list=[1], var_list=[1],
recursive="{{recursive}}", recursive="{{recursive}}",
) )
templar = Templar(loader=fake_loader, variables=variables) self.templar = Templar(loader=fake_loader, variables=variables)
def tearDown(self):
pass
def test_templar_simple(self):
templar = self.templar
# test some basic templating # test some basic templating
self.assertEqual(templar.template("{{foo}}"), "bar") self.assertEqual(templar.template("{{foo}}"), "bar")
self.assertEqual(templar.template("{{foo}}\n"), "bar\n") self.assertEqual(templar.template("{{foo}}\n"), "bar\n")
@ -89,6 +89,20 @@ class TestTemplar(unittest.TestCase):
# variables must be a dict() for set_available_variables() # variables must be a dict() for set_available_variables()
self.assertRaises(AssertionError, templar.set_available_variables, "foo=bam") self.assertRaises(AssertionError, templar.set_available_variables, "foo=bam")
def test_templar_escape_backslashes(self):
# Rule of thumb: If escape backslashes is True you should end up with
# the same number of backslashes as when you started.
self.assertEqual(self.templar.template("\t{{foo}}", escape_backslashes=True), "\tbar")
self.assertEqual(self.templar.template("\t{{foo}}", escape_backslashes=False), "\tbar")
self.assertEqual(self.templar.template("\\{{foo}}", escape_backslashes=True), "\\bar")
self.assertEqual(self.templar.template("\\{{foo}}", escape_backslashes=False), "\\bar")
self.assertEqual(self.templar.template("\\{{foo + '\t' }}", escape_backslashes=True), "\\bar\t")
self.assertEqual(self.templar.template("\\{{foo + '\t' }}", escape_backslashes=False), "\\bar\t")
self.assertEqual(self.templar.template("\\{{foo + '\\t' }}", escape_backslashes=True), "\\bar\\t")
self.assertEqual(self.templar.template("\\{{foo + '\\t' }}", escape_backslashes=False), "\\bar\t")
self.assertEqual(self.templar.template("\\{{foo + '\\\\t' }}", escape_backslashes=True), "\\bar\\\\t")
self.assertEqual(self.templar.template("\\{{foo + '\\\\t' }}", escape_backslashes=False), "\\bar\\t")
def test_template_jinja2_extensions(self): def test_template_jinja2_extensions(self):
fake_loader = DictDataLoader({}) fake_loader = DictDataLoader({})
templar = Templar(loader=fake_loader) templar = Templar(loader=fake_loader)

@ -22,7 +22,7 @@ __metaclass__ = type
import jinja2 import jinja2
from ansible.compat.tests import unittest from ansible.compat.tests import unittest
from ansible.template import _preserve_backslashes, _count_newlines_from_end from ansible.template import _escape_backslashes, _count_newlines_from_end
# These are internal utility functions only needed for templating. They're # These are internal utility functions only needed for templating. They're
# algorithmic so good candidates for unittesting by themselves # algorithmic so good candidates for unittesting by themselves
@ -78,7 +78,7 @@ class TestBackslashEscape(unittest.TestCase):
def test_backslash_escaping(self): def test_backslash_escaping(self):
for test in self.test_data: for test in self.test_data:
intermediate = _preserve_backslashes(test['template'], self.env) intermediate = _escape_backslashes(test['template'], self.env)
self.assertEquals(intermediate, test['intermediate']) self.assertEquals(intermediate, test['intermediate'])
template = jinja2.Template(intermediate) template = jinja2.Template(intermediate)
args = test['args'] args = test['args']

Loading…
Cancel
Save