Skip to content

Commit

Permalink
Merge pull request #52351 from mchugh19/slot_hack
Browse files Browse the repository at this point in the history
Draft: support slot parsing inside dict and lists of dict or strings
  • Loading branch information
thatch45 authored Apr 9, 2019
2 parents 166a33a + 408942d commit cd8d7a5
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 3 deletions.
41 changes: 38 additions & 3 deletions salt/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2157,18 +2157,53 @@ def format_slots(self, cdata):
'''
Read in the arguments from the low level slot syntax to make a last
minute runtime call to gather relevant data for the specific routine
Will parse strings, first level of dictionary values, and strings and
first level dict values inside of lists
'''
# __slot__:salt.cmd.run(foo, bar, baz=qux)
SLOT_TEXT = '__slot__:'
ctx = (('args', enumerate(cdata['args'])),
('kwargs', cdata['kwargs'].items()))
for atype, avalues in ctx:
for ind, arg in avalues:
arg = salt.utils.data.decode(arg, keep=True)
if not isinstance(arg, six.text_type) \
or not arg.startswith('__slot__:'):
if isinstance(arg, dict):
# Search dictionary values for __slot__:
for key, value in arg.items():
try:
if value.startswith(SLOT_TEXT):
log.trace("Slot processsing dict value %s", value)
cdata[atype][ind][key] = self.__eval_slot(value)
except AttributeError:
# Not a string/slot
continue
elif isinstance(arg, list):
for idx, listvalue in enumerate(arg):
log.trace("Slot processing list value: %s", listvalue)
if isinstance(listvalue, dict):
# Search dict values in list for __slot__:
for key, value in listvalue.items():
try:
if value.startswith(SLOT_TEXT):
log.trace("Slot processsing nested dict value %s", value)
cdata[atype][ind][idx][key] = self.__eval_slot(value)
except AttributeError:
# Not a string/slot
continue
if isinstance(listvalue, six.text_type):
# Search strings in a list for __slot__:
if listvalue.startswith(SLOT_TEXT):
log.trace("Slot processsing nested string %s", listvalue)
cdata[atype][ind][idx] = self.__eval_slot(listvalue)
elif isinstance(arg, six.text_type) \
and arg.startswith(SLOT_TEXT):
# Search strings for __slot__:
log.trace("Slot processsing %s", arg)
cdata[atype][ind] = self.__eval_slot(arg)
else:
# Not a slot, skip it
continue
cdata[atype][ind] = self.__eval_slot(arg)

def verify_retry_data(self, retry_data):
'''
Expand Down
54 changes: 54 additions & 0 deletions tests/unit/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,60 @@ def test_format_slots_arg(self):
mock.assert_called_once_with('fun_arg', fun_key='fun_val')
self.assertEqual(cdata, {'args': ['fun_return'], 'kwargs': {'key': 'val'}})

def test_format_slots_dict_arg(self):
'''
Test the format slots is calling a slot specified in dict arg.
'''
cdata = {
'args': [
{'subarg': '__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)'},
],
'kwargs': {
'key': 'val',
}
}
mock = MagicMock(return_value='fun_return')
with patch.dict(self.state_obj.functions, {'mod.fun': mock}):
self.state_obj.format_slots(cdata)
mock.assert_called_once_with('fun_arg', fun_key='fun_val')
self.assertEqual(cdata, {'args': [{'subarg': 'fun_return'}], 'kwargs': {'key': 'val'}})

def test_format_slots_listdict_arg(self):
'''
Test the format slots is calling a slot specified in list containing a dict.
'''
cdata = {
'args': [[
{'subarg': '__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)'},
]],
'kwargs': {
'key': 'val',
}
}
mock = MagicMock(return_value='fun_return')
with patch.dict(self.state_obj.functions, {'mod.fun': mock}):
self.state_obj.format_slots(cdata)
mock.assert_called_once_with('fun_arg', fun_key='fun_val')
self.assertEqual(cdata, {'args': [[{'subarg': 'fun_return'}]], 'kwargs': {'key': 'val'}})

def test_format_slots_liststr_arg(self):
'''
Test the format slots is calling a slot specified in list containing a dict.
'''
cdata = {
'args': [[
'__slot__:salt:mod.fun(fun_arg, fun_key=fun_val)',
]],
'kwargs': {
'key': 'val',
}
}
mock = MagicMock(return_value='fun_return')
with patch.dict(self.state_obj.functions, {'mod.fun': mock}):
self.state_obj.format_slots(cdata)
mock.assert_called_once_with('fun_arg', fun_key='fun_val')
self.assertEqual(cdata, {'args': [['fun_return']], 'kwargs': {'key': 'val'}})

def test_format_slots_kwarg(self):
'''
Test the format slots is calling a slot specified in kwargs with corresponding arguments.
Expand Down

0 comments on commit cd8d7a5

Please sign in to comment.