Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support args in unless and onlyif #52969

Merged
merged 2 commits into from
May 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions doc/ref/states/requisites.rst
Original file line number Diff line number Diff line change
Expand Up @@ -852,8 +852,8 @@ In the above case, ``some_check`` will be run prior to _each_ name -- once for
.. versionchanged:: Neon
The ``unless`` requisite can take a module as a dictionary field in unless.
The dictionary must contain an argument ``fun`` which is the module that is
being run, and everything else passed in will be kwargs passed to the module
function.
being run, and everything else must be passed in under the args key or will
be passed as individual kwargs to the module function.

.. code-block:: yaml

Expand All @@ -865,6 +865,18 @@ In the above case, ``some_check`` will be run prior to _each_ name -- once for
- fun: file.file_exists
path: /usr/local/bin/whatever

.. code-block:: yaml

set mysql root password:
debconf.set:
- name: mysql-server-5.7
- data:
'mysql-server/root_password': {'type': 'password', 'value': {{pillar['mysql.pass']}} }
- unless:
- fun: pkg.version
args:
- mysql-server-5.7

.. _onlyif-requisite:

onlyif
Expand Down Expand Up @@ -908,8 +920,8 @@ if the gluster commands return a 0 ret value.
.. versionchanged:: Neon
The ``onlyif`` requisite can take a module as a dictionary field in onlyif.
The dictionary must contain an argument ``fun`` which is the module that is
being run, and everything else passed in will be kwargs passed to the module
function.
being run, and everything else must be passed in under the args key or will
be passed as individual kwargs to the module function.

.. code-block:: yaml

Expand All @@ -927,6 +939,17 @@ if the gluster commands return a 0 ret value.
- fun: match.grain
tgt: 'os_family: Debian'

.. code-block:: yaml

arbitrary file example:
file.touch:
- name: /path/to/file
- onlyif:
- fun: file.search
args:
- /etc/crontab
- 'entry1'

runas
~~~~~

Expand Down
30 changes: 30 additions & 0 deletions doc/topics/releases/neon.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,36 @@ New output:
Skipped:
0

Unless and onlyif Enhancements
==============================

The ``unless`` and ``onlyif`` requisites can now be operated with salt modules.
The dictionary must contain an argument ``fun`` which is the module that is
being run, and everything else must be passed in under the args key or will be
passed as individual kwargs to the module function.

.. code-block:: yaml

install apache on debian based distros:
cmd.run:
- name: make install
- cwd: /path/to/dir/whatever-2.1.5/
- unless:
- fun: file.file_exists
path: /usr/local/bin/whatever

.. code-block:: yaml

set mysql root password:
debconf.set:
- name: mysql-server-5.7
- data:
'mysql-server/root_password': {'type': 'password', 'value': {{pillar['mysql.pass']}} }
- unless:
- fun: pkg.version
args:
- mysql-server-5.7


Keystore State and Module
=========================
Expand Down
14 changes: 11 additions & 3 deletions salt/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,11 @@ def _check_cmd(cmd):
ret['comment'] = 'no `fun` argument in onlyif: {0}'.format(entry)
log.warning(ret['comment'])
return ret
result = self.functions[entry.pop('fun')](**entry)

if 'args' in entry:
result = self.functions[entry.pop('fun')](*entry.pop('args'), **entry)
else:
result = self.functions[entry.pop('fun')](**entry)
if self.state_con.get('retcode', 0):
_check_cmd(self.state_con['retcode'])
elif not result:
Expand Down Expand Up @@ -946,10 +950,14 @@ def _check_cmd(cmd):
_check_cmd(cmd)
elif isinstance(entry, dict):
if 'fun' not in entry:
ret['comment'] = 'no `fun` argument in onlyif: {0}'.format(entry)
ret['comment'] = 'no `fun` argument in unless: {0}'.format(entry)
log.warning(ret['comment'])
return ret
result = self.functions[entry.pop('fun')](**entry)

if 'args' in entry:
result = self.functions[entry.pop('fun')](*entry.pop('args'), **entry)
else:
result = self.functions[entry.pop('fun')](**entry)
if self.state_con.get('retcode', 0):
_check_cmd(self.state_con['retcode'])
elif result:
Expand Down
66 changes: 66 additions & 0 deletions tests/unit/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,72 @@ def test_render_requisite_require_in_disabled(self):
run_num = ret['test_|-step_one_|-step_one_|-succeed_with_changes']['__run_num__']
self.assertEqual(run_num, 0)

def test_verify_onlyif_parse(self):
low_data = {
"onlyif": [
{
"fun": "file.search",
"args": [
"/etc/crontab",
"run-parts"
]
}
],
"name": "mysql-server-5.7",
"state": "debconf",
"__id__": "set root password",
"fun": "set",
"__env__": "base",
"__sls__": "debconf",
"data": {
"mysql-server/root_password": {
"type": "password",
"value": "temp123"
}
},
"order": 10000
}
expected_result = {'comment': 'onlyif condition is true', 'result': False}

with patch('salt.state.State._gather_pillar') as state_patch:
minion_opts = self.get_temp_config('minion')
state_obj = salt.state.State(minion_opts)
return_result = state_obj._run_check_onlyif(low_data, '')
self.assertEqual(expected_result, return_result)

def test_verify_unless_parse(self):
low_data = {
"unless": [
{
"fun": "file.search",
"args": [
"/etc/crontab",
"run-parts"
]
}
],
"name": "mysql-server-5.7",
"state": "debconf",
"__id__": "set root password",
"fun": "set",
"__env__": "base",
"__sls__": "debconf",
"data": {
"mysql-server/root_password": {
"type": "password",
"value": "temp123"
}
},
"order": 10000
}
expected_result = {'comment': 'unless condition is true', 'result': True, 'skip_watch': True}

with patch('salt.state.State._gather_pillar') as state_patch:
minion_opts = self.get_temp_config('minion')
state_obj = salt.state.State(minion_opts)
return_result = state_obj._run_check_unless(low_data, '')
self.assertEqual(expected_result, return_result)


class HighStateTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
def setUp(self):
Expand Down