Skip to content

Commit

Permalink
Merge pull request #42290 from isbm/isbm-module_run_parambug_42270_217
Browse files Browse the repository at this point in the history
Backport of #42270
  • Loading branch information
Nicole Thomas committed Jul 27, 2017
2 parents 4c20f1c + e38d432 commit 22eea38
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 15 deletions.
34 changes: 32 additions & 2 deletions doc/topics/releases/2017.7.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,27 +122,57 @@ State Module Changes
# After
run_something:
module.run:
mymodule.something:
- mymodule.something:
- name: some name
- first_arg: one
- second_arg: two
- do_stuff: True
Since a lot of users are already using :py:func:`module.run
<salt.states.module.run>` states, this new behavior must currently be
explicitly turned on, to allow users to take their time updating their SLS
files. However, please keep in mind that the new syntax will take effect in
the next feature release of Salt (Oxygen) and the old usage will no longer be
supported at that time.

Another feature of the new :py:func:`module.run <salt.states.module.run>` is that
it allows calling many functions in a single batch, such as:

.. code-block:: yaml
run_something:
module.run:
- mymodule.function_without_parameters:
- mymodule.another_function:
- myparam
- my_other_param
In a rare case that you have a function that needs to be called several times but
with the different parameters, an additional feature of "tagging" is to the
rescue. In order to tag a function, use a colon delimeter. For example:

.. code-block:: yaml
run_something:
module.run:
- mymodule.same_function:1:
- mymodule.same_function:2:
- myparam
- my_other_param
- mymodule.same_function:3:
- foo: bar
The example above will run `mymodule.same_function` three times with the
different parameters.

To enable the new behavior for :py:func:`module.run <salt.states.module.run>`,
add the following to the minion config file:

.. code-block:: yaml
use_superseded:
- module.run
- The default for the ``fingerprint_hash_type`` option used in the ``present``
function in the :mod:`ssh <salt.states.ssh_know_hosts>` state changed from
``md5`` to ``sha256``.
Expand Down
37 changes: 26 additions & 11 deletions salt/states/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ def run(**kwargs):
missing = []
tests = []
for func in functions:
func = func.split(':')[0]
if func not in __salt__:
missing.append(func)
elif __opts__['test']:
Expand All @@ -284,8 +285,9 @@ def run(**kwargs):
failures = []
success = []
for func in functions:
_func = func.split(':')[0]
try:
func_ret = _call_function(func, returner=kwargs.get('returner'),
func_ret = _call_function(_func, returner=kwargs.get('returner'),
func_args=kwargs.get(func))
if not _get_result(func_ret, ret['changes'].get('ret', {})):
if isinstance(func_ret, dict):
Expand Down Expand Up @@ -313,22 +315,35 @@ def _call_function(name, returner=None, **kwargs):
'''
argspec = salt.utils.args.get_function_argspec(__salt__[name])
func_kw = dict(zip(argspec.args[-len(argspec.defaults or []):], # pylint: disable=incompatible-py3-code
argspec.defaults or []))
func_args = []
for funcset in kwargs.get('func_args') or {}:
if isinstance(funcset, dict):
func_kw.update(funcset)
argspec.defaults or []))
arg_type, na_type, kw_type = [], {}, False
for funcset in reversed(kwargs.get('func_args') or []):
if not isinstance(funcset, dict):
kw_type = True
if kw_type:
if isinstance(funcset, dict):
arg_type += funcset.values()
na_type.update(funcset)
else:
arg_type.append(funcset)
else:
func_args.append(funcset)
func_kw.update(funcset)
arg_type.reverse()

_exp_prm = len(argspec.args or []) - len(argspec.defaults or [])
_passed_prm = len(arg_type)
missing = []
for arg in argspec.args:
if arg not in func_kw:
missing.append(arg)
if na_type and _exp_prm > _passed_prm:
for arg in argspec.args:
if arg not in func_kw:
missing.append(arg)
if missing:
raise SaltInvocationError('Missing arguments: {0}'.format(', '.join(missing)))
elif _exp_prm > _passed_prm:
raise SaltInvocationError('Function expects {0} parameters, got only {1}'.format(
_exp_prm, _passed_prm))

mret = __salt__[name](*func_args, **func_kw)
mret = __salt__[name](*arg_type, **func_kw)
if returner is not None:
returners = salt.loader.returners(__opts__, __salt__)
if returner in returners:
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/states/test_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def test_run_missing_arg(self):
with patch.dict(module.__salt__, {CMD: _mocked_func_named}):
with patch.dict(module.__opts__, {'use_superseded': ['module.run']}):
ret = module.run(**{CMD: None})
assert ret['comment'] == "'{0}' failed: Missing arguments: name".format(CMD)
assert ret['comment'] == "'{0}' failed: Function expects 1 parameters, got only 0".format(CMD)

def test_run_correct_arg(self):
'''
Expand All @@ -131,7 +131,7 @@ def test_run_correct_arg(self):
'''
with patch.dict(module.__salt__, {CMD: _mocked_func_named}):
with patch.dict(module.__opts__, {'use_superseded': ['module.run']}):
ret = module.run(**{CMD: [{'name': 'Fred'}]})
ret = module.run(**{CMD: ['Fred']})
assert ret['comment'] == '{0}: Success'.format(CMD)
assert ret['result']

Expand Down

0 comments on commit 22eea38

Please sign in to comment.