From 59581e8f5a60fc7cf02d1397adf8c51ddc541e44 Mon Sep 17 00:00:00 2001 From: Ken Crowell Date: Wed, 8 Apr 2020 18:13:28 -0300 Subject: [PATCH 1/2] Fix for compound nodegroup matching --- salt/client/__init__.py | 36 ++++++++++++++++++++----- tests/integration/shell/test_matcher.py | 30 ++++++++++----------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/salt/client/__init__.py b/salt/client/__init__.py index 698fe2dc9172..6aa7099ecf3e 100644 --- a/salt/client/__init__.py +++ b/salt/client/__init__.py @@ -1673,19 +1673,43 @@ def get_event_iter_returns(self, jid, minions, timeout=None): yield ret time.sleep(0.02) + def _resolve_nodegroup(self, ng): + """ + Resolve a nodegroup into its configured components + """ + if ng not in self.opts["nodegroups"]: + conf_file = self.opts.get("conf_file", "the master config file") + raise SaltInvocationError( + "Node group {0} unavailable in {1}".format(ng, conf_file) + ) + return salt.utils.minions.nodegroup_comp(ng, self.opts["nodegroups"]) + def _prep_pub(self, tgt, fun, arg, tgt_type, ret, jid, timeout, **kwargs): """ Set up the payload_kwargs to be sent down to the master """ if tgt_type == "nodegroup": - if tgt not in self.opts["nodegroups"]: - conf_file = self.opts.get("conf_file", "the master config file") - raise SaltInvocationError( - "Node group {0} unavailable in {1}".format(tgt, conf_file) - ) - tgt = salt.utils.minions.nodegroup_comp(tgt, self.opts["nodegroups"]) + tgt = self._resolve_nodegroup(tgt) tgt_type = "compound" + if tgt_type == "compound": + # Resolve all nodegroups, so that the minions don't have to. + new_tgt = list() + log.debug("compound resolution: original tgt: %s", tgt) + + if isinstance(tgt, six.string_types): + tgt = tgt.split() + + for word in tgt: + if word.startswith("N@") and len(word) > 2: + resolved = self._resolve_nodegroup(word[2:]) + new_tgt.extend(resolved) + else: + new_tgt.append(word) + + log.debug("compound resolution: new_tgt: %s", new_tgt) + tgt = " ".join(new_tgt) + # Convert a range expression to a list of nodes and change expression # form to list if tgt_type == "range" and HAS_RANGE: diff --git a/tests/integration/shell/test_matcher.py b/tests/integration/shell/test_matcher.py index e56c53e09ee2..4f2123917ac3 100644 --- a/tests/integration/shell/test_matcher.py +++ b/tests/integration/shell/test_matcher.py @@ -41,7 +41,7 @@ def test_list(self): self.assertIn("minion", data) self.assertIn("sub_minion", data) - # compound matcher tests: 11 + # compound matcher tests: 12 def test_compound_min_with_grain(self): """ @@ -106,21 +106,19 @@ def test_coumpound_pillar_pcre(self): data = self.run_salt("-C 'J%@knights%^(Lancelot|Galahad)$' test.ping") self.assertTrue(minion_in_returns("minion", data)) self.assertTrue(minion_in_returns("sub_minion", data)) - # The multiline nodegroup tests are failing in develop. - # This needs to be fixed for Fluorine. @skipIf wasn't used, because - # the rest of the assertions above pass just fine, so we don't want - # to bypass the whole test. - # time.sleep(2) - # data = self.run_salt("-C 'N@multiline_nodegroup' test.ping") - # self.assertTrue(minion_in_returns('minion', data)) - # self.assertTrue(minion_in_returns('sub_minion', data)) - # time.sleep(2) - # data = self.run_salt("-C 'N@multiline_nodegroup not sub_minion' test.ping") - # self.assertTrue(minion_in_returns('minion', data)) - # self.assertFalse(minion_in_returns('sub_minion', data)) - # data = self.run_salt("-C 'N@multiline_nodegroup not @fakenodegroup not sub_minion' test.ping") - # self.assertTrue(minion_in_returns('minion', data)) - # self.assertFalse(minion_in_returns('sub_minion', data)) + + def test_compound_nodegroup(self): + data = self.run_salt('-C "N@multiline_nodegroup" test.ping') + self.assertTrue(minion_in_returns("minion", data)) + self.assertTrue(minion_in_returns("sub_minion", data)) + data = self.run_salt('-C "N@multiline_nodegroup not sub_minion" test.ping') + self.assertTrue(minion_in_returns("minion", data)) + self.assertFalse(minion_in_returns("sub_minion", data)) + data = self.run_salt( + '-C "N@multiline_nodegroup not @fakenodegroup not sub_minion" test.ping' + ) + self.assertTrue(minion_in_returns("minion", data)) + self.assertFalse(minion_in_returns("sub_minion", data)) def test_nodegroup(self): """ From 94e0078e6e412b8411a8f551f68cdd32c9f22231 Mon Sep 17 00:00:00 2001 From: Ken Crowell Date: Wed, 8 Apr 2020 19:58:59 -0300 Subject: [PATCH 2/2] Fix "coumpound" test names --- tests/integration/shell/test_matcher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/shell/test_matcher.py b/tests/integration/shell/test_matcher.py index 4f2123917ac3..c7df8b7f3147 100644 --- a/tests/integration/shell/test_matcher.py +++ b/tests/integration/shell/test_matcher.py @@ -88,7 +88,7 @@ def test_compound_grain_regex(self): assert minion_in_returns("minion", data) is True assert minion_in_returns("sub_minion", data) is False - def test_coumpound_pcre_grain_regex(self): + def test_compound_pcre_grain_regex(self): data = self.run_salt('-C "P%@planets%^(mercury|saturn)$" test.ping') assert minion_in_returns("minion", data) is True assert minion_in_returns("sub_minion", data) is True @@ -102,7 +102,7 @@ def test_compound_pillar(self): @skipIf(True, "This test is unreliable. Need to investigate why more deeply.") @flaky - def test_coumpound_pillar_pcre(self): + def test_compound_pillar_pcre(self): data = self.run_salt("-C 'J%@knights%^(Lancelot|Galahad)$' test.ping") self.assertTrue(minion_in_returns("minion", data)) self.assertTrue(minion_in_returns("sub_minion", data))