Skip to content

Commit

Permalink
Merge pull request #52187 from mchugh19/slot-extend
Browse files Browse the repository at this point in the history
draft support for parsing slot results and appending text
  • Loading branch information
thatch45 committed Apr 9, 2019
2 parents 6b84ab2 + 9a28d37 commit 166a33a
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 2 deletions.
25 changes: 25 additions & 0 deletions doc/topics/releases/neon.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,31 @@ editing XML IDs.
- xpath: .//actor[@id='1']
- value: William Shatner
Slot Syntax Updates
===================

The slot syntax has been updated to support parsing dictionary responses and to append text.

.. code-block:: yaml
demo dict parsing and append:
test.configurable_test_state:
- name: slot example
- changes: False
- comment: __slot__:salt:test.arg(shell="/bin/bash").kwargs.shell ~ /appended
.. code-block:: none
local:
----------
ID: demo dict parsing and append
Function: test.configurable_test_state
Name: slot example
Result: True
Comment: /bin/bash/appended
Started: 09:59:58.623575
Duration: 1.229 ms
Changes:
State Changes
=============
Expand Down
19 changes: 18 additions & 1 deletion doc/topics/slots/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Slots
=====

.. versionadded:: 2018.3.0
.. versionchanged:: Neon

.. note:: This functionality is under development and could be changed in the
future releases
Expand Down Expand Up @@ -33,7 +34,14 @@ Slot syntax looks close to the simple python function call.
__slot__:salt:<module>.<function>(<args>, ..., <kwargs...>, ...)
Also there are some specifics in the syntax coming from the execution functions
For the Neon release, this syntax has been updated to support parsing functions
which return dictionaries and for appending text to the slot result.

.. code-block:: text
__slot__:salt:<module>.<function>(<args>..., <kwargs...>, ...).dictionary ~ append
There are some specifics in the syntax coming from the execution functions
nature and a desire to simplify the user experience. First one is that you
don't need to quote the strings passed to the slots functions. The second one
is that all arguments handled as strings.
Expand All @@ -51,3 +59,12 @@ This will execute the :py:func:`test.echo <salt.modules.test.echo>` execution
functions right before calling the state. The functions in the example will
return `/tmp/some_file` and `/etc/hosts` strings that will be used as a target
and source arguments in the state function `file.copy`.

Here is an example of result parsing and appending:

.. code-block:: yaml
file-in-user-home:
file.copy:
- name: __slot__:salt:user.info(someuser).home ~ /subdirectory
- source: salt://somefile
39 changes: 38 additions & 1 deletion salt/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2114,7 +2114,44 @@ def __eval_slot(self, slot):
'test.arg(\'arg\', kw=\'kwarg\')')
return slot
log.debug('Calling slot: %s(%s, %s)', fun, args, kwargs)
return self.functions[fun](*args, **kwargs)
slot_return = self.functions[fun](*args, **kwargs)

# Given input __slot__:salt:test.arg(somekey="value").not.exist ~ /appended
# slot_text should be __slot...).not.exist
# append_data should be ~ /appended
slot_text = fmt[2].split('~')[0]
append_data = fmt[2].split('~', 1)[1:]
log.debug('slot_text: %s', slot_text)
log.debug('append_data: %s', append_data)

# Support parsing slot dict response
# return_get should result in a kwargs.nested.dict path by getting
# everything after first closing paren: )
return_get = None
try:
return_get = slot_text[slot_text.rindex(')')+1:]
except ValueError:
pass
if return_get:
#remove first period
return_get = return_get.split('.', 1)[1].strip()
log.debug('Searching slot result %s for %s', slot_return, return_get)
slot_return = salt.utils.data.traverse_dict_and_list(slot_return,
return_get,
default=None,
delimiter='.'
)

if append_data:
if isinstance(slot_return, six.string_types):
# Append text to slot string result
append_data = ' '.join(append_data).strip()
log.debug('appending to slot result: %s', append_data)
slot_return += append_data
else:
log.error('Ignoring slot append, slot result is not a string')

return slot_return

def format_slots(self, cdata):
'''
Expand Down
38 changes: 38 additions & 0 deletions tests/unit/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,41 @@ def test_format_slots_malformed(self):
self.state_obj.format_slots(cdata)
mock.assert_not_called()
self.assertEqual(cdata, sls_data)

def test_slot_traverse_dict(self):
'''
Test the slot parsing of dict response.
'''
cdata = {
'args': [
'arg',
],
'kwargs': {
'key': '__slot__:salt:mod.fun(fun_arg, fun_key=fun_val).key1',
}
}
return_data = {'key1': 'value1'}
mock = MagicMock(return_value=return_data)
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': ['arg'], 'kwargs': {'key': 'value1'}})

def test_slot_append(self):
'''
Test the slot parsing of dict response.
'''
cdata = {
'args': [
'arg',
],
'kwargs': {
'key': '__slot__:salt:mod.fun(fun_arg, fun_key=fun_val).key1 ~ thing~',
}
}
return_data = {'key1': 'value1'}
mock = MagicMock(return_value=return_data)
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': ['arg'], 'kwargs': {'key': 'value1thing~'}})

0 comments on commit 166a33a

Please sign in to comment.