diff options
| author | Michal Nasiadka <mnasiadka@gmail.com> | 2026-08-21 08:22:06 +0200 |
|---|---|---|
| committer | Bartosz Bezak <bartosz@stackhpc.com> | 2026-08-24 10:12:58 +0000 |
| commit | e3aa050a57e53c17d15aad0273fae397f4a690b8 (patch) | |
| tree | 21b8cb9a822ac095cefa7727461056b3b668fd8e | |
| parent | 762181ae4918e3e261df06ed983a1ef1cb61b10c (diff) | |
| download | kolla-ansible-e3aa050a57e53c17d15aad0273fae397f4a690b8.tar.gz kolla-ansible-e3aa050a57e53c17d15aad0273fae397f4a690b8.zip | |
merge_configs: Add lstrip_blocks
Closes-Bug: #2164718
Change-Id: If5b7f30d2467b61c3578d09992faf446b5d25f4e
Signed-off-by: Michal Nasiadka <mnasiadka@gmail.com>
(cherry picked from commit 0f4da209da6fa39739ffc7b7fb1a69dc967734b7)
| -rw-r--r-- | ansible/action_plugins/merge_configs.py | 7 | ||||
| -rw-r--r-- | ansible/action_plugins/merge_yaml.py | 7 | ||||
| -rw-r--r-- | tests/test_merge_config.py | 41 | ||||
| -rw-r--r-- | tests/test_merge_yaml.py | 32 |
4 files changed, 83 insertions, 4 deletions
diff --git a/ansible/action_plugins/merge_configs.py b/ansible/action_plugins/merge_configs.py index 67a7da1cd..09dc1d04e 100644 --- a/ansible/action_plugins/merge_configs.py +++ b/ansible/action_plugins/merge_configs.py @@ -169,9 +169,12 @@ class ActionModule(action.ActionBase): os.path.join(self._loader._basedir, 'templates'), os.path.dirname(source), ] - self._templar.environment.loader.searchpath = searchpath + templar = self._templar.copy_with_new_env(searchpath=searchpath) - result = self._templar.template(template_data) + # lstrip_blocks avoids Jinja2 block tags (e.g. {% if %}) leaving + # behind leading whitespace that glues adjacent lines together. + result = templar.template( + template_data, overrides=dict(lstrip_blocks=True)) fakefile = StringIO(result) config.parse(fakefile) fakefile.close() diff --git a/ansible/action_plugins/merge_yaml.py b/ansible/action_plugins/merge_yaml.py index d2c15eb70..f3ba8597b 100644 --- a/ansible/action_plugins/merge_yaml.py +++ b/ansible/action_plugins/merge_yaml.py @@ -109,9 +109,12 @@ class ActionModule(action.ActionBase): os.path.join(self._loader._basedir, 'templates'), os.path.dirname(source), ] - self._templar.environment.loader.searchpath = searchpath + templar = self._templar.copy_with_new_env(searchpath=searchpath) - template_data = self._templar.template(template_data) + # lstrip_blocks avoids Jinja2 block tags (e.g. {% if %}) leaving + # behind leading whitespace that glues adjacent lines together. + template_data = templar.template( + template_data, overrides=dict(lstrip_blocks=True)) result = yaml.safe_load(template_data) return result or {} diff --git a/tests/test_merge_config.py b/tests/test_merge_config.py index d64b2ae6b..de2c98281 100644 --- a/tests/test_merge_config.py +++ b/tests/test_merge_config.py @@ -15,8 +15,12 @@ from importlib.machinery import SourceFileLoader import os +import tempfile from io import StringIO + +from ansible.parsing.dataloader import DataLoader +from ansible.template import Templar from oslotest import base @@ -211,3 +215,40 @@ class OverrideConfigParserTest(base.BaseTestCase): parser.write(output) self.assertEqual(TESTC_NO_WHITESPACE, output.getvalue()) output.close() + + def test_read_config_lstrip_blocks(self): + # An indented Jinja2 block tag on its own line must not leak its + # leading whitespace into the following line, or the line gets + # parsed as a continuation of the previous key's value instead of + # a new key. + content = ( + "[DEFAULT]\n" + "key1 = value1\n" + " {% if true %}\n" + "key2 = value2\n" + " {% endif %}\n" + "key3 = value3\n" + ) + with tempfile.TemporaryDirectory() as tmpdir: + source = os.path.join(tmpdir, 'source.conf') + with open(source, 'w') as f: + f.write(content) + + loader = DataLoader() + loader.set_basedir(tmpdir) + action = object.__new__(merge_configs.ActionModule) + action._loader = loader + action._templar = Templar(loader=loader) + + config = merge_configs.OverrideConfigParser() + action.read_config(source, config) + + output = StringIO() + config.write(output) + self.assertEqual( + "[DEFAULT]\n" + "key1 = value1\n" + "key2 = value2\n" + "key3 = value3\n\n", + output.getvalue()) + output.close() diff --git a/tests/test_merge_yaml.py b/tests/test_merge_yaml.py index d6b74ae77..35de91d2c 100644 --- a/tests/test_merge_yaml.py +++ b/tests/test_merge_yaml.py @@ -15,8 +15,11 @@ from importlib.machinery import SourceFileLoader import os +import tempfile from ansible.errors import AnsibleModuleError +from ansible.parsing.dataloader import DataLoader +from ansible.template import Templar from oslotest import base PROJECT_DIR = os.path.abspath(os.path.join(os. path.dirname(__file__), '../')) @@ -174,3 +177,32 @@ class MergeYamlConfigTest(base.BaseTestCase): with self.assertRaisesRegex(AnsibleModuleError, "Failure merging key"): merge_yaml.Utils.update_nested_conf( initial_conf, extension, extend_lists=True) + + def test_read_config_lstrip_blocks(self): + # An indented Jinja2 block tag on its own line must not leak its + # leading whitespace into the following line, or the resulting + # YAML indentation becomes inconsistent with its siblings. + content = ( + "foo:\n" + " bar: baz\n" + " {% if true %}\n" + " extra: value\n" + " {% endif %}\n" + " qux: quux\n" + ) + with tempfile.TemporaryDirectory() as tmpdir: + source = os.path.join(tmpdir, 'source.yml') + with open(source, 'w') as f: + f.write(content) + + loader = DataLoader() + loader.set_basedir(tmpdir) + action = object.__new__(merge_yaml.ActionModule) + action._loader = loader + action._templar = Templar(loader=loader) + + result = action.read_config(source) + + self.assertEqual( + {'foo': {'bar': 'baz', 'extra': 'value', 'qux': 'quux'}}, + result) |
