mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Add option -J/--pillar-pcre to match on pillar PCREs
This commit is contained in:
parent
6c68668c52
commit
c91392bc91
9 changed files with 104 additions and 7 deletions
|
@ -496,6 +496,7 @@ class LocalClient(object):
|
|||
* ``grain`` - Match based on a grain comparison
|
||||
* ``grain_pcre`` - Grain comparison with a regex
|
||||
* ``pillar`` - Pillar data comparison
|
||||
* ``pillar_pcre`` - Pillar data comparison with a regex
|
||||
* ``nodegroup`` - Match on nodegroup
|
||||
* ``range`` - Use a Range server for matching
|
||||
* ``compound`` - Pass a compound match string
|
||||
|
|
|
@ -1022,7 +1022,7 @@ class Minion(MinionBase):
|
|||
'{0}_match'.format(data['tgt_type']), None)
|
||||
if match_func is None:
|
||||
return
|
||||
if data['tgt_type'] in ('grain', 'grain_pcre', 'pillar'):
|
||||
if data['tgt_type'] in ('grain', 'grain_pcre', 'pillar', 'pillar_pcre'):
|
||||
delimiter = data.get('delimiter', DEFAULT_TARGET_DELIM)
|
||||
if not match_func(data['tgt'], delimiter=delimiter):
|
||||
return
|
||||
|
@ -2729,9 +2729,22 @@ class Matcher(object):
|
|||
self.opts['pillar'], tgt, delimiter=delimiter
|
||||
)
|
||||
|
||||
def pillar_pcre_match(self, tgt, delimiter=DEFAULT_TARGET_DELIM):
|
||||
'''
|
||||
Reads in the pillar pcre match
|
||||
'''
|
||||
log.debug('pillar PCRE target: {0}'.format(tgt))
|
||||
if delimiter not in tgt:
|
||||
log.error('Got insufficient arguments for pillar PCRE match '
|
||||
'statement from master')
|
||||
return False
|
||||
return salt.utils.subdict_match(
|
||||
self.opts['pillar'], tgt, delimiter=delimiter, regex_match=True
|
||||
)
|
||||
|
||||
def pillar_exact_match(self, tgt, delimiter=':'):
|
||||
'''
|
||||
Reads in the pillar match, no globbing
|
||||
Reads in the pillar match, no globbing, no PCRE
|
||||
'''
|
||||
log.debug('pillar target: {0}'.format(tgt))
|
||||
if delimiter not in tgt:
|
||||
|
@ -2791,6 +2804,7 @@ class Matcher(object):
|
|||
ref = {'G': 'grain',
|
||||
'P': 'grain_pcre',
|
||||
'I': 'pillar',
|
||||
'J': 'pillar_pcre',
|
||||
'L': 'list',
|
||||
'S': 'ipcidr',
|
||||
'E': 'pcre'}
|
||||
|
|
|
@ -70,6 +70,46 @@ def ipcidr(tgt):
|
|||
return False
|
||||
|
||||
|
||||
def pillar_pcre(tgt, delimiter=DEFAULT_TARGET_DELIM, delim=None):
|
||||
'''
|
||||
Return True if the minion matches the given pillar_pcre target. The
|
||||
``delimiter`` argument can be used to specify a different delimiter.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' match.pillar_pcre 'cheese:(swiss|american)'
|
||||
salt '*' match.pillar_pcre 'clone_url|https://github\.com/.*\.git' delimiter='|'
|
||||
|
||||
delimiter
|
||||
Specify an alternate delimiter to use when traversing a nested dict
|
||||
|
||||
.. versionadded:: 2014.7.0
|
||||
|
||||
delim
|
||||
Specify an alternate delimiter to use when traversing a nested dict
|
||||
|
||||
.. versionadded:: 0.16.4
|
||||
.. deprecated:: 2014.7.0
|
||||
'''
|
||||
if delim is not None:
|
||||
salt.utils.warn_until(
|
||||
'Beryllium',
|
||||
'The \'delim\' argument to match.pillar_pcre has been deprecated '
|
||||
'and will be removed in a future release. Please use '
|
||||
'\'delimiter\' instead.'
|
||||
)
|
||||
delimiter = delim
|
||||
|
||||
matcher = salt.minion.Matcher({'pillar': __pillar__}, __salt__)
|
||||
try:
|
||||
return matcher.pillar_pcre_match(tgt, delimiter=delimiter)
|
||||
except Exception as exc:
|
||||
log.exception(exc)
|
||||
return False
|
||||
|
||||
|
||||
def pillar(tgt, delimiter=DEFAULT_TARGET_DELIM, delim=None):
|
||||
'''
|
||||
Return True if the minion matches the given pillar target. The
|
||||
|
|
|
@ -213,6 +213,7 @@ def get(tgt, fun, expr_form='glob'):
|
|||
grain_pcre
|
||||
compound
|
||||
pillar
|
||||
pillar_pcre
|
||||
|
||||
Note that all pillar matches, whether using the compound matching system or
|
||||
the pillar matching system, will be exact matches, with globbing disabled.
|
||||
|
@ -235,6 +236,7 @@ def get(tgt, fun, expr_form='glob'):
|
|||
'ipcidr': __salt__['match.ipcidr'],
|
||||
'compound': __salt__['match.compound'],
|
||||
'pillar': __salt__['match.pillar'],
|
||||
'pillar_pcre': __salt__['match.pillar_pcre'],
|
||||
}[expr_form](tgt)
|
||||
if is_target:
|
||||
data = __salt__['data.getval']('mine_cache')
|
||||
|
|
|
@ -160,6 +160,7 @@ def publish(tgt, fun, arg=None, expr_form='glob', returner='', timeout=5):
|
|||
- grain
|
||||
- grain_pcre
|
||||
- pillar
|
||||
- pillar_pcre
|
||||
- ipcidr
|
||||
- range
|
||||
- compound
|
||||
|
|
|
@ -120,6 +120,7 @@ def publish(tgt, fun, arg=None, expr_form='glob', returner='', timeout=5):
|
|||
- grain
|
||||
- grain_pcre
|
||||
- pillar
|
||||
- pillar_pcre
|
||||
- ipcidr
|
||||
- range
|
||||
- compound
|
||||
|
|
|
@ -219,6 +219,16 @@ class CkMinions(object):
|
|||
'''
|
||||
return self._check_cache_minions(expr, delimiter, greedy, 'pillar')
|
||||
|
||||
def _check_pillar_pcre_minions(self, expr, delimiter, greedy):
|
||||
'''
|
||||
Return the minions found by looking via pillar with PCRE
|
||||
'''
|
||||
return self._check_cache_minions(expr,
|
||||
delimiter,
|
||||
greedy,
|
||||
'pillar',
|
||||
regex_match=True)
|
||||
|
||||
def _check_pillar_exact_minions(self, expr, delimiter, greedy):
|
||||
'''
|
||||
Return the minions found by looking via pillar
|
||||
|
@ -360,6 +370,7 @@ class CkMinions(object):
|
|||
ref = {'G': self._check_grain_minions,
|
||||
'P': self._check_grain_pcre_minions,
|
||||
'I': self._check_pillar_minions,
|
||||
'J': self._check_pillar_pcre_minions,
|
||||
'L': self._check_list_minions,
|
||||
'S': self._check_ipcidr_minions,
|
||||
'E': self._check_pcre_minions,
|
||||
|
@ -372,13 +383,13 @@ class CkMinions(object):
|
|||
tokens = expr.split()
|
||||
for match in tokens:
|
||||
# Try to match tokens from the compound target, first by using
|
||||
# the 'G, X, I, L, S, E' matcher types, then by hostname glob.
|
||||
# the 'G, X, I, J, L, S, E' matcher types, then by hostname glob.
|
||||
if '@' in match and match[1] == '@':
|
||||
comps = match.split('@')
|
||||
matcher = ref.get(comps[0])
|
||||
|
||||
matcher_args = ['@'.join(comps[1:])]
|
||||
if comps[0] in ('G', 'P', 'I'):
|
||||
if comps[0] in ('G', 'P', 'I', 'J'):
|
||||
matcher_args.append(delimiter)
|
||||
matcher_args.append(True)
|
||||
|
||||
|
@ -532,6 +543,7 @@ class CkMinions(object):
|
|||
ref = {'G': 'grain',
|
||||
'P': 'grain_pcre',
|
||||
'I': 'pillar',
|
||||
'J': 'pillar_pcre',
|
||||
'L': 'list',
|
||||
'S': 'ipcidr',
|
||||
'E': 'pcre',
|
||||
|
@ -539,7 +551,8 @@ class CkMinions(object):
|
|||
infinite = [
|
||||
'node',
|
||||
'ipcidr',
|
||||
'pillar']
|
||||
'pillar',
|
||||
'pillar_pcre']
|
||||
if not self.opts.get('minion_data_cache', False):
|
||||
infinite.append('grain')
|
||||
infinite.append('grain_pcre')
|
||||
|
@ -612,7 +625,7 @@ class CkMinions(object):
|
|||
'''
|
||||
if publish_validate:
|
||||
v_tgt_type = tgt_type
|
||||
if tgt_type.lower() == 'pillar':
|
||||
if tgt_type.lower() in ('pillar', 'pillar_pcre'):
|
||||
v_tgt_type = 'pillar_exact'
|
||||
elif tgt_type.lower() == 'compound':
|
||||
v_tgt_type = 'compound_pillar_exact'
|
||||
|
@ -620,7 +633,8 @@ class CkMinions(object):
|
|||
minions = set(self.check_minions(tgt, tgt_type))
|
||||
mismatch = bool(minions.difference(v_minions))
|
||||
# If the non-exact match gets more minions than the exact match
|
||||
# then pillar globbing is being used, and we have a problem
|
||||
# then pillar globbing or PCRE is being used, and we have a
|
||||
# problem
|
||||
if mismatch:
|
||||
return False
|
||||
# compound commands will come in a list so treat everything as a list
|
||||
|
|
|
@ -938,6 +938,15 @@ class ExtendedTargetOptionsMixIn(TargetOptionsMixIn):
|
|||
'for the target is the pillar key followed by a glob'
|
||||
'expression:\n"role:production*"')
|
||||
)
|
||||
group.add_option(
|
||||
'-J', '--pillar-pcre',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=('Instead of using shell globs to evaluate the target '
|
||||
'use a pillar value to identify targets, the syntax '
|
||||
'for the target is the pillar key followed by a pcre'
|
||||
'regular expression:\n"role:prod.*"')
|
||||
)
|
||||
group.add_option(
|
||||
'-S', '--ipcidr',
|
||||
default=False,
|
||||
|
|
|
@ -191,6 +191,21 @@ class MatchTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn):
|
|||
self.assertIn('minion', data)
|
||||
self.assertIn('sub_minion', data)
|
||||
|
||||
def test_repillar(self):
|
||||
'''
|
||||
test salt pillar PCRE matcher
|
||||
'''
|
||||
data = self.run_salt(
|
||||
'-t 1 --pillar-pcre "monty:^(python|hall)$" test.ping'
|
||||
)
|
||||
data = '\n'.join(data)
|
||||
self.assertIn('minion', data)
|
||||
self.assertNotIn('sub_minion', data)
|
||||
data = self.run_salt('--pillar-pcre "knights:^(Robin|Lancelot)$" test.ping')
|
||||
data = '\n'.join(data)
|
||||
self.assertIn('sub_minion', data)
|
||||
self.assertNotIn('minion', data.replace('sub_minion', 'stub'))
|
||||
|
||||
def test_ipcidr(self):
|
||||
subnets_data = self.run_salt('--out yaml \'*\' network.subnets')
|
||||
yaml_data = yaml.load('\n'.join(subnets_data))
|
||||
|
|
Loading…
Add table
Reference in a new issue