mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Consolidate some state requisites (#55974)
* add cmd state features to state.py also dry git state * dry docker_container * update docker test * correct integration test * clarity improvement * lint and test fixes * correct test * global req updates * doc update * doc updates * remove unused mac requisite implementation * other macpackage cleanup * handle missing user in runas * add test cases unless/onlyif exception handling * fix macpackage tests * fix typo
This commit is contained in:
parent
7d90120182
commit
2520ae8675
13 changed files with 472 additions and 810 deletions
|
@ -992,6 +992,38 @@ if the gluster commands return a 0 ret value.
|
|||
- /etc/crontab
|
||||
- 'entry1'
|
||||
|
||||
.. _creates-requisite:
|
||||
|
||||
Creates
|
||||
-------
|
||||
|
||||
.. versionadded:: Sodium
|
||||
|
||||
The ``creates`` requisite specifies that a state should only run when any of
|
||||
the specified files do not already exist. Like ``unless``, ``creates`` requisite
|
||||
operates as NAND and is useful in giving more granular control over when a state
|
||||
should execute. This was previously used by the :mod:`cmd <salt.states.cmd>` and
|
||||
:mod:`docker_container <salt.states.docker_container>` states.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
contrived creates example:
|
||||
file.touch:
|
||||
- name: /path/to/file
|
||||
- creates: /path/to/file
|
||||
|
||||
``creates`` also accepts a list of files, in which case this state will
|
||||
run if **any** of the files do not exist:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
creates list:
|
||||
file.cmd:
|
||||
- name: /path/to/command
|
||||
- creates:
|
||||
- /path/file
|
||||
- /path/file2
|
||||
|
||||
listen
|
||||
~~~~~~
|
||||
|
||||
|
|
|
@ -17,6 +17,16 @@ The old syntax for the mine_function - as a dict, or as a list with dicts that
|
|||
contain more than exactly one key - is still supported but discouraged in favor
|
||||
of the more uniform syntax of module.run.
|
||||
|
||||
State updates
|
||||
=============
|
||||
|
||||
The ``creates`` state requisite has been migrated from the
|
||||
:mod:`docker_container <salt.states.docker_container>` and :mod:`cmd <salt.states.cmd>`
|
||||
states to become a global option. This acts similar to an equivalent
|
||||
``unless: test -f filename`` but can also accept a list of filenames. This allows
|
||||
all states to take advantage of the enhanced functionality released in Neon, of allowing
|
||||
salt execution modules for requisite checks.
|
||||
|
||||
State Execution Module
|
||||
======================
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ def orchestrate(
|
|||
.. seealso:: More Orchestrate documentation
|
||||
|
||||
* :ref:`Full Orchestrate Tutorial <orchestrate-runner>`
|
||||
* :py:mod:`Docs for the ``salt`` state module <salt.states.saltmod>`
|
||||
* Docs for the salt state module :py:mod:`salt.states.saltmod`
|
||||
|
||||
CLI Examples:
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ import salt.utils.url
|
|||
|
||||
# Explicit late import to avoid circular import. DO NOT MOVE THIS.
|
||||
import salt.utils.yamlloader as yamlloader
|
||||
from salt.exceptions import SaltRenderError, SaltReqTimeoutError
|
||||
from salt.exceptions import CommandExecutionError, SaltRenderError, SaltReqTimeoutError
|
||||
|
||||
# Import third party libs
|
||||
# pylint: disable=import-error,no-name-in-module,redefined-builtin
|
||||
|
@ -97,6 +97,7 @@ STATE_RUNTIME_KEYWORDS = frozenset(
|
|||
"failhard",
|
||||
"onlyif",
|
||||
"unless",
|
||||
"creates",
|
||||
"retry",
|
||||
"order",
|
||||
"parallel",
|
||||
|
@ -900,6 +901,14 @@ class State(object):
|
|||
# If either result is True, the returned result should be True
|
||||
ret["skip_watch"] = _ret["skip_watch"] or ret["skip_watch"]
|
||||
|
||||
if "creates" in low_data:
|
||||
_ret = self._run_check_creates(low_data)
|
||||
ret["result"] = _ret["result"] or ret["result"]
|
||||
ret["comment"].append(_ret["comment"])
|
||||
if "skip_watch" in _ret:
|
||||
# If either result is True, the returned result should be True
|
||||
ret["skip_watch"] = _ret["skip_watch"] or ret["skip_watch"]
|
||||
|
||||
return ret
|
||||
|
||||
def _run_check_function(self, entry):
|
||||
|
@ -935,9 +944,13 @@ class State(object):
|
|||
|
||||
for entry in low_data_onlyif:
|
||||
if isinstance(entry, six.string_types):
|
||||
cmd = self.functions["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True, **cmd_opts
|
||||
)
|
||||
try:
|
||||
cmd = self.functions["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True, **cmd_opts
|
||||
)
|
||||
except CommandExecutionError:
|
||||
# Command failed, notify onlyif to skip running the item
|
||||
cmd = 100
|
||||
log.debug("Last command return code: %s", cmd)
|
||||
_check_cmd(cmd)
|
||||
elif isinstance(entry, dict):
|
||||
|
@ -994,10 +1007,14 @@ class State(object):
|
|||
|
||||
for entry in low_data_unless:
|
||||
if isinstance(entry, six.string_types):
|
||||
cmd = self.functions["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True, **cmd_opts
|
||||
)
|
||||
log.debug("Last command return code: %s", cmd)
|
||||
try:
|
||||
cmd = self.functions["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True, **cmd_opts
|
||||
)
|
||||
log.debug("Last command return code: %s", cmd)
|
||||
except CommandExecutionError:
|
||||
# Command failed, so notify unless to skip the item
|
||||
cmd = 0
|
||||
_check_cmd(cmd)
|
||||
elif isinstance(entry, dict):
|
||||
if "fun" not in entry:
|
||||
|
@ -1061,6 +1078,30 @@ class State(object):
|
|||
return ret
|
||||
return ret
|
||||
|
||||
def _run_check_creates(self, low_data):
|
||||
"""
|
||||
Check that listed files exist
|
||||
"""
|
||||
ret = {"result": False}
|
||||
|
||||
if isinstance(low_data["creates"], six.string_types) and os.path.exists(
|
||||
low_data["creates"]
|
||||
):
|
||||
ret["comment"] = "{0} exists".format(low_data["creates"])
|
||||
ret["result"] = True
|
||||
ret["skip_watch"] = True
|
||||
elif isinstance(low_data["creates"], list) and all(
|
||||
[os.path.exists(path) for path in low_data["creates"]]
|
||||
):
|
||||
ret["comment"] = "All files in creates exist"
|
||||
ret["result"] = True
|
||||
ret["skip_watch"] = True
|
||||
else:
|
||||
ret["comment"] = "Creates files not found"
|
||||
ret["result"] = False
|
||||
|
||||
return ret
|
||||
|
||||
def reset_run_num(self):
|
||||
"""
|
||||
Rest the run_num value to 0
|
||||
|
@ -2068,11 +2109,9 @@ class State(object):
|
|||
# that's not found in cdata, we look for what we're being passed in
|
||||
# the original data, namely, the special dunder __env__. If that's
|
||||
# not found we default to 'base'
|
||||
req_list = ("unless", "onlyif", "creates")
|
||||
if (
|
||||
"unless" in low
|
||||
and "{0[state]}.mod_run_check".format(low) not in self.states
|
||||
) or (
|
||||
"onlyif" in low
|
||||
any(req in low for req in req_list)
|
||||
and "{0[state]}.mod_run_check".format(low) not in self.states
|
||||
):
|
||||
ret.update(self._run_check(low))
|
||||
|
|
|
@ -46,7 +46,8 @@ run if **any** of the files do not exist:
|
|||
|
||||
.. note::
|
||||
|
||||
The ``creates`` option was added to version 2014.7.0
|
||||
The ``creates`` option was added to the cmd state in version 2014.7.0,
|
||||
and made a global requisite in Sodium.
|
||||
|
||||
Sometimes when running a command that starts up a daemon, the init script
|
||||
doesn't return properly which causes Salt to wait indefinitely for a response.
|
||||
|
@ -323,103 +324,8 @@ def _is_true(val):
|
|||
raise ValueError("Failed parsing boolean value: {0}".format(val))
|
||||
|
||||
|
||||
def mod_run_check(cmd_kwargs, onlyif, unless, creates):
|
||||
"""
|
||||
Execute the onlyif and unless logic.
|
||||
Return a result dict if:
|
||||
* onlyif failed (onlyif != 0)
|
||||
* unless succeeded (unless == 0)
|
||||
else return True
|
||||
"""
|
||||
# never use VT for onlyif/unless executions because this will lead
|
||||
# to quote problems
|
||||
cmd_kwargs = copy.deepcopy(cmd_kwargs)
|
||||
cmd_kwargs["use_vt"] = False
|
||||
cmd_kwargs["bg"] = False
|
||||
|
||||
if onlyif is not None:
|
||||
if isinstance(onlyif, six.string_types):
|
||||
cmd = __salt__["cmd.retcode"](
|
||||
onlyif, ignore_retcode=True, python_shell=True, **cmd_kwargs
|
||||
)
|
||||
log.debug("Last command return code: {0}".format(cmd))
|
||||
if cmd != 0:
|
||||
return {
|
||||
"comment": "onlyif condition is false",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
elif isinstance(onlyif, list):
|
||||
for entry in onlyif:
|
||||
cmd = __salt__["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True, **cmd_kwargs
|
||||
)
|
||||
log.debug("Last command '{0}' return code: {1}".format(entry, cmd))
|
||||
if cmd != 0:
|
||||
return {
|
||||
"comment": "onlyif condition is false: {0}".format(entry),
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
elif not isinstance(onlyif, six.string_types):
|
||||
if not onlyif:
|
||||
log.debug("Command not run: onlyif did not evaluate to string_type")
|
||||
return {
|
||||
"comment": "onlyif condition is false",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
if unless is not None:
|
||||
if isinstance(unless, six.string_types):
|
||||
cmd = __salt__["cmd.retcode"](
|
||||
unless, ignore_retcode=True, python_shell=True, **cmd_kwargs
|
||||
)
|
||||
log.debug("Last command return code: {0}".format(cmd))
|
||||
if cmd == 0:
|
||||
return {
|
||||
"comment": "unless condition is true",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
elif isinstance(unless, list):
|
||||
cmd = []
|
||||
for entry in unless:
|
||||
cmd.append(
|
||||
__salt__["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True, **cmd_kwargs
|
||||
)
|
||||
)
|
||||
log.debug("Last command return code: {0}".format(cmd))
|
||||
if all([c == 0 for c in cmd]):
|
||||
return {
|
||||
"comment": "unless condition is true",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
elif not isinstance(unless, six.string_types):
|
||||
if unless:
|
||||
log.debug("Command not run: unless did not evaluate to string_type")
|
||||
return {
|
||||
"comment": "unless condition is true",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
if isinstance(creates, six.string_types) and os.path.exists(creates):
|
||||
return {"comment": "{0} exists".format(creates), "result": True}
|
||||
elif isinstance(creates, list) and all([os.path.exists(path) for path in creates]):
|
||||
return {"comment": "All files in creates exist", "result": True}
|
||||
|
||||
# No reason to stop, return True
|
||||
return True
|
||||
|
||||
|
||||
def wait(
|
||||
name,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
creates=None,
|
||||
cwd=None,
|
||||
root=None,
|
||||
runas=None,
|
||||
|
@ -445,14 +351,6 @@ def wait(
|
|||
The command to execute, remember that the command will execute with the
|
||||
path and permissions of the salt-minion.
|
||||
|
||||
onlyif
|
||||
A command to run as a check, run the named command only if the command
|
||||
passed to the ``onlyif`` option returns true
|
||||
|
||||
unless
|
||||
A command to run as a check, only run the named command if the command
|
||||
passed to the ``unless`` option returns false
|
||||
|
||||
cwd
|
||||
The current working directory to execute the command in, defaults to
|
||||
/root
|
||||
|
@ -562,8 +460,6 @@ def wait_script(
|
|||
name,
|
||||
source=None,
|
||||
template=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
cwd=None,
|
||||
runas=None,
|
||||
shell=None,
|
||||
|
@ -594,14 +490,6 @@ def wait_script(
|
|||
The command to execute, remember that the command will execute with the
|
||||
path and permissions of the salt-minion.
|
||||
|
||||
onlyif
|
||||
A command to run as a check, run the named command only if the command
|
||||
passed to the ``onlyif`` option returns true
|
||||
|
||||
unless
|
||||
A command to run as a check, only run the named command if the command
|
||||
passed to the ``unless`` option returns false
|
||||
|
||||
cwd
|
||||
The current working directory to execute the command in, defaults to
|
||||
/root
|
||||
|
@ -694,9 +582,6 @@ def wait_script(
|
|||
|
||||
def run(
|
||||
name,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
creates=None,
|
||||
cwd=None,
|
||||
root=None,
|
||||
runas=None,
|
||||
|
@ -721,14 +606,6 @@ def run(
|
|||
The command to execute, remember that the command will execute with the
|
||||
path and permissions of the salt-minion.
|
||||
|
||||
onlyif
|
||||
A command to run as a check, run the named command only if the command
|
||||
passed to the ``onlyif`` option returns a zero exit status
|
||||
|
||||
unless
|
||||
A command to run as a check, only run the named command if the command
|
||||
passed to the ``unless`` option returns a non-zero exit status
|
||||
|
||||
cwd
|
||||
The current working directory to execute the command in, defaults to
|
||||
/root
|
||||
|
@ -906,11 +783,6 @@ def run(
|
|||
}
|
||||
)
|
||||
|
||||
cret = mod_run_check(cmd_kwargs, onlyif, unless, creates)
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
if __opts__["test"] and not test_name:
|
||||
ret["result"] = None
|
||||
ret["comment"] = 'Command "{0}" would have been executed'.format(name)
|
||||
|
@ -956,9 +828,6 @@ def script(
|
|||
name,
|
||||
source=None,
|
||||
template=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
creates=None,
|
||||
cwd=None,
|
||||
runas=None,
|
||||
shell=None,
|
||||
|
@ -991,14 +860,6 @@ def script(
|
|||
Either "cmd arg1 arg2 arg3..." (cmd is not used) or a source
|
||||
"salt://...".
|
||||
|
||||
onlyif
|
||||
Run the named command only if the command passed to the ``onlyif``
|
||||
option returns true
|
||||
|
||||
unless
|
||||
Run the named command only if the command passed to the ``unless``
|
||||
option returns false
|
||||
|
||||
cwd
|
||||
The current working directory to execute the command in, defaults to
|
||||
/root
|
||||
|
@ -1153,8 +1014,6 @@ def script(
|
|||
"runas": runas,
|
||||
"shell": shell or __grains__["shell"],
|
||||
"env": env,
|
||||
"onlyif": onlyif,
|
||||
"unless": unless,
|
||||
"cwd": cwd,
|
||||
"template": template,
|
||||
"umask": umask,
|
||||
|
@ -1182,11 +1041,6 @@ def script(
|
|||
if not cmd_kwargs.get("args", None) and len(name.split()) > 1:
|
||||
cmd_kwargs.update({"args": name.split(" ", 1)[1]})
|
||||
|
||||
cret = mod_run_check(run_check_cmd_kwargs, onlyif, unless, creates)
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
if __opts__["test"] and not test_name:
|
||||
ret["result"] = None
|
||||
ret["comment"] = "Command '{0}' would have been " "executed".format(name)
|
||||
|
@ -1228,9 +1082,6 @@ def call(
|
|||
func,
|
||||
args=(),
|
||||
kws=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
creates=None,
|
||||
output_loglevel="debug",
|
||||
hide_output=False,
|
||||
use_vt=False,
|
||||
|
@ -1241,13 +1092,6 @@ def call(
|
|||
declaration. This function is mainly used by the
|
||||
:mod:`salt.renderers.pydsl` renderer.
|
||||
|
||||
The interpretation of ``onlyif`` and ``unless`` arguments are identical to
|
||||
those of :mod:`cmd.run <salt.states.cmd.run>`, and all other
|
||||
arguments(``cwd``, ``runas``, ...) allowed by :mod:`cmd.run
|
||||
<salt.states.cmd.run>` are allowed here, except that their effects apply
|
||||
only to the commands specified in `onlyif` and `unless` rather than to the
|
||||
function to be invoked.
|
||||
|
||||
In addition, the ``stateful`` argument has no effects here.
|
||||
|
||||
The return value of the invoked function will be interpreted as follows.
|
||||
|
@ -1281,11 +1125,6 @@ def call(
|
|||
"umask": kwargs.get("umask"),
|
||||
}
|
||||
|
||||
cret = mod_run_check(cmd_kwargs, onlyif, unless, creates)
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
if not kws:
|
||||
kws = {}
|
||||
result = func(*args, **kws)
|
||||
|
@ -1306,9 +1145,6 @@ def wait_call(
|
|||
func,
|
||||
args=(),
|
||||
kws=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
creates=None,
|
||||
stateful=False,
|
||||
use_vt=False,
|
||||
output_loglevel="debug",
|
||||
|
|
|
@ -49,7 +49,6 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
|
||||
import salt.utils.args
|
||||
import salt.utils.data
|
||||
|
@ -2093,9 +2092,6 @@ def running(
|
|||
def run(
|
||||
name,
|
||||
image=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
creates=None,
|
||||
bg=False,
|
||||
failhard=True,
|
||||
replace=False,
|
||||
|
@ -2131,15 +2127,6 @@ def run(
|
|||
|
||||
Additionally, the following arguments are supported:
|
||||
|
||||
onlyif
|
||||
A command or list of commands to run as a check. The container will
|
||||
only run if any of the specified commands returns a zero exit status.
|
||||
|
||||
unless
|
||||
A command or list of commands to run as a check. The container will
|
||||
only run if any of the specified commands returns a non-zero exit
|
||||
status.
|
||||
|
||||
creates
|
||||
A path or list of paths. Only run if one or more of the specified paths
|
||||
do not exist on the minion.
|
||||
|
@ -2213,11 +2200,6 @@ def run(
|
|||
elif not isinstance(image, six.string_types):
|
||||
image = six.text_type(image)
|
||||
|
||||
cret = mod_run_check(onlyif, unless, creates)
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
try:
|
||||
if "networks" in kwargs and kwargs["networks"] is not None:
|
||||
kwargs["networks"] = _parse_networks(kwargs["networks"])
|
||||
|
@ -2230,11 +2212,6 @@ def run(
|
|||
ret["comment"] = exc.__str__()
|
||||
return ret
|
||||
|
||||
cret = mod_run_check(onlyif, unless, creates)
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
if __opts__["test"]:
|
||||
ret["result"] = None
|
||||
ret["comment"] = "Container would be run{0}".format(
|
||||
|
@ -2532,82 +2509,6 @@ def absent(name, force=False):
|
|||
return ret
|
||||
|
||||
|
||||
def mod_run_check(onlyif, unless, creates):
|
||||
"""
|
||||
Execute the onlyif/unless/creates logic. Returns a result dict if any of
|
||||
the checks fail, otherwise returns True
|
||||
"""
|
||||
cmd_kwargs = {"use_vt": False, "bg": False}
|
||||
|
||||
if onlyif is not None:
|
||||
if isinstance(onlyif, six.string_types):
|
||||
onlyif = [onlyif]
|
||||
if not isinstance(onlyif, list) or not all(
|
||||
isinstance(x, six.string_types) for x in onlyif
|
||||
):
|
||||
return {
|
||||
"comment": "onlyif is not a string or list of strings",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
for entry in onlyif:
|
||||
retcode = __salt__["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True
|
||||
)
|
||||
if retcode != 0:
|
||||
return {
|
||||
"comment": "onlyif command {0} returned exit code of {1}".format(
|
||||
entry, retcode
|
||||
),
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
if unless is not None:
|
||||
if isinstance(unless, six.string_types):
|
||||
unless = [unless]
|
||||
if not isinstance(unless, list) or not all(
|
||||
isinstance(x, six.string_types) for x in unless
|
||||
):
|
||||
return {
|
||||
"comment": "unless is not a string or list of strings",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
for entry in unless:
|
||||
retcode = __salt__["cmd.retcode"](
|
||||
entry, ignore_retcode=True, python_shell=True
|
||||
)
|
||||
if retcode == 0:
|
||||
return {
|
||||
"comment": "unless command {0} returned exit code of {1}".format(
|
||||
entry, retcode
|
||||
),
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
if creates is not None:
|
||||
if isinstance(creates, six.string_types):
|
||||
creates = [creates]
|
||||
if not isinstance(creates, list) or not all(
|
||||
isinstance(x, six.string_types) for x in creates
|
||||
):
|
||||
return {
|
||||
"comment": "creates is not a string or list of strings",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
if all(os.path.exists(x) for x in creates):
|
||||
return {
|
||||
"comment": "All specified paths in 'creates' " "argument exist",
|
||||
"result": True,
|
||||
}
|
||||
|
||||
# No reason to stop, return True
|
||||
return True
|
||||
|
||||
|
||||
def mod_watch(name, sfun=None, **kwargs):
|
||||
"""
|
||||
The docker_container watcher, called to invoke the watch command.
|
||||
|
|
|
@ -13,7 +13,6 @@ States to manage git repositories and git configuration
|
|||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import python libs
|
||||
import copy
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
|
@ -281,8 +280,6 @@ def latest(
|
|||
identity=None,
|
||||
https_user=None,
|
||||
https_pass=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
refspec_branch="*",
|
||||
refspec_tag="*",
|
||||
output_encoding=None,
|
||||
|
@ -543,14 +540,6 @@ def latest(
|
|||
|
||||
.. versionadded:: 2015.5.0
|
||||
|
||||
onlyif
|
||||
A command to run as a check, run the named command only if the command
|
||||
passed to the ``onlyif`` option returns true
|
||||
|
||||
unless
|
||||
A command to run as a check, only run the named command if the command
|
||||
passed to the ``unless`` option returns false
|
||||
|
||||
refspec_branch : *
|
||||
A glob expression defining which branches to retrieve when fetching.
|
||||
See `git-fetch(1)`_ for more information on how refspecs work.
|
||||
|
@ -724,12 +713,6 @@ def latest(
|
|||
if "shell" in __grains__:
|
||||
run_check_cmd_kwargs["shell"] = __grains__["shell"]
|
||||
|
||||
# check if git.latest should be applied
|
||||
cret = mod_run_check(run_check_cmd_kwargs, onlyif, unless)
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
refspecs = (
|
||||
[
|
||||
"refs/heads/{0}:refs/remotes/{1}/{0}".format(refspec_branch, remote),
|
||||
|
@ -2207,8 +2190,6 @@ def detached(
|
|||
identity=None,
|
||||
https_user=None,
|
||||
https_pass=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
output_encoding=None,
|
||||
**kwargs
|
||||
):
|
||||
|
@ -2281,14 +2262,6 @@ def detached(
|
|||
https_pass
|
||||
HTTP Basic Auth password for HTTPS (only) clones
|
||||
|
||||
onlyif
|
||||
A command to run as a check, run the named command only if the command
|
||||
passed to the ``onlyif`` option returns true
|
||||
|
||||
unless
|
||||
A command to run as a check, only run the named command if the command
|
||||
passed to the ``unless`` option returns false
|
||||
|
||||
output_encoding
|
||||
Use this option to specify which encoding to use to decode the output
|
||||
from any git commands which are run. This should not be needed in most
|
||||
|
@ -2369,15 +2342,6 @@ def detached(
|
|||
|
||||
redacted_fetch_url = salt.utils.url.redact_http_basic_auth(desired_fetch_url)
|
||||
|
||||
# Check if onlyif or unless conditions match
|
||||
run_check_cmd_kwargs = {"runas": user}
|
||||
if "shell" in __grains__:
|
||||
run_check_cmd_kwargs["shell"] = __grains__["shell"]
|
||||
cret = mod_run_check(run_check_cmd_kwargs, onlyif, unless)
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
# Determine if supplied ref is a hash
|
||||
remote_rev_type = "ref"
|
||||
if len(rev) <= 40 and all(x in string.hexdigits for x in rev):
|
||||
|
@ -3337,76 +3301,3 @@ def config_set(
|
|||
value_comment,
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
def mod_run_check(cmd_kwargs, onlyif, unless):
|
||||
"""
|
||||
Execute the onlyif and unless logic. Return a result dict if:
|
||||
|
||||
* onlyif failed (onlyif != 0)
|
||||
* unless succeeded (unless == 0)
|
||||
|
||||
Otherwise, returns ``True``
|
||||
"""
|
||||
cmd_kwargs = copy.deepcopy(cmd_kwargs)
|
||||
cmd_kwargs.update(
|
||||
{"use_vt": False, "bg": False, "ignore_retcode": True, "python_shell": True}
|
||||
)
|
||||
|
||||
if onlyif is not None:
|
||||
if not isinstance(onlyif, list):
|
||||
onlyif = [onlyif]
|
||||
|
||||
for command in onlyif:
|
||||
if not isinstance(command, six.string_types) and command:
|
||||
# Boolean or some other non-string which resolves to True
|
||||
continue
|
||||
try:
|
||||
if __salt__["cmd.retcode"](command, **cmd_kwargs) == 0:
|
||||
# Command exited with a zero retcode
|
||||
continue
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
log.exception(
|
||||
"The following onlyif command raised an error: %s", command
|
||||
)
|
||||
return {
|
||||
"comment": "onlyif raised error ({0}), see log for "
|
||||
"more details".format(exc),
|
||||
"result": False,
|
||||
}
|
||||
|
||||
return {
|
||||
"comment": "onlyif condition is false",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
if unless is not None:
|
||||
if not isinstance(unless, list):
|
||||
unless = [unless]
|
||||
|
||||
for command in unless:
|
||||
if not isinstance(command, six.string_types) and not command:
|
||||
# Boolean or some other non-string which resolves to False
|
||||
break
|
||||
try:
|
||||
if __salt__["cmd.retcode"](command, **cmd_kwargs) != 0:
|
||||
# Command exited with a non-zero retcode
|
||||
break
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
log.exception(
|
||||
"The following unless command raised an error: %s", command
|
||||
)
|
||||
return {
|
||||
"comment": "unless raised error ({0}), see log for "
|
||||
"more details".format(exc),
|
||||
"result": False,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"comment": "unless condition is true",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
return True
|
||||
|
|
|
@ -54,9 +54,6 @@ def installed(
|
|||
store=False,
|
||||
app=False,
|
||||
mpkg=False,
|
||||
user=None,
|
||||
onlyif=None,
|
||||
unless=None,
|
||||
force=False,
|
||||
allow_untrusted=False,
|
||||
version_check=None,
|
||||
|
@ -84,17 +81,6 @@ def installed(
|
|||
mpkg
|
||||
Is the file a .mpkg? If so then we'll check all of the .pkg files found are installed
|
||||
|
||||
user
|
||||
Name of the user performing the unless or onlyif checks
|
||||
|
||||
onlyif
|
||||
A command to run as a check, run the named command only if the command
|
||||
passed to the ``onlyif`` option returns true
|
||||
|
||||
unless
|
||||
A command to run as a check, only run the named command if the command
|
||||
passed to the ``unless`` option returns false
|
||||
|
||||
force
|
||||
Force the package to be installed even if its already been found installed
|
||||
|
||||
|
@ -115,17 +101,6 @@ def installed(
|
|||
|
||||
real_pkg = name
|
||||
|
||||
# Check onlyif, unless first
|
||||
run_check_cmd_kwargs = {"runas": user, "python_shell": True}
|
||||
if "shell" in __grains__:
|
||||
run_check_cmd_kwargs["shell"] = __grains__["shell"]
|
||||
|
||||
cret = _mod_run_check(run_check_cmd_kwargs, onlyif, unless)
|
||||
|
||||
if isinstance(cret, dict):
|
||||
ret.update(cret)
|
||||
return ret
|
||||
|
||||
# Check version info
|
||||
if version_check is not None:
|
||||
split = version_check.split("=")
|
||||
|
@ -185,7 +160,7 @@ def installed(
|
|||
pkg_ids = [os.path.basename(name)]
|
||||
mount_point = os.path.dirname(name)
|
||||
|
||||
if onlyif is None and unless is None and version_check is None:
|
||||
if version_check is None:
|
||||
for p in pkg_ids:
|
||||
if target[-4:] == ".app":
|
||||
install_dir = target
|
||||
|
@ -262,31 +237,3 @@ def installed(
|
|||
__salt__["macpackage.unmount"](mount_point)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _mod_run_check(cmd_kwargs, onlyif, unless):
|
||||
"""
|
||||
Execute the onlyif and unless logic.
|
||||
Return a result dict if:
|
||||
* onlyif failed (onlyif != 0)
|
||||
* unless succeeded (unless == 0)
|
||||
else return True
|
||||
"""
|
||||
if onlyif:
|
||||
if __salt__["cmd.retcode"](onlyif, **cmd_kwargs) != 0:
|
||||
return {
|
||||
"comment": "onlyif condition is false",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
if unless:
|
||||
if __salt__["cmd.retcode"](unless, **cmd_kwargs) == 0:
|
||||
return {
|
||||
"comment": "unless condition is true",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
}
|
||||
|
||||
# No reason to stop, return True
|
||||
return True
|
||||
|
|
|
@ -1584,10 +1584,20 @@ def installed(
|
|||
|
||||
.. seealso:: unless and onlyif
|
||||
|
||||
You can use the :ref:`unless <unless-requisite>` or
|
||||
:ref:`onlyif <onlyif-requisite>` syntax to skip a full package run.
|
||||
This can be helpful in large environments with multiple states that
|
||||
include requisites for packages to be installed.
|
||||
If running pkg commands together with :ref:`aggregate <mod-aggregate-state>`
|
||||
isn't an option, you can use the :ref:`creates <creates-requisite>`,
|
||||
:ref:`unless <unless-requisite>`, or :ref:`onlyif <onlyif-requisite>`
|
||||
syntax to skip a full package run. This can be helpful in large environments
|
||||
with multiple states that include requisites for packages to be installed.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Using creates for a simple single-factor check
|
||||
install_nginx:
|
||||
pkg.installed:
|
||||
- name: nginx
|
||||
- creates:
|
||||
- /etc/nginx/nginx.conf
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -1600,6 +1610,12 @@ def installed(
|
|||
args:
|
||||
- /etc/nginx/nginx.conf
|
||||
|
||||
# Using unless with a shell test
|
||||
install_nginx:
|
||||
pkg.installed:
|
||||
- name: nginx
|
||||
- unless: test -f /etc/nginx/nginx.conf
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Using file.search for a two-factor check
|
||||
|
@ -1612,11 +1628,11 @@ def installed(
|
|||
- /etc/nginx/nginx.conf
|
||||
- 'user www-data;'
|
||||
|
||||
The above examples use two different methods to reasonably ensure
|
||||
The above examples use different methods to reasonably ensure
|
||||
that a package has already been installed. First, with checking for a
|
||||
file that would be created with the package. Second, by checking for
|
||||
specific text within a file that would be created or managed by salt.
|
||||
With these requisists satisfied, unless will return ``True`` and the
|
||||
With these requisists satisfied, creates/unless will return ``True`` and the
|
||||
``pkg.installed`` state will be skipped.
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
|
@ -891,11 +891,7 @@ class DockerContainerTestCase(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertSaltTrueReturn(ret)
|
||||
ret = ret[next(iter(ret))]
|
||||
self.assertFalse(ret["changes"])
|
||||
self.assertTrue(
|
||||
ret["comment"].startswith(
|
||||
"onlyif command /bin/false returned exit code of"
|
||||
)
|
||||
)
|
||||
self.assertTrue(ret["comment"].startswith("onlyif condition is false"))
|
||||
self.run_function("docker.rm", [name], force=True)
|
||||
|
||||
for cmd in ("/bin/true", ["/bin/true", "ls /"]):
|
||||
|
@ -936,9 +932,7 @@ class DockerContainerTestCase(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertSaltTrueReturn(ret)
|
||||
ret = ret[next(iter(ret))]
|
||||
self.assertFalse(ret["changes"])
|
||||
self.assertEqual(
|
||||
ret["comment"], "unless command /bin/true returned exit code of 0"
|
||||
)
|
||||
self.assertEqual(ret["comment"], "unless condition is true")
|
||||
self.run_function("docker.rm", [name], force=True)
|
||||
|
||||
for cmd in ("/bin/false", ["/bin/false", "ls /paththatdoesnotexist"]):
|
||||
|
@ -982,22 +976,34 @@ class DockerContainerTestCase(ModuleCase, SaltReturnAssertsMixin):
|
|||
good_file1 = _mkstemp()
|
||||
good_file2 = _mkstemp()
|
||||
|
||||
for path in (good_file1, [good_file1, good_file2]):
|
||||
log.debug("Trying %s", path)
|
||||
ret = self.run_state(
|
||||
"docker_container.run",
|
||||
name=name,
|
||||
image=self.image,
|
||||
command="whoami",
|
||||
creates=path,
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = ret[next(iter(ret))]
|
||||
self.assertFalse(ret["changes"])
|
||||
self.assertEqual(
|
||||
ret["comment"], "All specified paths in 'creates' argument exist"
|
||||
)
|
||||
self.run_function("docker.rm", [name], force=True)
|
||||
log.debug("Trying %s", good_file1)
|
||||
ret = self.run_state(
|
||||
"docker_container.run",
|
||||
name=name,
|
||||
image=self.image,
|
||||
command="whoami",
|
||||
creates=good_file1,
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = ret[next(iter(ret))]
|
||||
self.assertFalse(ret["changes"])
|
||||
self.assertEqual(ret["comment"], "{0} exists".format(good_file1))
|
||||
self.run_function("docker.rm", [name], force=True)
|
||||
|
||||
path = [good_file1, good_file2]
|
||||
log.debug("Trying %s", path)
|
||||
ret = self.run_state(
|
||||
"docker_container.run",
|
||||
name=name,
|
||||
image=self.image,
|
||||
command="whoami",
|
||||
creates=path,
|
||||
)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = ret[next(iter(ret))]
|
||||
self.assertFalse(ret["changes"])
|
||||
self.assertEqual(ret["comment"], "All files in creates exist")
|
||||
self.run_function("docker.rm", [name], force=True)
|
||||
|
||||
for path in (bad_file, [good_file1, bad_file]):
|
||||
log.debug("Trying %s", path)
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import os.path
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.states.cmd as cmd
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
@ -25,73 +23,6 @@ class CmdTestCase(TestCase, LoaderModuleMockMixin):
|
|||
def setup_loader_modules(self):
|
||||
return {cmd: {"__env__": "base"}}
|
||||
|
||||
# 'mod_run_check' function tests: 1
|
||||
|
||||
def test_mod_run_check(self):
|
||||
"""
|
||||
Test to execute the onlyif and unless logic.
|
||||
"""
|
||||
cmd_kwargs = {}
|
||||
creates = "/tmp"
|
||||
|
||||
mock = MagicMock(return_value=1)
|
||||
with patch.dict(cmd.__salt__, {"cmd.retcode": mock}):
|
||||
with patch.dict(cmd.__opts__, {"test": True}):
|
||||
ret = {
|
||||
"comment": "onlyif condition is false",
|
||||
"result": True,
|
||||
"skip_watch": True,
|
||||
}
|
||||
self.assertDictEqual(
|
||||
cmd.mod_run_check(cmd_kwargs, "", "", creates), ret
|
||||
)
|
||||
|
||||
self.assertDictEqual(
|
||||
cmd.mod_run_check(cmd_kwargs, {}, "", creates), ret
|
||||
)
|
||||
|
||||
mock = MagicMock(return_value=1)
|
||||
with patch.dict(cmd.__salt__, {"cmd.retcode": mock}):
|
||||
with patch.dict(cmd.__opts__, {"test": True}):
|
||||
ret = {
|
||||
"comment": "onlyif condition is false: ",
|
||||
"result": True,
|
||||
"skip_watch": True,
|
||||
}
|
||||
self.assertDictEqual(
|
||||
cmd.mod_run_check(cmd_kwargs, [""], "", creates), ret
|
||||
)
|
||||
|
||||
mock = MagicMock(return_value=0)
|
||||
with patch.dict(cmd.__salt__, {"cmd.retcode": mock}):
|
||||
ret = {
|
||||
"comment": "unless condition is true",
|
||||
"result": True,
|
||||
"skip_watch": True,
|
||||
}
|
||||
self.assertDictEqual(cmd.mod_run_check(cmd_kwargs, None, "", creates), ret)
|
||||
|
||||
self.assertDictEqual(
|
||||
cmd.mod_run_check(cmd_kwargs, None, [""], creates), ret
|
||||
)
|
||||
|
||||
self.assertDictEqual(
|
||||
cmd.mod_run_check(cmd_kwargs, None, True, creates), ret
|
||||
)
|
||||
|
||||
with patch.object(os.path, "exists", MagicMock(sid_effect=[True, True, False])):
|
||||
ret = {"comment": "/tmp exists", "result": True}
|
||||
self.assertDictEqual(
|
||||
cmd.mod_run_check(cmd_kwargs, None, None, creates), ret
|
||||
)
|
||||
|
||||
ret = {"comment": "All files in creates exist", "result": True}
|
||||
self.assertDictEqual(
|
||||
cmd.mod_run_check(cmd_kwargs, None, None, [creates]), ret
|
||||
)
|
||||
|
||||
self.assertTrue(cmd.mod_run_check(cmd_kwargs, None, None, {}))
|
||||
|
||||
# 'wait' function tests: 1
|
||||
|
||||
def test_wait(self):
|
||||
|
@ -153,13 +84,6 @@ class CmdTestCase(TestCase, LoaderModuleMockMixin):
|
|||
ret.update({"comment": comt, "result": None, "changes": {}})
|
||||
self.assertDictEqual(cmd.run(name), ret)
|
||||
|
||||
mock = MagicMock(return_value=1)
|
||||
with patch.dict(cmd.__salt__, {"cmd.retcode": mock}):
|
||||
with patch.dict(cmd.__opts__, {"test": False}):
|
||||
comt = "onlyif condition is false"
|
||||
ret.update({"comment": comt, "result": True, "skip_watch": True})
|
||||
self.assertDictEqual(cmd.run(name, onlyif=""), ret)
|
||||
|
||||
def test_run_root(self):
|
||||
"""
|
||||
Test to run a command with a different root
|
||||
|
@ -220,20 +144,6 @@ class CmdTestCase(TestCase, LoaderModuleMockMixin):
|
|||
)
|
||||
self.assertDictEqual(cmd.script(name), ret)
|
||||
|
||||
mock = MagicMock(return_value=1)
|
||||
with patch.dict(cmd.__salt__, {"cmd.retcode": mock}):
|
||||
with patch.dict(cmd.__opts__, {"test": False}):
|
||||
comt = "onlyif condition is false"
|
||||
ret.update(
|
||||
{
|
||||
"comment": comt,
|
||||
"result": True,
|
||||
"skip_watch": True,
|
||||
"changes": {},
|
||||
}
|
||||
)
|
||||
self.assertDictEqual(cmd.script(name, onlyif=""), ret)
|
||||
|
||||
# 'call' function tests: 1
|
||||
|
||||
def test_call(self):
|
||||
|
@ -262,24 +172,9 @@ class CmdTestCase(TestCase, LoaderModuleMockMixin):
|
|||
self.assertDictEqual(cmd.call(name, func), ret)
|
||||
|
||||
flag = False
|
||||
comt = "onlyif condition is false"
|
||||
ret.update({"comment": "", "result": False, "changes": {"retval": []}})
|
||||
self.assertDictEqual(cmd.call(name, func), ret)
|
||||
|
||||
mock = MagicMock(return_value=1)
|
||||
with patch.dict(cmd.__salt__, {"cmd.retcode": mock}):
|
||||
with patch.dict(cmd.__opts__, {"test": True}):
|
||||
comt = "onlyif condition is false"
|
||||
ret.update(
|
||||
{
|
||||
"comment": comt,
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
"changes": {},
|
||||
}
|
||||
)
|
||||
self.assertDictEqual(cmd.call(name, func, onlyif=""), ret)
|
||||
|
||||
# 'wait_call' function tests: 1
|
||||
|
||||
def test_wait_call(self):
|
||||
|
|
|
@ -23,233 +23,215 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"""
|
||||
Test installing a PKG file
|
||||
"""
|
||||
with patch("salt.states.macpackage._mod_run_check") as _mod_run_check_mock:
|
||||
expected = {
|
||||
"changes": {"installed": ["some.other.id"]},
|
||||
"comment": "/path/to/file.pkg installed",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
expected = {
|
||||
"changes": {"installed": ["some.other.id"]},
|
||||
"comment": "/path/to/file.pkg installed",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
|
||||
installed_mock = MagicMock(return_value=["com.apple.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
_mod_run_check_mock.return_value = True
|
||||
installed_mock = MagicMock(return_value=["com.apple.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.pkg")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/path/to/file.pkg")
|
||||
install_mock.assert_called_once_with(
|
||||
"/path/to/file.pkg", "LocalSystem", False, False
|
||||
)
|
||||
self.assertEqual(out, expected)
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.pkg")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/path/to/file.pkg")
|
||||
install_mock.assert_called_once_with(
|
||||
"/path/to/file.pkg", "LocalSystem", False, False
|
||||
)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_pkg_exists(self):
|
||||
"""
|
||||
Test installing a PKG file where it's already installed
|
||||
"""
|
||||
with patch("salt.states.macpackage._mod_run_check") as _mod_run_check_mock:
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
|
||||
installed_mock = MagicMock(return_value=["com.apple.id", "some.other.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
_mod_run_check_mock.return_value = True
|
||||
installed_mock = MagicMock(return_value=["com.apple.id", "some.other.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.pkg")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/path/to/file.pkg")
|
||||
assert not install_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.pkg")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/path/to/file.pkg")
|
||||
assert not install_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_pkg_version_succeeds(self):
|
||||
"""
|
||||
Test installing a PKG file where the version number matches the current installed version
|
||||
"""
|
||||
with patch("salt.states.macpackage._mod_run_check") as _mod_run_check_mock:
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "Version already matches .*5\\.1\\.[0-9]",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "Version already matches .*5\\.1\\.[0-9]",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
|
||||
installed_mock = MagicMock(return_value=["com.apple.id", "some.other.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
cmd_mock = MagicMock(return_value="Version of this: 5.1.9")
|
||||
_mod_run_check_mock.return_value = True
|
||||
installed_mock = MagicMock(return_value=["com.apple.id", "some.other.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
cmd_mock = MagicMock(return_value="Version of this: 5.1.9")
|
||||
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
"cmd.run": cmd_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed(
|
||||
"/path/to/file.pkg",
|
||||
version_check=r"/usr/bin/runme --version=.*5\.1\.[0-9]",
|
||||
)
|
||||
cmd_mock.assert_called_once_with(
|
||||
"/usr/bin/runme --version",
|
||||
output_loglevel="quiet",
|
||||
ignore_retcode=True,
|
||||
)
|
||||
assert not installed_mock.called
|
||||
assert not get_pkg_id_mock.called
|
||||
assert not install_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
"cmd.run": cmd_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed(
|
||||
"/path/to/file.pkg",
|
||||
version_check=r"/usr/bin/runme --version=.*5\.1\.[0-9]",
|
||||
)
|
||||
cmd_mock.assert_called_once_with(
|
||||
"/usr/bin/runme --version", output_loglevel="quiet", ignore_retcode=True
|
||||
)
|
||||
assert not installed_mock.called
|
||||
assert not get_pkg_id_mock.called
|
||||
assert not install_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_pkg_version_fails(self):
|
||||
"""
|
||||
Test installing a PKG file where the version number if different from the expected one
|
||||
"""
|
||||
with patch("salt.states.macpackage._mod_run_check") as _mod_run_check_mock:
|
||||
expected = {
|
||||
"changes": {"installed": ["some.other.id"]},
|
||||
"comment": "Version Version of this: 1.8.9 doesn't match .*5\\.1\\.[0-9]. /path/to/file.pkg installed",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
expected = {
|
||||
"changes": {"installed": ["some.other.id"]},
|
||||
"comment": "Version Version of this: 1.8.9 doesn't match .*5\\.1\\.[0-9]. /path/to/file.pkg installed",
|
||||
"name": "/path/to/file.pkg",
|
||||
"result": True,
|
||||
}
|
||||
|
||||
installed_mock = MagicMock(return_value=["com.apple.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
cmd_mock = MagicMock(return_value="Version of this: 1.8.9")
|
||||
_mod_run_check_mock.return_value = True
|
||||
installed_mock = MagicMock(return_value=["com.apple.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
cmd_mock = MagicMock(return_value="Version of this: 1.8.9")
|
||||
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
"cmd.run": cmd_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed(
|
||||
"/path/to/file.pkg",
|
||||
version_check=r"/usr/bin/runme --version=.*5\.1\.[0-9]",
|
||||
)
|
||||
cmd_mock.assert_called_once_with(
|
||||
"/usr/bin/runme --version",
|
||||
output_loglevel="quiet",
|
||||
ignore_retcode=True,
|
||||
)
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/path/to/file.pkg")
|
||||
install_mock.assert_called_once_with(
|
||||
"/path/to/file.pkg", "LocalSystem", False, False
|
||||
)
|
||||
self.assertEqual(out, expected)
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
"cmd.run": cmd_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed(
|
||||
"/path/to/file.pkg",
|
||||
version_check=r"/usr/bin/runme --version=.*5\.1\.[0-9]",
|
||||
)
|
||||
cmd_mock.assert_called_once_with(
|
||||
"/usr/bin/runme --version", output_loglevel="quiet", ignore_retcode=True
|
||||
)
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/path/to/file.pkg")
|
||||
install_mock.assert_called_once_with(
|
||||
"/path/to/file.pkg", "LocalSystem", False, False
|
||||
)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_dmg(self):
|
||||
"""
|
||||
Test installing a DMG file
|
||||
"""
|
||||
with patch("salt.states.macpackage._mod_run_check") as _mod_run_check_mock:
|
||||
expected = {
|
||||
"changes": {"installed": ["some.other.id"]},
|
||||
"comment": "/path/to/file.dmg installed",
|
||||
"name": "/path/to/file.dmg",
|
||||
"result": True,
|
||||
}
|
||||
expected = {
|
||||
"changes": {"installed": ["some.other.id"]},
|
||||
"comment": "/path/to/file.dmg installed",
|
||||
"name": "/path/to/file.dmg",
|
||||
"result": True,
|
||||
}
|
||||
|
||||
mount_mock = MagicMock(return_value=["success", "/tmp/dmg-X"])
|
||||
unmount_mock = MagicMock()
|
||||
installed_mock = MagicMock(return_value=["com.apple.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
_mod_run_check_mock.return_value = True
|
||||
mount_mock = MagicMock(return_value=["success", "/tmp/dmg-X"])
|
||||
unmount_mock = MagicMock()
|
||||
installed_mock = MagicMock(return_value=["com.apple.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.mount": mount_mock,
|
||||
"macpackage.unmount": unmount_mock,
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.dmg", dmg=True)
|
||||
mount_mock.assert_called_once_with("/path/to/file.dmg")
|
||||
unmount_mock.assert_called_once_with("/tmp/dmg-X")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/tmp/dmg-X/*.pkg")
|
||||
install_mock.assert_called_once_with(
|
||||
"/tmp/dmg-X/*.pkg", "LocalSystem", False, False
|
||||
)
|
||||
self.assertEqual(out, expected)
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.mount": mount_mock,
|
||||
"macpackage.unmount": unmount_mock,
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.dmg", dmg=True)
|
||||
mount_mock.assert_called_once_with("/path/to/file.dmg")
|
||||
unmount_mock.assert_called_once_with("/tmp/dmg-X")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/tmp/dmg-X/*.pkg")
|
||||
install_mock.assert_called_once_with(
|
||||
"/tmp/dmg-X/*.pkg", "LocalSystem", False, False
|
||||
)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_dmg_exists(self):
|
||||
"""
|
||||
Test installing a DMG file when the package already exists
|
||||
"""
|
||||
with patch("salt.states.macpackage._mod_run_check") as _mod_run_check_mock:
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "",
|
||||
"name": "/path/to/file.dmg",
|
||||
"result": True,
|
||||
}
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "",
|
||||
"name": "/path/to/file.dmg",
|
||||
"result": True,
|
||||
}
|
||||
|
||||
mount_mock = MagicMock(return_value=["success", "/tmp/dmg-X"])
|
||||
unmount_mock = MagicMock()
|
||||
installed_mock = MagicMock(return_value=["com.apple.id", "some.other.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
_mod_run_check_mock.return_value = True
|
||||
mount_mock = MagicMock(return_value=["success", "/tmp/dmg-X"])
|
||||
unmount_mock = MagicMock()
|
||||
installed_mock = MagicMock(return_value=["com.apple.id", "some.other.id"])
|
||||
get_pkg_id_mock = MagicMock(return_value=["some.other.id"])
|
||||
install_mock = MagicMock(return_value={"retcode": 0})
|
||||
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.mount": mount_mock,
|
||||
"macpackage.unmount": unmount_mock,
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.dmg", dmg=True)
|
||||
mount_mock.assert_called_once_with("/path/to/file.dmg")
|
||||
unmount_mock.assert_called_once_with("/tmp/dmg-X")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/tmp/dmg-X/*.pkg")
|
||||
assert not install_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
with patch.dict(
|
||||
macpackage.__salt__,
|
||||
{
|
||||
"macpackage.mount": mount_mock,
|
||||
"macpackage.unmount": unmount_mock,
|
||||
"macpackage.installed_pkgs": installed_mock,
|
||||
"macpackage.get_pkg_id": get_pkg_id_mock,
|
||||
"macpackage.install": install_mock,
|
||||
},
|
||||
):
|
||||
out = macpackage.installed("/path/to/file.dmg", dmg=True)
|
||||
mount_mock.assert_called_once_with("/path/to/file.dmg")
|
||||
unmount_mock.assert_called_once_with("/tmp/dmg-X")
|
||||
installed_mock.assert_called_once_with()
|
||||
get_pkg_id_mock.assert_called_once_with("/tmp/dmg-X/*.pkg")
|
||||
assert not install_mock.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_app(self):
|
||||
"""
|
||||
Test installing an APP file
|
||||
"""
|
||||
with patch(
|
||||
"salt.states.macpackage._mod_run_check"
|
||||
) as _mod_run_check_mock, patch("os.path.exists") as exists_mock:
|
||||
with patch("os.path.exists") as exists_mock:
|
||||
expected = {
|
||||
"changes": {"installed": ["file.app"]},
|
||||
"comment": "file.app installed",
|
||||
|
@ -258,7 +240,6 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
}
|
||||
|
||||
install_mock = MagicMock()
|
||||
_mod_run_check_mock.return_value = True
|
||||
exists_mock.return_value = False
|
||||
|
||||
with patch.dict(
|
||||
|
@ -275,9 +256,7 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"""
|
||||
Test installing an APP file that already exists
|
||||
"""
|
||||
with patch(
|
||||
"salt.states.macpackage._mod_run_check"
|
||||
) as _mod_run_check_mock, patch("os.path.exists") as exists_mock:
|
||||
with patch("os.path.exists") as exists_mock:
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "",
|
||||
|
@ -286,7 +265,6 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
}
|
||||
|
||||
install_mock = MagicMock()
|
||||
_mod_run_check_mock.return_value = True
|
||||
exists_mock.return_value = True
|
||||
|
||||
with patch.dict(
|
||||
|
@ -301,9 +279,7 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"""
|
||||
Test installing an APP file contained in a DMG file
|
||||
"""
|
||||
with patch(
|
||||
"salt.states.macpackage._mod_run_check"
|
||||
) as _mod_run_check_mock, patch("os.path.exists") as exists_mock:
|
||||
with patch("os.path.exists") as exists_mock:
|
||||
expected = {
|
||||
"changes": {"installed": ["file.app"]},
|
||||
"comment": "file.app installed",
|
||||
|
@ -315,7 +291,6 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
mount_mock = MagicMock(return_value=["success", "/tmp/dmg-X"])
|
||||
unmount_mock = MagicMock()
|
||||
cmd_mock = MagicMock(return_value="file.app")
|
||||
_mod_run_check_mock.return_value = True
|
||||
exists_mock.return_value = False
|
||||
|
||||
with patch.dict(
|
||||
|
@ -343,9 +318,7 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"""
|
||||
Test installing an APP file contained in a DMG file where the file exists
|
||||
"""
|
||||
with patch(
|
||||
"salt.states.macpackage._mod_run_check"
|
||||
) as _mod_run_check_mock, patch("os.path.exists") as exists_mock:
|
||||
with patch("os.path.exists") as exists_mock:
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "",
|
||||
|
@ -357,7 +330,6 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
mount_mock = MagicMock(return_value=["success", "/tmp/dmg-X"])
|
||||
unmount_mock = MagicMock()
|
||||
cmd_mock = MagicMock(return_value="file.app")
|
||||
_mod_run_check_mock.return_value = True
|
||||
exists_mock.return_value = True
|
||||
|
||||
with patch.dict(
|
||||
|
@ -411,39 +383,3 @@ class MacPackageTestCase(TestCase, LoaderModuleMockMixin):
|
|||
"/path/to/file.pkg", "LocalSystem", False, False
|
||||
)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_pkg_onlyif_fail(self,):
|
||||
"""
|
||||
Test installing a PKG file where the onlyif call fails
|
||||
"""
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "onlyif condition is false",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
"name": "/path/to/file.pkg",
|
||||
}
|
||||
|
||||
mock = MagicMock(return_value=1)
|
||||
|
||||
with patch.dict(macpackage.__salt__, {"cmd.retcode": mock}):
|
||||
out = macpackage.installed("/path/to/file.pkg", onlyif="some command")
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_installed_pkg_unless_fail(self,):
|
||||
"""
|
||||
Test installing a PKG file where the unless run fails
|
||||
"""
|
||||
expected = {
|
||||
"changes": {},
|
||||
"comment": "unless condition is true",
|
||||
"skip_watch": True,
|
||||
"result": True,
|
||||
"name": "/path/to/file.pkg",
|
||||
}
|
||||
|
||||
mock = MagicMock(return_value=0)
|
||||
|
||||
with patch.dict(macpackage.__salt__, {"cmd.retcode": mock}):
|
||||
out = macpackage.installed("/path/to/file.pkg", unless="some command")
|
||||
self.assertEqual(out, expected)
|
||||
|
|
|
@ -15,6 +15,7 @@ import salt.exceptions
|
|||
import salt.state
|
||||
import salt.utils.files
|
||||
import salt.utils.platform
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.utils.decorators import state as statedecorators
|
||||
from salt.utils.odict import OrderedDict
|
||||
from tests.support.helpers import with_tempfile
|
||||
|
@ -120,6 +121,70 @@ class StateCompilerTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
return_result = state_obj._run_check_onlyif(low_data, "")
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
def test_verify_onlyif_cmd_error(self):
|
||||
"""
|
||||
Simulates a failure in cmd.retcode from onlyif
|
||||
This could occur is runas is specified with a user that does not exist
|
||||
"""
|
||||
low_data = {
|
||||
"onlyif": "somecommand",
|
||||
"runas" "doesntexist" "name": "echo something",
|
||||
"state": "cmd",
|
||||
"__id__": "this is just a test",
|
||||
"fun": "run",
|
||||
"__env__": "base",
|
||||
"__sls__": "sometest",
|
||||
"order": 10000,
|
||||
}
|
||||
expected_result = {
|
||||
"comment": "onlyif condition is false",
|
||||
"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)
|
||||
mock = MagicMock(side_effect=CommandExecutionError("Boom!"))
|
||||
with patch.dict(state_obj.functions, {"cmd.retcode": mock}):
|
||||
# The mock handles the exception, but the runas dict is being passed as it would actually be
|
||||
return_result = state_obj._run_check_onlyif(
|
||||
low_data, {"runas": "doesntexist"}
|
||||
)
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
def test_verify_unless_cmd_error(self):
|
||||
"""
|
||||
Simulates a failure in cmd.retcode from unless
|
||||
This could occur is runas is specified with a user that does not exist
|
||||
"""
|
||||
low_data = {
|
||||
"unless": "somecommand",
|
||||
"runas" "doesntexist" "name": "echo something",
|
||||
"state": "cmd",
|
||||
"__id__": "this is just a test",
|
||||
"fun": "run",
|
||||
"__env__": "base",
|
||||
"__sls__": "sometest",
|
||||
"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)
|
||||
mock = MagicMock(side_effect=CommandExecutionError("Boom!"))
|
||||
with patch.dict(state_obj.functions, {"cmd.retcode": mock}):
|
||||
# The mock handles the exception, but the runas dict is being passed as it would actually be
|
||||
return_result = state_obj._run_check_unless(
|
||||
low_data, {"runas": "doesntexist"}
|
||||
)
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
def test_verify_unless_parse(self):
|
||||
low_data = {
|
||||
"unless": [{"fun": "test.arg", "args": ["arg1", "arg2"]}],
|
||||
|
@ -146,6 +211,72 @@ class StateCompilerTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
return_result = state_obj._run_check_unless(low_data, "")
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
def test_verify_creates(self):
|
||||
low_data = {
|
||||
"state": "cmd",
|
||||
"name": 'echo "something"',
|
||||
"__sls__": "tests.creates",
|
||||
"__env__": "base",
|
||||
"__id__": "do_a_thing",
|
||||
"creates": "/tmp/thing",
|
||||
"order": 10000,
|
||||
"fun": "run",
|
||||
}
|
||||
|
||||
with patch("salt.state.State._gather_pillar") as state_patch:
|
||||
minion_opts = self.get_temp_config("minion")
|
||||
state_obj = salt.state.State(minion_opts)
|
||||
with patch("os.path.exists") as path_mock:
|
||||
path_mock.return_value = True
|
||||
expected_result = {
|
||||
"comment": "/tmp/thing exists",
|
||||
"result": True,
|
||||
"skip_watch": True,
|
||||
}
|
||||
return_result = state_obj._run_check_creates(low_data)
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
path_mock.return_value = False
|
||||
expected_result = {
|
||||
"comment": "Creates files not found",
|
||||
"result": False,
|
||||
}
|
||||
return_result = state_obj._run_check_creates(low_data)
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
def test_verify_creates_list(self):
|
||||
low_data = {
|
||||
"state": "cmd",
|
||||
"name": 'echo "something"',
|
||||
"__sls__": "tests.creates",
|
||||
"__env__": "base",
|
||||
"__id__": "do_a_thing",
|
||||
"creates": ["/tmp/thing", "/tmp/thing2"],
|
||||
"order": 10000,
|
||||
"fun": "run",
|
||||
}
|
||||
|
||||
with patch("salt.state.State._gather_pillar") as state_patch:
|
||||
minion_opts = self.get_temp_config("minion")
|
||||
state_obj = salt.state.State(minion_opts)
|
||||
with patch("os.path.exists") as path_mock:
|
||||
path_mock.return_value = True
|
||||
expected_result = {
|
||||
"comment": "All files in creates exist",
|
||||
"result": True,
|
||||
"skip_watch": True,
|
||||
}
|
||||
return_result = state_obj._run_check_creates(low_data)
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
path_mock.return_value = False
|
||||
expected_result = {
|
||||
"comment": "Creates files not found",
|
||||
"result": False,
|
||||
}
|
||||
return_result = state_obj._run_check_creates(low_data)
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
def _expand_win_path(self, path):
|
||||
"""
|
||||
Expand C:/users/admini~1/appdata/local/temp/salt-tests-tmpdir/...
|
||||
|
@ -193,6 +324,28 @@ class StateCompilerTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
return_result = state_obj._run_check_onlyif(low_data, "")
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
def test_verify_onlyif_list_cmd(self):
|
||||
low_data = {
|
||||
"state": "cmd",
|
||||
"name": 'echo "something"',
|
||||
"__sls__": "tests.cmd",
|
||||
"__env__": "base",
|
||||
"__id__": "check onlyif",
|
||||
"onlyif": ["/bin/true", "/bin/false"],
|
||||
"order": 10001,
|
||||
"fun": "run",
|
||||
}
|
||||
expected_result = {
|
||||
"comment": "onlyif condition is false",
|
||||
"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_onlyif(low_data, {})
|
||||
self.assertEqual(expected_result, return_result)
|
||||
|
||||
@with_tempfile()
|
||||
def test_verify_unless_parse_slots(self, name):
|
||||
with salt.utils.files.fopen(name, "w") as fp:
|
||||
|
|
Loading…
Add table
Reference in a new issue