mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge pull request #43188 from alexbleotu/ext_pillar_config_param-gh
Ext pillar config param gh
This commit is contained in:
commit
0e42e8f9cc
@ -2113,6 +2113,41 @@ It will be interpreted as megabytes.
|
||||
|
||||
file_recv_max_size: 100
|
||||
|
||||
.. conf_minion:: pass_to_ext_pillars
|
||||
|
||||
``pass_to_ext_pillars``
|
||||
-----------------------
|
||||
|
||||
Specify a list of configuration keys whose values are to be passed to
|
||||
external pillar functions.
|
||||
|
||||
Suboptions can be specified using the ':' notation (i.e. ``option:suboption``)
|
||||
|
||||
The values are merged and included in the ``extra_minion_data`` optional
|
||||
parameter of the external pillar function. The ``extra_minion_data`` parameter
|
||||
is passed only to the external pillar functions that have it explicitly
|
||||
specified in their definition.
|
||||
|
||||
If the config contains
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
opt1: value1
|
||||
opt2:
|
||||
subopt1: value2
|
||||
subopt2: value3
|
||||
|
||||
pass_to_ext_pillars:
|
||||
- opt1
|
||||
- opt2: subopt1
|
||||
|
||||
the ``extra_minion_data`` parameter will be
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{'opt1': 'value1',
|
||||
'opt2': {'subopt1': 'value2'}}
|
||||
|
||||
Security Settings
|
||||
=================
|
||||
|
||||
|
@ -1080,6 +1080,11 @@ VALID_OPTS = {
|
||||
# (in other words, require that minions have 'minion_sign_messages'
|
||||
# turned on)
|
||||
'require_minion_sign_messages': bool,
|
||||
|
||||
# The list of config entries to be passed to external pillar function as
|
||||
# part of the extra_minion_data param
|
||||
# Subconfig entries can be specified by using the ':' notation (e.g. key:subkey)
|
||||
'pass_to_ext_pillars': (six.string_types, list),
|
||||
}
|
||||
|
||||
# default configurations
|
||||
|
@ -1311,7 +1311,8 @@ class AESFuncs(object):
|
||||
load.get(u'saltenv', load.get(u'env')),
|
||||
ext=load.get(u'ext'),
|
||||
pillar_override=load.get(u'pillar_override', {}),
|
||||
pillarenv=load.get(u'pillarenv'))
|
||||
pillarenv=load.get(u'pillarenv'),
|
||||
extra_minion_data=load.get(u'extra_minion_data'))
|
||||
data = pillar.compile_pillar()
|
||||
self.fs_.update_opts()
|
||||
if self.opts.get(u'minion_data_cache', False):
|
||||
|
@ -13,6 +13,7 @@ import logging
|
||||
import tornado.gen
|
||||
import sys
|
||||
import traceback
|
||||
import inspect
|
||||
|
||||
# Import salt libs
|
||||
import salt.loader
|
||||
@ -23,6 +24,8 @@ import salt.transport
|
||||
import salt.utils.url
|
||||
import salt.utils.cache
|
||||
import salt.utils.crypt
|
||||
import salt.utils.dictupdate
|
||||
import salt.utils.args
|
||||
from salt.exceptions import SaltClientError
|
||||
from salt.template import compile_template
|
||||
from salt.utils.dictupdate import merge
|
||||
@ -36,7 +39,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_pillar(opts, grains, minion_id, saltenv=None, ext=None, funcs=None,
|
||||
pillar_override=None, pillarenv=None):
|
||||
pillar_override=None, pillarenv=None, extra_minion_data=None):
|
||||
'''
|
||||
Return the correct pillar driver based on the file_client option
|
||||
'''
|
||||
@ -55,12 +58,14 @@ def get_pillar(opts, grains, minion_id, saltenv=None, ext=None, funcs=None,
|
||||
return PillarCache(opts, grains, minion_id, saltenv, ext=ext, functions=funcs,
|
||||
pillar_override=pillar_override, pillarenv=pillarenv)
|
||||
return ptype(opts, grains, minion_id, saltenv, ext, functions=funcs,
|
||||
pillar_override=pillar_override, pillarenv=pillarenv)
|
||||
pillar_override=pillar_override, pillarenv=pillarenv,
|
||||
extra_minion_data=extra_minion_data)
|
||||
|
||||
|
||||
# TODO: migrate everyone to this one!
|
||||
def get_async_pillar(opts, grains, minion_id, saltenv=None, ext=None, funcs=None,
|
||||
pillar_override=None, pillarenv=None):
|
||||
pillar_override=None, pillarenv=None,
|
||||
extra_minion_data=None):
|
||||
'''
|
||||
Return the correct pillar driver based on the file_client option
|
||||
'''
|
||||
@ -72,15 +77,62 @@ def get_async_pillar(opts, grains, minion_id, saltenv=None, ext=None, funcs=None
|
||||
'local': AsyncPillar,
|
||||
}.get(file_client, AsyncPillar)
|
||||
return ptype(opts, grains, minion_id, saltenv, ext, functions=funcs,
|
||||
pillar_override=pillar_override, pillarenv=pillarenv)
|
||||
pillar_override=pillar_override, pillarenv=pillarenv,
|
||||
extra_minion_data=extra_minion_data)
|
||||
|
||||
|
||||
class AsyncRemotePillar(object):
|
||||
class RemotePillarMixin(object):
|
||||
'''
|
||||
Common remote pillar functionality
|
||||
'''
|
||||
def get_ext_pillar_extra_minion_data(self, opts):
|
||||
'''
|
||||
Returns the extra data from the minion's opts dict (the config file).
|
||||
|
||||
This data will be passed to external pillar functions.
|
||||
'''
|
||||
def get_subconfig(opts_key):
|
||||
'''
|
||||
Returns a dict containing the opts key subtree, while maintaining
|
||||
the opts structure
|
||||
'''
|
||||
ret_dict = aux_dict = {}
|
||||
config_val = opts
|
||||
subkeys = opts_key.split(':')
|
||||
# Build an empty dict with the opts path
|
||||
for subkey in subkeys[:-1]:
|
||||
aux_dict[subkey] = {}
|
||||
aux_dict = aux_dict[subkey]
|
||||
if not config_val.get(subkey):
|
||||
# The subkey is not in the config
|
||||
return {}
|
||||
config_val = config_val[subkey]
|
||||
if subkeys[-1] not in config_val:
|
||||
return {}
|
||||
aux_dict[subkeys[-1]] = config_val[subkeys[-1]]
|
||||
return ret_dict
|
||||
|
||||
extra_data = {}
|
||||
if 'pass_to_ext_pillars' in opts:
|
||||
if not isinstance(opts['pass_to_ext_pillars'], list):
|
||||
log.exception('\'pass_to_ext_pillars\' config is malformed.')
|
||||
raise SaltClientError('\'pass_to_ext_pillars\' config is '
|
||||
'malformed.')
|
||||
for key in opts['pass_to_ext_pillars']:
|
||||
salt.utils.dictupdate.update(extra_data,
|
||||
get_subconfig(key),
|
||||
recursive_update=True,
|
||||
merge_lists=True)
|
||||
log.trace('ext_pillar_extra_data = {0}'.format(extra_data))
|
||||
return extra_data
|
||||
|
||||
|
||||
class AsyncRemotePillar(RemotePillarMixin):
|
||||
'''
|
||||
Get the pillar from the master
|
||||
'''
|
||||
def __init__(self, opts, grains, minion_id, saltenv, ext=None, functions=None,
|
||||
pillar_override=None, pillarenv=None):
|
||||
pillar_override=None, pillarenv=None, extra_minion_data=None):
|
||||
self.opts = opts
|
||||
self.opts['environment'] = saltenv
|
||||
self.ext = ext
|
||||
@ -93,6 +145,14 @@ class AsyncRemotePillar(object):
|
||||
if not isinstance(self.pillar_override, dict):
|
||||
self.pillar_override = {}
|
||||
log.error('Pillar data must be a dictionary')
|
||||
self.extra_minion_data = extra_minion_data or {}
|
||||
if not isinstance(self.extra_minion_data, dict):
|
||||
self.extra_minion_data = {}
|
||||
log.error('Extra minion data must be a dictionary')
|
||||
salt.utils.dictupdate.update(self.extra_minion_data,
|
||||
self.get_ext_pillar_extra_minion_data(opts),
|
||||
recursive_update=True,
|
||||
merge_lists=True)
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def compile_pillar(self):
|
||||
@ -104,6 +164,7 @@ class AsyncRemotePillar(object):
|
||||
'saltenv': self.opts['environment'],
|
||||
'pillarenv': self.opts['pillarenv'],
|
||||
'pillar_override': self.pillar_override,
|
||||
'extra_minion_data': self.extra_minion_data,
|
||||
'ver': '2',
|
||||
'cmd': '_pillar'}
|
||||
if self.ext:
|
||||
@ -126,12 +187,12 @@ class AsyncRemotePillar(object):
|
||||
raise tornado.gen.Return(ret_pillar)
|
||||
|
||||
|
||||
class RemotePillar(object):
|
||||
class RemotePillar(RemotePillarMixin):
|
||||
'''
|
||||
Get the pillar from the master
|
||||
'''
|
||||
def __init__(self, opts, grains, minion_id, saltenv, ext=None, functions=None,
|
||||
pillar_override=None, pillarenv=None):
|
||||
pillar_override=None, pillarenv=None, extra_minion_data=None):
|
||||
self.opts = opts
|
||||
self.opts['environment'] = saltenv
|
||||
self.ext = ext
|
||||
@ -144,6 +205,14 @@ class RemotePillar(object):
|
||||
if not isinstance(self.pillar_override, dict):
|
||||
self.pillar_override = {}
|
||||
log.error('Pillar data must be a dictionary')
|
||||
self.extra_minion_data = extra_minion_data or {}
|
||||
if not isinstance(self.extra_minion_data, dict):
|
||||
self.extra_minion_data = {}
|
||||
log.error('Extra minion data must be a dictionary')
|
||||
salt.utils.dictupdate.update(self.extra_minion_data,
|
||||
self.get_ext_pillar_extra_minion_data(opts),
|
||||
recursive_update=True,
|
||||
merge_lists=True)
|
||||
|
||||
def compile_pillar(self):
|
||||
'''
|
||||
@ -154,6 +223,7 @@ class RemotePillar(object):
|
||||
'saltenv': self.opts['environment'],
|
||||
'pillarenv': self.opts['pillarenv'],
|
||||
'pillar_override': self.pillar_override,
|
||||
'extra_minion_data': self.extra_minion_data,
|
||||
'ver': '2',
|
||||
'cmd': '_pillar'}
|
||||
if self.ext:
|
||||
@ -187,7 +257,7 @@ class PillarCache(object):
|
||||
'''
|
||||
# TODO ABC?
|
||||
def __init__(self, opts, grains, minion_id, saltenv, ext=None, functions=None,
|
||||
pillar_override=None, pillarenv=None):
|
||||
pillar_override=None, pillarenv=None, extra_minion_data=None):
|
||||
# Yes, we need all of these because we need to route to the Pillar object
|
||||
# if we have no cache. This is another refactor target.
|
||||
|
||||
@ -265,7 +335,7 @@ class Pillar(object):
|
||||
Read over the pillar top files and render the pillar data
|
||||
'''
|
||||
def __init__(self, opts, grains, minion_id, saltenv, ext=None, functions=None,
|
||||
pillar_override=None, pillarenv=None):
|
||||
pillar_override=None, pillarenv=None, extra_minion_data=None):
|
||||
self.minion_id = minion_id
|
||||
self.ext = ext
|
||||
if pillarenv is None:
|
||||
@ -311,6 +381,10 @@ class Pillar(object):
|
||||
if not isinstance(self.pillar_override, dict):
|
||||
self.pillar_override = {}
|
||||
log.error('Pillar data must be a dictionary')
|
||||
self.extra_minion_data = extra_minion_data or {}
|
||||
if not isinstance(self.extra_minion_data, dict):
|
||||
self.extra_minion_data = {}
|
||||
log.error('Extra minion data must be a dictionary')
|
||||
|
||||
def __valid_on_demand_ext_pillar(self, opts):
|
||||
'''
|
||||
@ -768,17 +842,35 @@ class Pillar(object):
|
||||
Builds actual pillar data structure and updates the ``pillar`` variable
|
||||
'''
|
||||
ext = None
|
||||
args = salt.utils.args.get_function_argspec(self.ext_pillars[key]).args
|
||||
|
||||
if isinstance(val, dict):
|
||||
ext = self.ext_pillars[key](self.minion_id, pillar, **val)
|
||||
if ('extra_minion_data' in args) and self.extra_minion_data:
|
||||
ext = self.ext_pillars[key](
|
||||
self.minion_id, pillar,
|
||||
extra_minion_data=self.extra_minion_data, **val)
|
||||
else:
|
||||
ext = self.ext_pillars[key](self.minion_id, pillar, **val)
|
||||
elif isinstance(val, list):
|
||||
ext = self.ext_pillars[key](self.minion_id,
|
||||
pillar,
|
||||
*val)
|
||||
if ('extra_minion_data' in args) and self.extra_minion_data:
|
||||
ext = self.ext_pillars[key](
|
||||
self.minion_id, pillar, *val,
|
||||
extra_minion_data=self.extra_minion_data)
|
||||
else:
|
||||
ext = self.ext_pillars[key](self.minion_id,
|
||||
pillar,
|
||||
*val)
|
||||
else:
|
||||
ext = self.ext_pillars[key](self.minion_id,
|
||||
pillar,
|
||||
val)
|
||||
if ('extra_minion_data' in args) and self.extra_minion_data:
|
||||
ext = self.ext_pillars[key](
|
||||
self.minion_id,
|
||||
pillar,
|
||||
val,
|
||||
extra_minion_data=self.extra_minion_data)
|
||||
else:
|
||||
ext = self.ext_pillars[key](self.minion_id,
|
||||
pillar,
|
||||
val)
|
||||
return ext
|
||||
|
||||
def ext_pillar(self, pillar, errors=None):
|
||||
|
@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
:codeauthor: :email:`Pedro Algarvio (pedro@algarvio.me)`
|
||||
:codeauthor: :email:`Alexandru Bleotu (alexandru.bleotu@morganstanley.com)`
|
||||
|
||||
|
||||
tests.unit.pillar_test
|
||||
@ -19,6 +20,7 @@ from tests.support.paths import TMP
|
||||
# Import salt libs
|
||||
import salt.pillar
|
||||
import salt.utils.stringutils
|
||||
import salt.exceptions
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@ -56,6 +58,244 @@ class PillarTestCase(TestCase):
|
||||
self.assertEqual(pillar.opts['environment'], 'dev')
|
||||
self.assertEqual(pillar.opts['pillarenv'], 'dev')
|
||||
|
||||
def test_ext_pillar_no_extra_minion_data_val_dict(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'renderer_blacklist': [],
|
||||
'renderer_whitelist': [],
|
||||
'state_top': '',
|
||||
'pillar_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'file_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'extension_modules': '',
|
||||
'pillarenv_from_saltenv': True
|
||||
}
|
||||
mock_ext_pillar_func = MagicMock()
|
||||
with patch('salt.loader.pillars',
|
||||
MagicMock(return_value={'fake_ext_pillar':
|
||||
mock_ext_pillar_func})):
|
||||
pillar = salt.pillar.Pillar(opts, {}, 'mocked-minion', 'dev')
|
||||
# ext pillar function doesn't have the extra_minion_data arg
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=[]))):
|
||||
pillar._external_pillar_data('fake_pillar', {'arg': 'foo'},
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with('mocked-minion',
|
||||
'fake_pillar',
|
||||
arg='foo')
|
||||
# ext pillar function has the extra_minion_data arg
|
||||
mock_ext_pillar_func.reset_mock()
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=['extra_minion_data']))):
|
||||
pillar._external_pillar_data('fake_pillar', {'arg': 'foo'},
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with('mocked-minion',
|
||||
'fake_pillar',
|
||||
arg='foo')
|
||||
|
||||
def test_ext_pillar_no_extra_minion_data_val_list(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'renderer_blacklist': [],
|
||||
'renderer_whitelist': [],
|
||||
'state_top': '',
|
||||
'pillar_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'file_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'extension_modules': '',
|
||||
'pillarenv_from_saltenv': True
|
||||
}
|
||||
mock_ext_pillar_func = MagicMock()
|
||||
with patch('salt.loader.pillars',
|
||||
MagicMock(return_value={'fake_ext_pillar':
|
||||
mock_ext_pillar_func})):
|
||||
pillar = salt.pillar.Pillar(opts, {}, 'mocked-minion', 'dev')
|
||||
# ext pillar function doesn't have the extra_minion_data arg
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=[]))):
|
||||
pillar._external_pillar_data('fake_pillar', ['foo'],
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with('mocked-minion',
|
||||
'fake_pillar',
|
||||
'foo')
|
||||
# ext pillar function has the extra_minion_data arg
|
||||
mock_ext_pillar_func.reset_mock()
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=['extra_minion_data']))):
|
||||
pillar._external_pillar_data('fake_pillar', ['foo'],
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with('mocked-minion',
|
||||
'fake_pillar',
|
||||
'foo')
|
||||
|
||||
def test_ext_pillar_no_extra_minion_data_val_elem(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'renderer_blacklist': [],
|
||||
'renderer_whitelist': [],
|
||||
'state_top': '',
|
||||
'pillar_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'file_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'extension_modules': '',
|
||||
'pillarenv_from_saltenv': True
|
||||
}
|
||||
mock_ext_pillar_func = MagicMock()
|
||||
with patch('salt.loader.pillars',
|
||||
MagicMock(return_value={'fake_ext_pillar':
|
||||
mock_ext_pillar_func})):
|
||||
pillar = salt.pillar.Pillar(opts, {}, 'mocked-minion', 'dev')
|
||||
# ext pillar function doesn't have the extra_minion_data arg
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=[]))):
|
||||
pillar._external_pillar_data('fake_pillar', 'fake_val',
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with('mocked-minion',
|
||||
'fake_pillar', 'fake_val')
|
||||
# ext pillar function has the extra_minion_data arg
|
||||
mock_ext_pillar_func.reset_mock()
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=['extra_minion_data']))):
|
||||
pillar._external_pillar_data('fake_pillar', 'fake_val',
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with('mocked-minion',
|
||||
'fake_pillar', 'fake_val')
|
||||
|
||||
def test_ext_pillar_with_extra_minion_data_val_dict(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'renderer_blacklist': [],
|
||||
'renderer_whitelist': [],
|
||||
'state_top': '',
|
||||
'pillar_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'file_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'extension_modules': '',
|
||||
'pillarenv_from_saltenv': True
|
||||
}
|
||||
mock_ext_pillar_func = MagicMock()
|
||||
with patch('salt.loader.pillars',
|
||||
MagicMock(return_value={'fake_ext_pillar':
|
||||
mock_ext_pillar_func})):
|
||||
pillar = salt.pillar.Pillar(opts, {}, 'mocked-minion', 'dev',
|
||||
extra_minion_data={'fake_key': 'foo'})
|
||||
# ext pillar function doesn't have the extra_minion_data arg
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=[]))):
|
||||
pillar._external_pillar_data('fake_pillar', {'arg': 'foo'},
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with(
|
||||
'mocked-minion', 'fake_pillar', arg='foo')
|
||||
# ext pillar function has the extra_minion_data arg
|
||||
mock_ext_pillar_func.reset_mock()
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=['extra_minion_data']))):
|
||||
pillar._external_pillar_data('fake_pillar', {'arg': 'foo'},
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with(
|
||||
'mocked-minion', 'fake_pillar', arg='foo',
|
||||
extra_minion_data={'fake_key': 'foo'})
|
||||
|
||||
def test_ext_pillar_with_extra_minion_data_val_list(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'renderer_blacklist': [],
|
||||
'renderer_whitelist': [],
|
||||
'state_top': '',
|
||||
'pillar_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'file_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'extension_modules': '',
|
||||
'pillarenv_from_saltenv': True
|
||||
}
|
||||
mock_ext_pillar_func = MagicMock()
|
||||
with patch('salt.loader.pillars',
|
||||
MagicMock(return_value={'fake_ext_pillar':
|
||||
mock_ext_pillar_func})):
|
||||
pillar = salt.pillar.Pillar(opts, {}, 'mocked-minion', 'dev',
|
||||
extra_minion_data={'fake_key': 'foo'})
|
||||
# ext pillar function doesn't have the extra_minion_data arg
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=[]))):
|
||||
pillar._external_pillar_data('fake_pillar', ['bar'],
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with(
|
||||
'mocked-minion', 'fake_pillar', 'bar')
|
||||
# ext pillar function has the extra_minion_data arg
|
||||
mock_ext_pillar_func.reset_mock()
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=['extra_minion_data']))):
|
||||
pillar._external_pillar_data('fake_pillar', ['bar'],
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with(
|
||||
'mocked-minion', 'fake_pillar', 'bar',
|
||||
extra_minion_data={'fake_key': 'foo'})
|
||||
|
||||
def test_ext_pillar_with_extra_minion_data_val_elem(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'renderer_blacklist': [],
|
||||
'renderer_whitelist': [],
|
||||
'state_top': '',
|
||||
'pillar_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'file_roots': {
|
||||
'dev': [],
|
||||
'base': []
|
||||
},
|
||||
'extension_modules': '',
|
||||
'pillarenv_from_saltenv': True
|
||||
}
|
||||
mock_ext_pillar_func = MagicMock()
|
||||
with patch('salt.loader.pillars',
|
||||
MagicMock(return_value={'fake_ext_pillar':
|
||||
mock_ext_pillar_func})):
|
||||
pillar = salt.pillar.Pillar(opts, {}, 'mocked-minion', 'dev',
|
||||
extra_minion_data={'fake_key': 'foo'})
|
||||
# ext pillar function doesn't have the extra_minion_data arg
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=[]))):
|
||||
pillar._external_pillar_data('fake_pillar', 'bar',
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with(
|
||||
'mocked-minion', 'fake_pillar', 'bar')
|
||||
# ext pillar function has the extra_minion_data arg
|
||||
mock_ext_pillar_func.reset_mock()
|
||||
with patch('salt.utils.args.get_function_argspec',
|
||||
MagicMock(return_value=MagicMock(args=['extra_minion_data']))):
|
||||
pillar._external_pillar_data('fake_pillar', 'bar',
|
||||
'fake_ext_pillar')
|
||||
mock_ext_pillar_func.assert_called_once_with(
|
||||
'mocked-minion', 'fake_pillar', 'bar',
|
||||
extra_minion_data={'fake_key': 'foo'})
|
||||
|
||||
def test_malformed_pillar_sls(self):
|
||||
with patch('salt.pillar.compile_template') as compile_template:
|
||||
opts = {
|
||||
@ -318,3 +558,174 @@ p2:
|
||||
}[sls]
|
||||
|
||||
client.get_state.side_effect = get_state
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@patch('salt.transport.Channel.factory', MagicMock())
|
||||
class RemotePillarTestCase(TestCase):
|
||||
'''
|
||||
Tests for instantiating a RemotePillar in salt.pillar
|
||||
'''
|
||||
def setUp(self):
|
||||
self.grains = {}
|
||||
|
||||
def tearDown(self):
|
||||
for attr in ('grains',):
|
||||
try:
|
||||
delattr(self, attr)
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
def test_get_opts_in_pillar_override_call(self):
|
||||
mock_get_extra_minion_data = MagicMock(return_value={})
|
||||
with patch(
|
||||
'salt.pillar.RemotePillarMixin.get_ext_pillar_extra_minion_data',
|
||||
mock_get_extra_minion_data):
|
||||
|
||||
salt.pillar.RemotePillar({}, self.grains, 'mocked-minion', 'dev')
|
||||
mock_get_extra_minion_data.assert_called_once_with(
|
||||
{'environment': 'dev'})
|
||||
|
||||
def test_multiple_keys_in_opts_added_to_pillar(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data2': ['fake_data3', 'fake_data4']},
|
||||
'pass_to_ext_pillars': ['path_to_add', 'path_to_add2']
|
||||
}
|
||||
pillar = salt.pillar.RemotePillar(opts, self.grains,
|
||||
'mocked-minion', 'dev')
|
||||
self.assertEqual(pillar.extra_minion_data,
|
||||
{'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data2': ['fake_data3',
|
||||
'fake_data4']}})
|
||||
|
||||
def test_subkey_in_opts_added_to_pillar(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data5': 'fake_data6',
|
||||
'fake_data2': ['fake_data3', 'fake_data4']},
|
||||
'pass_to_ext_pillars': ['path_to_add2:fake_data5']
|
||||
}
|
||||
pillar = salt.pillar.RemotePillar(opts, self.grains,
|
||||
'mocked-minion', 'dev')
|
||||
self.assertEqual(pillar.extra_minion_data,
|
||||
{'path_to_add2': {'fake_data5': 'fake_data6'}})
|
||||
|
||||
def test_non_existent_leaf_opt_in_add_to_pillar(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data5': 'fake_data6',
|
||||
'fake_data2': ['fake_data3', 'fake_data4']},
|
||||
'pass_to_ext_pillars': ['path_to_add2:fake_data_non_exist']
|
||||
}
|
||||
pillar = salt.pillar.RemotePillar(opts, self.grains,
|
||||
'mocked-minion', 'dev')
|
||||
self.assertEqual(pillar.pillar_override, {})
|
||||
|
||||
def test_non_existent_intermediate_opt_in_add_to_pillar(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data5': 'fake_data6',
|
||||
'fake_data2': ['fake_data3', 'fake_data4']},
|
||||
'pass_to_ext_pillars': ['path_to_add_no_exist']
|
||||
}
|
||||
pillar = salt.pillar.RemotePillar(opts, self.grains,
|
||||
'mocked-minion', 'dev')
|
||||
self.assertEqual(pillar.pillar_override, {})
|
||||
|
||||
def test_malformed_add_to_pillar(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data5': 'fake_data6',
|
||||
'fake_data2': ['fake_data3', 'fake_data4']},
|
||||
'pass_to_ext_pillars': MagicMock()
|
||||
}
|
||||
with self.assertRaises(salt.exceptions.SaltClientError) as excinfo:
|
||||
salt.pillar.RemotePillar(opts, self.grains, 'mocked-minion', 'dev')
|
||||
self.assertEqual(excinfo.exception.strerror,
|
||||
'\'pass_to_ext_pillars\' config is malformed.')
|
||||
|
||||
def test_pillar_send_extra_minion_data_from_config(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'pillarenv': 'fake_pillar_env',
|
||||
'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data5': 'fake_data6',
|
||||
'fake_data2': ['fake_data3', 'fake_data4']},
|
||||
'pass_to_ext_pillars': ['path_to_add']}
|
||||
mock_channel = MagicMock(
|
||||
crypted_transfer_decode_dictentry=MagicMock(return_value={}))
|
||||
with patch('salt.transport.Channel.factory',
|
||||
MagicMock(return_value=mock_channel)):
|
||||
pillar = salt.pillar.RemotePillar(opts, self.grains,
|
||||
'mocked_minion', 'fake_env')
|
||||
|
||||
ret = pillar.compile_pillar()
|
||||
self.assertEqual(pillar.channel, mock_channel)
|
||||
mock_channel.crypted_transfer_decode_dictentry.assert_called_once_with(
|
||||
{'cmd': '_pillar', 'ver': '2',
|
||||
'id': 'mocked_minion',
|
||||
'grains': {},
|
||||
'saltenv': 'fake_env',
|
||||
'pillarenv': 'fake_pillar_env',
|
||||
'pillar_override': {},
|
||||
'extra_minion_data': {'path_to_add': 'fake_data'}},
|
||||
dictkey='pillar')
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@patch('salt.transport.client.AsyncReqChannel.factory', MagicMock())
|
||||
class AsyncRemotePillarTestCase(TestCase):
|
||||
'''
|
||||
Tests for instantiating a AsyncRemotePillar in salt.pillar
|
||||
'''
|
||||
def setUp(self):
|
||||
self.grains = {}
|
||||
|
||||
def tearDown(self):
|
||||
for attr in ('grains',):
|
||||
try:
|
||||
delattr(self, attr)
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
def test_get_opts_in_pillar_override_call(self):
|
||||
mock_get_extra_minion_data = MagicMock(return_value={})
|
||||
with patch(
|
||||
'salt.pillar.RemotePillarMixin.get_ext_pillar_extra_minion_data',
|
||||
mock_get_extra_minion_data):
|
||||
|
||||
salt.pillar.RemotePillar({}, self.grains, 'mocked-minion', 'dev')
|
||||
mock_get_extra_minion_data.assert_called_once_with(
|
||||
{'environment': 'dev'})
|
||||
|
||||
def test_pillar_send_extra_minion_data_from_config(self):
|
||||
opts = {
|
||||
'renderer': 'json',
|
||||
'pillarenv': 'fake_pillar_env',
|
||||
'path_to_add': 'fake_data',
|
||||
'path_to_add2': {'fake_data5': 'fake_data6',
|
||||
'fake_data2': ['fake_data3', 'fake_data4']},
|
||||
'pass_to_ext_pillars': ['path_to_add']}
|
||||
mock_channel = MagicMock(
|
||||
crypted_transfer_decode_dictentry=MagicMock(return_value={}))
|
||||
with patch('salt.transport.client.AsyncReqChannel.factory',
|
||||
MagicMock(return_value=mock_channel)):
|
||||
pillar = salt.pillar.RemotePillar(opts, self.grains,
|
||||
'mocked_minion', 'fake_env')
|
||||
|
||||
ret = pillar.compile_pillar()
|
||||
mock_channel.crypted_transfer_decode_dictentry.assert_called_once_with(
|
||||
{'cmd': '_pillar', 'ver': '2',
|
||||
'id': 'mocked_minion',
|
||||
'grains': {},
|
||||
'saltenv': 'fake_env',
|
||||
'pillarenv': 'fake_pillar_env',
|
||||
'pillar_override': {},
|
||||
'extra_minion_data': {'path_to_add': 'fake_data'}},
|
||||
dictkey='pillar')
|
||||
|
Loading…
Reference in New Issue
Block a user