Merge pull request #53624 from Ch3LL/nodegroup_group_list

Allow yaml list notation for nodegroup expansion
This commit is contained in:
Megan Wilhite 2019-07-02 17:32:42 -04:00 committed by GitHub
commit 02461cbe8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 27 deletions

View file

@ -47,6 +47,37 @@ TARGET_REX = re.compile(
)
def _nodegroup_regex(nodegroup, words, opers):
opers_set = set(opers)
ret = words
if (set(ret) - opers_set) == set(ret):
# No compound operators found in nodegroup definition. Check for
# group type specifiers
group_type_re = re.compile('^[A-Z]@')
regex_chars = ['(', '[', '{', '\\', '?', '}', ']', ')']
if not [x for x in ret if '*' in x or group_type_re.match(x)]:
# No group type specifiers and no wildcards.
# Treat this as an expression.
if [x for x in ret if x in [x for y in regex_chars if y in x]]:
joined = 'E@' + ','.join(ret)
log.debug(
'Nodegroup \'%s\' (%s) detected as an expression. '
'Assuming compound matching syntax of \'%s\'',
nodegroup, ret, joined
)
else:
# Treat this as a list of nodenames.
joined = 'L@' + ','.join(ret)
log.debug(
'Nodegroup \'%s\' (%s) detected as list of nodenames. '
'Assuming compound matching syntax of \'%s\'',
nodegroup, ret, joined
)
# Return data must be a list of compound matching components
# to be fed into compound matcher. Enclose return data in list.
return [joined]
def parse_target(target_expression):
'''Parse `target_expressing` splitting it into `engine`, `delimiter`,
`pattern` - returns a dict'''
@ -141,36 +172,16 @@ def nodegroup_comp(nodegroup, nodegroups, skip=None, first_call=True):
# Only return list form if a nodegroup was expanded. Otherwise return
# the original string to conserve backwards compat
if expanded_nodegroup or not first_call:
if not first_call:
joined = _nodegroup_regex(nodegroup, words, opers)
if joined:
return joined
return ret
else:
opers_set = set(opers)
ret = words
if (set(ret) - opers_set) == set(ret):
# No compound operators found in nodegroup definition. Check for
# group type specifiers
group_type_re = re.compile('^[A-Z]@')
regex_chars = ['(', '[', '{', '\\', '?', '}', ']', ')']
if not [x for x in ret if '*' in x or group_type_re.match(x)]:
# No group type specifiers and no wildcards.
# Treat this as an expression.
if [x for x in ret if x in [x for y in regex_chars if y in x]]:
joined = 'E@' + ','.join(ret)
log.debug(
'Nodegroup \'%s\' (%s) detected as an expression. '
'Assuming compound matching syntax of \'%s\'',
nodegroup, ret, joined
)
else:
# Treat this as a list of nodenames.
joined = 'L@' + ','.join(ret)
log.debug(
'Nodegroup \'%s\' (%s) detected as list of nodenames. '
'Assuming compound matching syntax of \'%s\'',
nodegroup, ret, joined
)
# Return data must be a list of compound matching components
# to be fed into compound matcher. Enclose return data in list.
return [joined]
joined = _nodegroup_regex(nodegroup, ret, opers)
if joined:
return joined
log.debug(
'No nested nodegroups detected. Using original nodegroup '

View file

@ -70,14 +70,22 @@ nodegroups:
min: minion
sub_min: sub_minion
mins: N@min or N@sub_min
list_nodegroup:
- 'minion'
- 'sub_minion'
multiline_nodegroup:
- 'minion'
- 'or'
- 'sub_minion'
one_minion_list:
- 'minion'
redundant_minions: N@min or N@mins
nodegroup_loop_a: N@nodegroup_loop_b
nodegroup_loop_b: N@nodegroup_loop_a
missing_minion: L@minion,ghostminion
list_group: N@multiline_nodegroup
one_list_group: N@one_minion_list
list_group2: N@list_nodegroup
mysql.host: localhost

View file

@ -153,6 +153,23 @@ class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
self.assertTrue(minion_in_returns('minion', data))
self.assertTrue(minion_in_returns('sub_minion', data))
def test_nodegroup_list(self):
data = self.run_salt('-N list_group test.ping')
self.assertTrue(minion_in_returns('minion', data))
self.assertTrue(minion_in_returns('sub_minion', data))
data = self.run_salt('-N list_group2 test.ping')
self.assertTrue(minion_in_returns('minion', data))
self.assertTrue(minion_in_returns('sub_minion', data))
data = self.run_salt('-N one_list_group test.ping')
self.assertTrue(minion_in_returns('minion', data))
self.assertFalse(minion_in_returns('sub_minion', data))
data = self.run_salt('-N one_minion_list test.ping')
self.assertTrue(minion_in_returns('minion', data))
self.assertFalse(minion_in_returns('sub_minion', data))
def test_glob(self):
'''
test salt glob matcher

View file

@ -19,6 +19,9 @@ NODEGROUPS = {
'group2': ['G@foo:bar', 'or', 'web1*'],
'group3': ['N@group1', 'or', 'N@group2'],
'group4': ['host4', 'host5', 'host6'],
'group5': 'N@group4',
'group6': 'N@group3',
'group7': ['host1']
}
EXPECTED = {
@ -26,6 +29,10 @@ EXPECTED = {
'group2': ['G@foo:bar', 'or', 'web1*'],
'group3': ['(', '(', 'L@host1,host2,host3', ')', 'or', '(', 'G@foo:bar', 'or', 'web1*', ')', ')'],
'group4': ['L@host4,host5,host6'],
'group5': ['(', 'L@host4,host5,host6', ')'],
'group6': ['(', '(', '(', 'L@host1,host2,host3', ')', 'or', '(',
'G@foo:bar', 'or', 'web1*', ')', ')', ')'],
'group7': ['L@host1']
}