From f729043e0cea476b71613eb033f421da9a51b8fa Mon Sep 17 00:00:00 2001 From: Wayne Werner Date: Mon, 11 Mar 2019 16:41:32 -0500 Subject: [PATCH] Port #52156 to master Allow pillar relative includes Fixes #8875 and Fixes #56186 --- changelog/56186.fixed | 1 + changelog/8875.added | 1 + salt/pillar/__init__.py | 13 ++- tests/unit/test_pillar.py | 165 +++++++++++++++++++++++++++++++++++++- 4 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 changelog/56186.fixed create mode 100644 changelog/8875.added diff --git a/changelog/56186.fixed b/changelog/56186.fixed new file mode 100644 index 000000000000..b221cde66dfd --- /dev/null +++ b/changelog/56186.fixed @@ -0,0 +1 @@ +Pillar data is correctly included from `init.sls` file. diff --git a/changelog/8875.added b/changelog/8875.added new file mode 100644 index 000000000000..13f39c3b78ef --- /dev/null +++ b/changelog/8875.added @@ -0,0 +1 @@ +Pillar relative includes. diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py index 273aeb8c5364..9d0d145e7424 100644 --- a/salt/pillar/__init__.py +++ b/salt/pillar/__init__.py @@ -814,7 +814,8 @@ def render_pstate(self, sls, saltenv, mods, defaults=None): defaults = {} err = "" errors = [] - fn_ = self.client.get_state(sls, saltenv).get("dest", False) + state_data = self.client.get_state(sls, saltenv) + fn_ = state_data.get("dest", False) if not fn_: if sls in self.ignored_pillars.get(saltenv, []): log.debug( @@ -907,6 +908,16 @@ def render_pstate(self, sls, saltenv, mods, defaults=None): self.avail[saltenv], sub_sls.lstrip(".").replace("/", "."), ) + if sub_sls.startswith("."): + if state_data.get("source", "").endswith( + "/init.sls" + ): + include_parts = sls.split(".") + else: + include_parts = sls.split(".")[:-1] + sub_sls = ".".join(include_parts + [sub_sls[1:]]) + matches = fnmatch.filter(self.avail[saltenv], sub_sls,) + matched_pstates.extend(matches) except KeyError: errors.extend( [ diff --git a/tests/unit/test_pillar.py b/tests/unit/test_pillar.py index 7b7cd51eefe8..defc9c238505 100644 --- a/tests/unit/test_pillar.py +++ b/tests/unit/test_pillar.py @@ -8,17 +8,19 @@ """ # Import python libs -from __future__ import absolute_import +from __future__ import absolute_import, print_function +import os import shutil import tempfile - -import salt.exceptions +import textwrap # Import salt libs +import salt.exceptions import salt.fileclient import salt.pillar import salt.utils.stringutils +from salt.utils.files import fopen from tests.support.helpers import with_tempdir from tests.support.mock import MagicMock, patch @@ -867,6 +869,163 @@ def _setup_test_include_sls(self, tempdir): "test.sub.with.slashes": {"path": "", "dest": sub_with_slashes_sls.name}, } + @with_tempdir() + def test_relative_include(self, tempdir): + join = os.path.join + with fopen(join(tempdir, "top.sls"), "w") as f: + print( + textwrap.dedent( + """ + base: + '*': + - includer + - simple_includer + - includes.with.more.depth + """ + ), + file=f, + ) + includer_dir = join(tempdir, "includer") + os.makedirs(includer_dir) + with fopen(join(includer_dir, "init.sls"), "w") as f: + print( + textwrap.dedent( + """ + include: + - .this + - includer.that + """ + ), + file=f, + ) + with fopen(join(includer_dir, "this.sls"), "w") as f: + print( + textwrap.dedent( + """ + this: + is all good + """ + ), + file=f, + ) + with fopen(join(includer_dir, "that.sls"), "w") as f: + print( + textwrap.dedent( + """ + that: + is also all good + """ + ), + file=f, + ) + + with fopen(join(tempdir, "simple_includer.sls"), "w") as simpleincluder: + print( + textwrap.dedent( + """ + include: + - .simple + - super_simple + """ + ), + file=simpleincluder, + ) + with fopen(join(tempdir, "simple.sls"), "w") as f: + print( + textwrap.dedent( + """ + simple: + simon + """ + ), + file=f, + ) + with fopen(join(tempdir, "super_simple.sls"), "w") as f: + print( + textwrap.dedent( + """ + super simple: + a caveman + """ + ), + file=f, + ) + + depth_dir = join(tempdir, "includes", "with", "more") + os.makedirs(depth_dir) + with fopen(join(depth_dir, "depth.sls"), "w") as f: + print( + textwrap.dedent( + """ + include: + - .ramble + - includes.with.more.doors + + mordor: + has dark depths + """ + ), + file=f, + ) + + with fopen(join(depth_dir, "ramble.sls"), "w") as f: + print( + textwrap.dedent( + """ + found: + my precious + """ + ), + file=f, + ) + + with fopen(join(depth_dir, "doors.sls"), "w") as f: + print( + textwrap.dedent( + """ + mojo: + bad risin' + """ + ), + file=f, + ) + opts = { + "optimization_order": [0, 1, 2], + "renderer": "yaml", + "renderer_blacklist": [], + "renderer_whitelist": [], + "state_top": "top.sls", + "pillar_roots": {"base": [tempdir]}, + "extension_modules": "", + "saltenv": "base", + "file_roots": [], + "file_ignore_regex": None, + "file_ignore_glob": None, + } + grains = { + "os": "Ubuntu", + "os_family": "Debian", + "oscodename": "raring", + "osfullname": "Ubuntu", + "osrelease": "13.04", + "kernel": "Linux", + } + pillar = salt.pillar.Pillar(opts, grains, "minion", "base") + # Make sure that confirm_top.confirm_top returns True + pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True + + # Act + compiled_pillar = pillar.compile_pillar() + + # Assert + self.assertEqual(compiled_pillar["this"], "is all good") + self.assertEqual(compiled_pillar["that"], "is also all good") + self.assertEqual(compiled_pillar["simple"], "simon") + self.assertEqual(compiled_pillar["super simple"], "a caveman") + self.assertEqual(compiled_pillar["mordor"], "has dark depths") + self.assertEqual(compiled_pillar["found"], "my precious") + self.assertEqual(compiled_pillar["mojo"], "bad risin'") + @patch("salt.transport.client.ReqChannel.factory", MagicMock()) class RemotePillarTestCase(TestCase):