From 1c3536fb8e1b1814f6ba988efbb018bc98b7066f Mon Sep 17 00:00:00 2001 From: Thayne Harbaugh Date: Wed, 8 Apr 2015 23:16:39 -0600 Subject: [PATCH 1/2] Support nested nodegroups Nodegroups can be recursively expanded without worrying about other compound matcher expansions. Once the nodegroups are expanded on the master the remaining flattened compound match can be expanded without the nodegroup information. --- salt/utils/minions.py | 50 +++++++++++++++++------------ tests/integration/files/conf/master | 5 +++ tests/integration/shell/matcher.py | 23 +++++++++++++ 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/salt/utils/minions.py b/salt/utils/minions.py index a0a13d3857..13c0538e43 100644 --- a/salt/utils/minions.py +++ b/salt/utils/minions.py @@ -69,31 +69,39 @@ def get_minion_data(minion, opts): return minion if minion else None, None, None -def nodegroup_comp(group, nodegroups, skip=None): +def nodegroup_comp(nodegroup, nodegroups, skip=None): ''' - Take the nodegroup and the nodegroups and fill in nodegroup refs + Recursively expand ``nodegroup`` from ``nodegroups``; ignore nodegroups in ``skip`` ''' - k = 1 + if skip is None: - skip = set([group]) - k = 0 - if group not in nodegroups: + skip = set() + elif nodegroup in skip: + log.error('Failed nodegroup expansion: illegal nested nodegroup "{0}"'.format(nodegroup)) return '' - gstr = nodegroups[group] - ret = '' - for comp in gstr.split(','): - if not comp.startswith('N@'): - ret += '{0} or '.format(comp) - continue - ngroup = comp[2:] - if ngroup in skip: - continue - skip.add(ngroup) - ret += nodegroup_comp(ngroup, nodegroups, skip) - if k == 1: - return ret - else: - return ret[:-3] + + skip.add(nodegroup) + + if nodegroup not in nodegroups: + log.error('Failed nodegroup expansion: unknown nodegroup "{0}"'.format(nodegroup)) + return '' + + nglookup = nodegroups[nodegroup] + + ret = [] + opers = ['and', 'or', 'not', '(', ')'] + tokens = nglookup.split() + for match in tokens: + if match in opers: + ret.append(match) + elif len(match) >= 3 and match[:2] == 'N@': + ret.append(nodegroup_comp(match[2:], nodegroups, skip=skip)) + else: + ret.append(match) + + expanded = '( {0} )'.format(' '.join(ret)) if ret else '' + log.debug('nodegroup_comp("{0}") => {1}'.format(nodegroup, expanded)) + return expanded class CkMinions(object): diff --git a/tests/integration/files/conf/master b/tests/integration/files/conf/master index b1d6e8d42c..b44c76b6e4 100644 --- a/tests/integration/files/conf/master +++ b/tests/integration/files/conf/master @@ -58,3 +58,8 @@ external_auth: master_tops: master_tops_test: True + +nodegroups: + min: minion + sub_min: sub_minion + mins: N@min or N@sub_min diff --git a/tests/integration/shell/matcher.py b/tests/integration/shell/matcher.py index 88c4bc7a69..2e7bb75bef 100644 --- a/tests/integration/shell/matcher.py +++ b/tests/integration/shell/matcher.py @@ -65,6 +65,29 @@ class MatchTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn): self.assertIn('sub_minion', data) self.assertNotIn('minion', data.replace('sub_minion', 'stub')) + def test_nodegroup(self): + ''' + test salt nodegroup matcher + ''' + def minion_in_target(minion, lines): + return sum([line == '{0}:'.format(minion) for line in lines]) + + data = self.run_salt('-N min test.ping') + self.assertTrue(minion_in_target('minion', data)) + self.assertFalse(minion_in_target('sub_minion', data)) + time.sleep(2) + data = self.run_salt('-N sub_min test.ping') + self.assertFalse(minion_in_target('minion', data)) + self.assertTrue(minion_in_target('sub_minion', data)) + time.sleep(2) + data = self.run_salt('-N mins test.ping') + self.assertTrue(minion_in_target('minion', data)) + self.assertTrue(minion_in_target('sub_minion', data)) + time.sleep(2) + data = self.run_salt('-N unknown_nodegroup test.ping') + self.assertFalse(minion_in_target('minion', data)) + self.assertFalse(minion_in_target('sub_minion', data)) + def test_glob(self): ''' test salt glob matcher From 617983922554b67bef801a4e73aedc873f10cf18 Mon Sep 17 00:00:00 2001 From: Thayne Harbaugh Date: Thu, 9 Apr 2015 01:43:18 -0600 Subject: [PATCH 2/2] Improve documentation for nested nodegroup. --- doc/ref/cli/index.rst | 2 +- doc/ref/configuration/master.rst | 3 +++ doc/topics/targeting/nodegroups.rst | 9 ++++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/doc/ref/cli/index.rst b/doc/ref/cli/index.rst index 4810782e35..f8cd8706cb 100644 --- a/doc/ref/cli/index.rst +++ b/doc/ref/cli/index.rst @@ -136,8 +136,8 @@ shorthand for having to type out complicated compound expressions. nodegroups:  group1: 'L@foo.domain.com,bar.domain.com,baz.domain.com and bl*.domain.com'  group2: 'G@os:Debian and foo.domain.com' +  group3: 'G@os:Debian and N@group1' -More info on using nodegroups can be found :ref:`here `. Calling the Function -------------------- diff --git a/doc/ref/configuration/master.rst b/doc/ref/configuration/master.rst index 01106f7cca..c0de2812cc 100644 --- a/doc/ref/configuration/master.rst +++ b/doc/ref/configuration/master.rst @@ -2286,6 +2286,9 @@ A group consists of a group name and a compound target. nodegroups: group1: 'L@foo.domain.com,bar.domain.com,baz.domain.com or bl*.domain.com' group2: 'G@os:Debian and foo.domain.com' + group3: 'G@os:Debian and N@group1' + +More information on using nodegroups can be found :ref:`here `. Range Cluster Settings diff --git a/doc/topics/targeting/nodegroups.rst b/doc/topics/targeting/nodegroups.rst index b19b82c3ac..b0e5420d2f 100644 --- a/doc/topics/targeting/nodegroups.rst +++ b/doc/topics/targeting/nodegroups.rst @@ -16,6 +16,7 @@ nodegroups. Here's an example nodegroup configuration within nodegroups: group1: 'L@foo.domain.com,bar.domain.com,baz.domain.com or bl*.domain.com' group2: 'G@os:Debian and foo.domain.com' + group3: 'G@os:Debian and N@group1' .. note:: @@ -23,6 +24,12 @@ nodegroups. Here's an example nodegroup configuration within group2 is matching specific grains. See the :doc:`compound matchers ` documentation for more details. +.. note:: + + Nodgroups can reference other nodegroups as seen in ``group3``. Ensure + that you do not have circular references. Circular references will be + detected and cause partial expansion with a logged error message. + To match a nodegroup on the CLI, use the ``-N`` command-line option: .. code-block:: bash @@ -45,4 +52,4 @@ nodegroup`` on the line directly following the nodegroup name. for those changes to be fully recognized. A limited amount of functionality, such as targeting with -N from the command-line may be - available without a restart. \ No newline at end of file + available without a restart.