Merge pull request #39727 from terminalmage/issue39627

salt.modules.state: check gathered pillar for errors instead of in-memory pillar
This commit is contained in:
Mike Place 2017-03-02 10:06:42 -07:00 committed by GitHub
commit 7dfc4b572a
4 changed files with 171 additions and 137 deletions

View File

@ -31,7 +31,7 @@ import salt.state
import salt.utils
import salt.utils.jid
import salt.utils.url
from salt.exceptions import SaltInvocationError
from salt.exceptions import CommandExecutionError, SaltInvocationError
from salt.runners.state import orchestrate as _orchestrate
# Import 3rd-party libs
@ -98,14 +98,15 @@ def _set_retcode(ret):
__context__['retcode'] = 2
def _check_pillar(kwargs):
def _check_pillar(kwargs, pillar=None):
'''
Check the pillar for errors, refuse to run the state if there are errors
in the pillar and return the pillar errors
'''
if kwargs.get('force'):
return True
if '_errors' in __pillar__:
pillar_dict = pillar if pillar is not None else __pillar__
if '_errors' in pillar_dict:
return False
return True
@ -379,6 +380,12 @@ def template(tem, queue=False, **kwargs):
if conflict is not None:
return conflict
st_ = salt.state.HighState(__opts__, context=__context__)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
raise CommandExecutionError('Pillar failed to render',
info=st_.opts['pillar']['_errors'])
if not tem.endswith('.sls'):
tem = '{sls}.sls'.format(sls=tem)
high_state, errors = st_.render_state(tem, saltenv, '', None, local=True)
@ -802,6 +809,12 @@ def highstate(test=None,
pillar_enc=pillar_enc,
mocked=kwargs.get('mock', False))
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
err = ['Pillar failed to render with the following messages:']
err += __pillar__['_errors']
return err
st_.push_active()
ret = {}
orchestration_jid = kwargs.get('orchestration_jid')
@ -967,11 +980,6 @@ def sls(mods,
__context__['retcode'] = 1
return disabled
if not _check_pillar(kwargs):
__context__['retcode'] = 5
err = ['Pillar failed to render with the following messages:']
err += __pillar__['_errors']
return err
orig_test = __opts__.get('test', None)
opts = _get_opts(kwargs.get('localconfig'))
@ -1007,6 +1015,12 @@ def sls(mods,
pillar_enc=pillar_enc,
mocked=kwargs.get('mock', False))
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
err = ['Pillar failed to render with the following messages:']
err += __pillar__['_errors']
return err
orchestration_jid = kwargs.get('orchestration_jid')
umask = os.umask(0o77)
if kwargs.get('cache'):
@ -1093,11 +1107,6 @@ def top(topfn,
conflict = _check_queue(queue, kwargs)
if conflict is not None:
return conflict
if not _check_pillar(kwargs):
__context__['retcode'] = 5
err = ['Pillar failed to render with the following messages:']
err += __pillar__['_errors']
return err
orig_test = __opts__.get('test', None)
opts = _get_opts(kwargs.get('localconfig'))
opts['test'] = _get_test_value(test, **kwargs)
@ -1113,6 +1122,12 @@ def top(topfn,
)
st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc, context=__context__)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
err = ['Pillar failed to render with the following messages:']
err += __pillar__['_errors']
return err
st_.push_active()
st_.opts['state_top'] = salt.utils.url.create(topfn)
ret = {}
@ -1163,6 +1178,12 @@ def show_highstate(queue=False, **kwargs):
)
st_ = salt.state.HighState(__opts__, pillar, pillar_enc=pillar_enc)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
raise CommandExecutionError('Pillar failed to render',
info=st_.opts['pillar']['_errors'])
st_.push_active()
try:
ret = st_.compile_highstate()
@ -1187,6 +1208,12 @@ def show_lowstate(queue=False, **kwargs):
assert False
return conflict
st_ = salt.state.HighState(__opts__)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
raise CommandExecutionError('Pillar failed to render',
info=st_.opts['pillar']['_errors'])
st_.push_active()
try:
ret = st_.compile_low_chunks()
@ -1227,6 +1254,13 @@ def sls_id(
st_ = salt.state.HighState(opts, proxy=__proxy__)
except NameError:
st_ = salt.state.HighState(opts)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
err = ['Pillar failed to render with the following messages:']
err += __pillar__['_errors']
return err
if isinstance(mods, six.string_types):
split_mods = mods.split(',')
st_.push_active()
@ -1289,6 +1323,12 @@ def show_low_sls(mods,
if 'pillarenv' in kwargs:
opts['pillarenv'] = kwargs['pillarenv']
st_ = salt.state.HighState(opts)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
raise CommandExecutionError('Pillar failed to render',
info=st_.opts['pillar']['_errors'])
if isinstance(mods, six.string_types):
mods = mods.split(',')
st_.push_active()
@ -1355,6 +1395,12 @@ def show_sls(mods, saltenv='base', test=None, queue=False, **kwargs):
opts['pillarenv'] = kwargs['pillarenv']
st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
raise CommandExecutionError('Pillar failed to render',
info=st_.opts['pillar']['_errors'])
if isinstance(mods, six.string_types):
mods = mods.split(',')
st_.push_active()
@ -1399,6 +1445,12 @@ def show_top(queue=False, **kwargs):
if conflict is not None:
return conflict
st_ = salt.state.HighState(opts)
if not _check_pillar(kwargs, st_.opts['pillar']):
__context__['retcode'] = 5
raise CommandExecutionError('Pillar failed to render',
info=st_.opts['pillar']['_errors'])
errors = []
top_ = st_.get_top()
errors += st_.verify_tops(top_)

View File

@ -824,7 +824,9 @@ class Pillar(object):
top, top_errors = self.get_top()
if ext:
if self.opts.get('ext_pillar_first', False):
self.opts['pillar'], errors = self.ext_pillar({}, pillar_dirs)
self.opts['pillar'], errors = self.ext_pillar(
self.pillar_override,
pillar_dirs)
self.rend = salt.loader.render(self.opts, self.functions)
matches = self.top_matches(top)
pillar, errors = self.render_pillar(matches, errors=errors)

View File

@ -459,6 +459,7 @@ def _process_stack_cfg(cfg, stack, minion_id, pillar, namespace):
for sub in namespace.split(':')[::-1]:
obj = {sub: obj}
stack = _merge_dict(stack, obj)
log.info('Stack template "{0}" parsed'.format(path))
except exceptions.TopLevelLookupException as e:
log.info('Stack template "{0}" not found.'.format(path))
continue

View File

@ -28,7 +28,7 @@ from salt.modules import state
# Globals
state.__salt__ = {}
state.__context__ = {}
state.__opts__ = {}
state.__opts__ = {'cachedir': '/D'}
state.__pillar__ = {}
@ -131,7 +131,8 @@ class MockState(object):
Mock HighState class
'''
flag = False
opts = {'state_top': ""}
opts = {'state_top': '',
'pillar': {}}
def __init__(self, opts, pillar=None, *args, **kwargs):
self.state = MockState.State(opts,
@ -465,16 +466,15 @@ class StateTestCase(TestCase):
'''
Test to clear out cached state file
'''
with patch.dict(state.__opts__, {"cachedir": "/D/"}):
mock = MagicMock(return_value=["A.cache.p", "B.cache.p", "C"])
with patch.object(os, 'listdir', mock):
mock = MagicMock(return_value=["A.cache.p", "B.cache.p", "C"])
with patch.object(os, 'listdir', mock):
mock = MagicMock(return_value=True)
with patch.object(os.path, 'isfile', mock):
mock = MagicMock(return_value=True)
with patch.object(os.path, 'isfile', mock):
mock = MagicMock(return_value=True)
with patch.object(os, 'remove', mock):
self.assertEqual(state.clear_cache(),
['A.cache.p',
'B.cache.p'])
with patch.object(os, 'remove', mock):
self.assertEqual(state.clear_cache(),
['A.cache.p',
'B.cache.p'])
def test_single(self):
'''
@ -537,11 +537,10 @@ class StateTestCase(TestCase):
mock = MagicMock(return_value=["True"])
with patch.object(state, 'apply_', mock):
with patch.dict(state.__opts__, {"cachedir": "/D/"}):
mock = MagicMock(return_value="")
with patch.object(os, 'remove', mock):
self.assertListEqual(state.run_request("name"),
["True"])
mock = MagicMock(return_value="")
with patch.object(os, 'remove', mock):
self.assertListEqual(state.run_request("name"),
["True"])
def test_show_highstate(self):
'''
@ -711,57 +710,53 @@ class StateTestCase(TestCase):
mock = MagicMock(return_value=True)
with patch.object(salt.payload, 'Serial',
mock):
with patch.dict(state.__opts__,
{"cachedir": "D"}):
with patch.object(os.path,
'join', mock):
with patch.object(
state,
'_set'
'_retcode',
mock):
self.assertTrue(state.
highstate
(arg))
with patch.object(os.path,
'join', mock):
with patch.object(
state,
'_set'
'_retcode',
mock):
self.assertTrue(state.
highstate
(arg))
def test_clear_request(self):
'''
Test to clear out the state execution request without executing it
'''
with patch.dict(state.__opts__, {"cachedir": "D"}):
mock = MagicMock(return_value=True)
with patch.object(os.path, 'join', mock):
mock = MagicMock(return_value=True)
with patch.object(os.path, 'join', mock):
mock = MagicMock(return_value=True)
with patch.object(salt.payload, 'Serial', mock):
mock = MagicMock(side_effect=[False, True, True])
with patch.object(os.path, 'isfile', mock):
self.assertTrue(state.clear_request("A"))
with patch.object(salt.payload, 'Serial', mock):
mock = MagicMock(side_effect=[False, True, True])
with patch.object(os.path, 'isfile', mock):
self.assertTrue(state.clear_request("A"))
mock = MagicMock(return_value=True)
with patch.object(os, 'remove', mock):
self.assertTrue(state.clear_request())
mock = MagicMock(return_value=True)
with patch.object(os, 'remove', mock):
self.assertTrue(state.clear_request())
mock = MagicMock(return_value={})
with patch.object(state, 'check_request', mock):
self.assertFalse(state.clear_request("A"))
mock = MagicMock(return_value={})
with patch.object(state, 'check_request', mock):
self.assertFalse(state.clear_request("A"))
@patch('salt.modules.state.salt.payload', MockSerial)
def test_check_request(self):
'''
Test to return the state request information
'''
with patch.dict(state.__opts__, {"cachedir": "D"}):
mock = MagicMock(return_value=True)
with patch.object(os.path, 'join', mock):
mock = MagicMock(side_effect=[True, True, False])
with patch.object(os.path, 'isfile', mock):
with patch('salt.utils.fopen', mock_open()):
self.assertDictEqual(state.check_request(), {'A': 'B'})
mock = MagicMock(return_value=True)
with patch.object(os.path, 'join', mock):
mock = MagicMock(side_effect=[True, True, False])
with patch.object(os.path, 'isfile', mock):
with patch('salt.utils.fopen', mock_open()):
self.assertDictEqual(state.check_request(), {'A': 'B'})
with patch('salt.utils.fopen', mock_open()):
self.assertEqual(state.check_request("A"), 'B')
with patch('salt.utils.fopen', mock_open()):
self.assertEqual(state.check_request("A"), 'B')
self.assertDictEqual(state.check_request(), {})
self.assertDictEqual(state.check_request(), {})
def test_request(self):
'''
@ -769,28 +764,21 @@ class StateTestCase(TestCase):
'''
mock = MagicMock(return_value=True)
with patch.object(state, 'apply_', mock):
with patch.dict(state.__opts__, {"cachedir": "D"}):
mock = MagicMock(return_value=True)
with patch.object(os.path, 'join', mock):
mock = MagicMock(return_value=
{"test_run": "",
"mods": "",
"kwargs": ""})
with patch.object(state, 'check_request', mock):
mock = MagicMock(return_value=True)
with patch.object(os, 'umask', mock):
with patch.object(salt.utils, 'is_windows', mock):
with patch.dict(state.__salt__,
{'cmd.run': mock}):
with patch('salt.utils.fopen',
mock_open()):
mock = MagicMock(
return_value=True)
with patch.object(os, 'umask',
mock):
self.assertTrue(
state.request("A")
)
mock = MagicMock(return_value=True)
with patch.object(os.path, 'join', mock):
mock = MagicMock(return_value=
{"test_run": "",
"mods": "",
"kwargs": ""})
with patch.object(state, 'check_request', mock):
mock = MagicMock(return_value=True)
with patch.object(os, 'umask', mock):
with patch.object(salt.utils, 'is_windows', mock):
with patch.dict(state.__salt__, {'cmd.run': mock}):
with patch('salt.utils.fopen', mock_open()):
mock = MagicMock(return_value=True)
with patch.object(os, 'umask', mock):
self.assertTrue(state.request("A"))
def test_sls(self):
'''
@ -847,59 +835,50 @@ class StateTestCase(TestCase):
True,
pillar="A")
with patch.dict(
state.__opts__,
{"cachedir": "/D/"}):
mock = MagicMock(return_value=
"/D/cache.cache.p")
mock = MagicMock(return_value="/D/cache.cache.p")
with patch.object(os.path,
'join',
mock):
mock = MagicMock(return_value=True)
with patch.object(os.path,
'join',
'isfile',
mock):
mock = MagicMock(return_value=True)
with patch.object(os.path,
'isfile',
with patch(
'salt.utils.fopen',
mock_open()):
self.assertTrue(
state.sls(arg,
None,
None,
None,
True,
cache
=True
)
)
MockState.HighState.flag = True
self.assertTrue(state.sls("core,edit"
".vim dev",
None,
None,
None,
True)
)
MockState.HighState.flag = False
mock = MagicMock(return_value=True)
with patch.dict(state.__salt__,
{'config.option':
mock}):
mock = MagicMock(return_value=
True)
with patch.object(
state,
'_filter_'
'running',
mock):
with patch(
'salt.utils.fopen',
mock_open()):
self.assertTrue(
state.sls(arg,
None,
None,
None,
True,
cache
=True
)
)
MockState.HighState.flag = True
self.assertTrue(state.sls("core,edit"
".vim dev",
None,
None,
None,
True)
)
MockState.HighState.flag = False
mock = MagicMock(return_value=True)
with patch.dict(state.__salt__,
{'config.option':
mock}):
mock = MagicMock(return_value=
True)
with patch.object(
state,
'_filter_'
'running',
mock):
with patch.dict(
state.
__opts__,
{"cachedir":
"/D/"}):
self.sub_test_sls()
self.sub_test_sls()
def sub_test_sls(self):
'''