Merge pull request #45851 from garethgreenaway/38625_overriding_retcode

[develop] Ability to override retcode from various cmdmod functions
This commit is contained in:
Nicole Thomas 2018-02-16 14:54:55 -05:00 committed by GitHub
commit 7897d7922c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 267 additions and 87 deletions

View file

@ -274,6 +274,7 @@ def _run(cmd,
password=None,
bg=False,
encoded_cmd=False,
success_retcodes=None,
**kwargs):
'''
Do the DRY thing and only call subprocess.Popen() once
@ -567,6 +568,18 @@ def _run(cmd,
and not isinstance(cmd, list):
cmd = salt.utils.args.shlex_split(cmd)
if success_retcodes is None:
success_retcodes = [0]
else:
try:
success_retcodes = [int(i) for i in
salt.utils.args.split_input(
success_retcodes
)]
except ValueError:
raise SaltInvocationError(
'success_retcodes must be a list of integers'
)
if not use_vt:
# This is where the magic happens
try:
@ -626,6 +639,8 @@ def _run(cmd,
err = err.rstrip()
ret['pid'] = proc.process.pid
ret['retcode'] = proc.process.returncode
if ret['retcode'] in success_retcodes:
ret['retcode'] = 0
ret['stdout'] = out
ret['stderr'] = err
else:
@ -695,6 +710,8 @@ def _run(cmd,
# the timeout
ret['stderr'] = stderr
ret['retcode'] = proc.exitstatus
if ret['retcode'] in success_retcodes:
ret['retcode'] = 0
ret['pid'] = proc.pid
finally:
proc.close(terminate=True, kill=True)
@ -722,7 +739,8 @@ def _run_quiet(cmd,
reset_system_locale=True,
saltenv='base',
pillarenv=None,
pillar_override=None):
pillar_override=None,
success_retcodes=None):
'''
Helper for running commands quietly for minion startup
'''
@ -742,7 +760,8 @@ def _run_quiet(cmd,
reset_system_locale=reset_system_locale,
saltenv=saltenv,
pillarenv=pillarenv,
pillar_override=pillar_override)['stdout']
pillar_override=pillar_override,
success_retcodes=success_retcodes)['stdout']
def _run_all_quiet(cmd,
@ -759,7 +778,8 @@ def _run_all_quiet(cmd,
saltenv='base',
pillarenv=None,
pillar_override=None,
output_loglevel=None):
output_loglevel=None,
success_retcodes=None):
'''
Helper for running commands quietly for minion startup.
@ -785,7 +805,8 @@ def _run_all_quiet(cmd,
reset_system_locale=reset_system_locale,
saltenv=saltenv,
pillarenv=pillarenv,
pillar_override=pillar_override)
pillar_override=pillar_override,
success_retcodes=success_retcodes)
def run(cmd,
@ -813,6 +834,7 @@ def run(cmd,
encoded_cmd=False,
raise_err=False,
prepend_path=None,
success_retcodes=None,
**kwargs):
r'''
Execute the passed command and return the output as a string
@ -951,6 +973,13 @@ def run(cmd,
Be absolutely certain that you have sanitized your input prior to using
python_shell=True
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -1014,6 +1043,7 @@ def run(cmd,
bg=bg,
password=password,
encoded_cmd=encoded_cmd,
success_retcodes=success_retcodes,
**kwargs)
log_callback = _check_cb(log_callback)
@ -1039,28 +1069,29 @@ def run(cmd,
def shell(cmd,
cwd=None,
stdin=None,
runas=None,
group=None,
shell=DEFAULT_SHELL,
env=None,
clean_env=False,
template=None,
rstrip=True,
umask=None,
output_loglevel='debug',
log_callback=None,
hide_output=False,
timeout=None,
reset_system_locale=True,
ignore_retcode=False,
saltenv='base',
use_vt=False,
bg=False,
password=None,
prepend_path=None,
**kwargs):
cwd=None,
stdin=None,
runas=None,
group=None,
shell=DEFAULT_SHELL,
env=None,
clean_env=False,
template=None,
rstrip=True,
umask=None,
output_loglevel='debug',
log_callback=None,
hide_output=False,
timeout=None,
reset_system_locale=True,
ignore_retcode=False,
saltenv='base',
use_vt=False,
bg=False,
password=None,
prepend_path=None,
success_retcodes=None,
**kwargs):
'''
Execute the passed command and return the output as a string.
@ -1185,6 +1216,12 @@ def shell(cmd,
``env`` represents the environment variables for the command, and
should be formatted as a dict, or a YAML string which resolves to a dict.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -1249,6 +1286,7 @@ def shell(cmd,
python_shell=python_shell,
bg=bg,
password=password,
success_retcodes=success_retcodes,
**kwargs)
@ -1274,6 +1312,7 @@ def run_stdout(cmd,
use_vt=False,
password=None,
prepend_path=None,
success_retcodes=None,
**kwargs):
'''
Execute a command, and only return the standard out
@ -1388,6 +1427,12 @@ def run_stdout(cmd,
``env`` represents the environment variables for the command, and
should be formatted as a dict, or a YAML string which resolves to a dict.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -1433,6 +1478,7 @@ def run_stdout(cmd,
saltenv=saltenv,
use_vt=use_vt,
password=password,
success_retcodes=success_retcodes,
**kwargs)
log_callback = _check_cb(log_callback)
@ -1480,6 +1526,7 @@ def run_stderr(cmd,
use_vt=False,
password=None,
prepend_path=None,
success_retcodes=None,
**kwargs):
'''
Execute a command and only return the standard error
@ -1595,6 +1642,12 @@ def run_stderr(cmd,
``env`` represents the environment variables for the command, and
should be formatted as a dict, or a YAML string which resolves to a dict.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -1640,6 +1693,7 @@ def run_stderr(cmd,
use_vt=use_vt,
saltenv=saltenv,
password=password,
success_retcodes=success_retcodes,
**kwargs)
log_callback = _check_cb(log_callback)
@ -1689,6 +1743,7 @@ def run_all(cmd,
password=None,
encoded_cmd=False,
prepend_path=None,
success_retcodes=None,
**kwargs):
'''
Execute the passed command and return a dict of return data
@ -1826,6 +1881,12 @@ def run_all(cmd,
.. versionadded:: 2016.3.6
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -1874,6 +1935,7 @@ def run_all(cmd,
use_vt=use_vt,
password=password,
encoded_cmd=encoded_cmd,
success_retcodes=success_retcodes,
**kwargs)
log_callback = _check_cb(log_callback)
@ -1921,6 +1983,7 @@ def retcode(cmd,
saltenv='base',
use_vt=False,
password=None,
success_retcodes=None,
**kwargs):
'''
Execute a shell command and return the command's return code.
@ -2023,6 +2086,12 @@ def retcode(cmd,
:rtype: None
:returns: Return Code as an int or None if there was an exception.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -2065,6 +2134,7 @@ def retcode(cmd,
saltenv=saltenv,
use_vt=use_vt,
password=password,
success_retcodes=success_retcodes,
**kwargs)
log_callback = _check_cb(log_callback)
@ -2104,6 +2174,7 @@ def _retcode_quiet(cmd,
saltenv='base',
use_vt=False,
password=None,
success_retcodes=None,
**kwargs):
'''
Helper for running commands quietly for minion startup.
@ -2128,6 +2199,7 @@ def _retcode_quiet(cmd,
saltenv=saltenv,
use_vt=use_vt,
password=password,
success_retcodes=success_retcodes,
**kwargs)
@ -2151,6 +2223,7 @@ def script(source,
use_vt=False,
bg=False,
password=None,
success_retcodes=None,
**kwargs):
'''
Download a script from a remote location and execute the script locally.
@ -2266,6 +2339,12 @@ def script(source,
:param bool use_vt: Use VT utils (saltstack) to stream the command output
more interactively to the console and the logs. This is experimental.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -2360,6 +2439,7 @@ def script(source,
use_vt=use_vt,
bg=bg,
password=password,
success_retcodes=success_retcodes,
**kwargs)
if salt.utils.platform.is_windows() and runas:
_cleanup_tempfile(cwd)
@ -2389,6 +2469,7 @@ def script_retcode(source,
log_callback=None,
use_vt=False,
password=None,
success_retcodes=None,
**kwargs):
'''
Download a script from a remote location and execute the script locally.
@ -2502,6 +2583,12 @@ def script_retcode(source,
:param bool use_vt: Use VT utils (saltstack) to stream the command output
more interactively to the console and the logs. This is experimental.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -2540,6 +2627,7 @@ def script_retcode(source,
log_callback=log_callback,
use_vt=use_vt,
password=password,
success_retcodes=success_retcodes,
**kwargs)['retcode']
@ -2692,6 +2780,7 @@ def run_chroot(root,
saltenv='base',
use_vt=False,
bg=False,
success_retcodes=None,
**kwargs):
'''
.. versionadded:: 2014.7.0
@ -2808,7 +2897,13 @@ def run_chroot(root,
This is experimental.
CLI Example:
success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -2855,6 +2950,7 @@ def run_chroot(root,
pillarenv=kwargs.get('pillarenv'),
pillar=kwargs.get('pillar'),
use_vt=use_vt,
success_retcodes=success_retcodes,
bg=bg)
# Kill processes running in the chroot
@ -3116,26 +3212,27 @@ def shell_info(shell, list_modules=False):
def powershell(cmd,
cwd=None,
stdin=None,
runas=None,
shell=DEFAULT_SHELL,
env=None,
clean_env=False,
template=None,
rstrip=True,
umask=None,
output_loglevel='debug',
hide_output=False,
timeout=None,
reset_system_locale=True,
ignore_retcode=False,
saltenv='base',
use_vt=False,
password=None,
depth=None,
encode_cmd=False,
**kwargs):
cwd=None,
stdin=None,
runas=None,
shell=DEFAULT_SHELL,
env=None,
clean_env=False,
template=None,
rstrip=True,
umask=None,
output_loglevel='debug',
hide_output=False,
timeout=None,
reset_system_locale=True,
ignore_retcode=False,
saltenv='base',
use_vt=False,
password=None,
depth=None,
encode_cmd=False,
success_retcodes=None,
**kwargs):
'''
Execute the passed PowerShell command and return the output as a dictionary.
@ -3290,6 +3387,13 @@ def powershell(cmd,
where characters may be dropped or incorrectly converted when executed.
Default is False.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
:returns:
:dict: A dictionary of data returned by the powershell command.
@ -3347,6 +3451,7 @@ def powershell(cmd,
python_shell=python_shell,
password=password,
encoded_cmd=encoded_cmd,
success_retcodes=success_retcodes,
**kwargs)
try:
@ -3377,6 +3482,7 @@ def powershell_all(cmd,
depth=None,
encode_cmd=False,
force_list=False,
success_retcodes=None,
**kwargs):
'''
Execute the passed PowerShell command and return a dictionary with a result field
@ -3570,6 +3676,13 @@ def powershell_all(cmd,
:param bool force_list: The purpose of this paramater is described in the preamble
of this function's documentation. Default value is False.
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
:return: A dictionary with the following entries:
result
@ -3624,26 +3737,27 @@ def powershell_all(cmd,
# Retrieve the response, while overriding shell with 'powershell'
response = run_all(cmd,
cwd=cwd,
stdin=stdin,
runas=runas,
shell='powershell',
env=env,
clean_env=clean_env,
template=template,
rstrip=rstrip,
umask=umask,
output_loglevel=output_loglevel,
quiet=quiet,
timeout=timeout,
reset_system_locale=reset_system_locale,
ignore_retcode=ignore_retcode,
saltenv=saltenv,
use_vt=use_vt,
python_shell=python_shell,
password=password,
encoded_cmd=encoded_cmd,
**kwargs)
cwd=cwd,
stdin=stdin,
runas=runas,
shell='powershell',
env=env,
clean_env=clean_env,
template=template,
rstrip=rstrip,
umask=umask,
output_loglevel=output_loglevel,
quiet=quiet,
timeout=timeout,
reset_system_locale=reset_system_locale,
ignore_retcode=ignore_retcode,
saltenv=saltenv,
use_vt=use_vt,
python_shell=python_shell,
password=password,
encoded_cmd=encoded_cmd,
success_retcodes=success_retcodes,
**kwargs)
stdoutput = response['stdout']
# if stdoutput is the empty string and force_list is True we return an empty list
@ -3680,24 +3794,25 @@ def powershell_all(cmd,
def run_bg(cmd,
cwd=None,
runas=None,
group=None,
shell=DEFAULT_SHELL,
python_shell=None,
env=None,
clean_env=False,
template=None,
umask=None,
timeout=None,
output_loglevel='debug',
log_callback=None,
reset_system_locale=True,
ignore_retcode=False,
saltenv='base',
password=None,
prepend_path=None,
**kwargs):
cwd=None,
runas=None,
group=None,
shell=DEFAULT_SHELL,
python_shell=None,
env=None,
clean_env=False,
template=None,
umask=None,
timeout=None,
output_loglevel='debug',
log_callback=None,
reset_system_locale=True,
ignore_retcode=False,
saltenv='base',
password=None,
prepend_path=None,
success_retcodes=None,
**kwargs):
r'''
.. versionadded: 2016.3.0
@ -3810,6 +3925,13 @@ def run_bg(cmd,
Be absolutely certain that you have sanitized your input prior to using
python_shell=True
:param list success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
CLI Example:
.. code-block:: bash
@ -3867,6 +3989,7 @@ def run_bg(cmd,
ignore_retcode=ignore_retcode,
saltenv=saltenv,
password=password,
success_retcodes=success_retcodes,
**kwargs
)

View file

@ -411,6 +411,7 @@ def wait(name,
output_loglevel='debug',
hide_output=False,
use_vt=False,
success_retcodes=None,
**kwargs):
'''
Run the given command only if the watch statement calls it.
@ -515,6 +516,13 @@ def wait(name,
Use VT utils (saltstack) to stream the command output more
interactively to the console and the logs.
This is experimental.
success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
'''
# Ignoring our arguments is intentional.
return {'name': name,
@ -647,6 +655,13 @@ def wait_script(name,
Salt logs to the minion log.
.. versionadded:: Oxygen
success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
'''
# Ignoring our arguments is intentional.
return {'name': name,
@ -671,6 +686,7 @@ def run(name,
timeout=None,
ignore_timeout=False,
use_vt=False,
success_retcodes=None,
**kwargs):
'''
Run a command if certain circumstances are met. Use ``cmd.wait`` if you
@ -801,6 +817,13 @@ def run(name,
.. versionadded:: 2016.3.6
success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
.. note::
cmd.run supports the usage of ``reload_modules``. This functionality
@ -868,7 +891,8 @@ def run(name,
'umask': umask,
'output_loglevel': output_loglevel,
'hide_output': hide_output,
'quiet': quiet})
'quiet': quiet,
'success_retcodes': success_retcodes})
cret = mod_run_check(cmd_kwargs, onlyif, unless, creates)
if isinstance(cret, dict):
@ -932,6 +956,7 @@ def script(name,
hide_output=False,
defaults=None,
context=None,
success_retcodes=None,
**kwargs):
'''
Download a script and execute it with specified arguments.
@ -1064,6 +1089,14 @@ def script(name,
Salt logs to the minion log.
.. versionadded:: Oxygen
success_retcodes: This parameter will be allow a list of
non-zero return codes that should be considered a success. If the
return code returned from the run matches any in the provided list,
the return code will be overridden with zero.
.. versionadded:: Fluorine
'''
test_name = None
if not isinstance(stateful, list):
@ -1112,7 +1145,8 @@ def script(name,
'hide_output': hide_output,
'use_vt': use_vt,
'context': tmpctx,
'saltenv': __env__})
'saltenv': __env__,
'success_retcodes': success_retcodes})
run_check_cmd_kwargs = {
'cwd': cwd,

View file

@ -115,6 +115,29 @@ class CMDModuleTest(ModuleCase):
self.assertEqual(self.run_function('cmd.retcode', ['exit 0'], python_shell=True), 0)
self.assertEqual(self.run_function('cmd.retcode', ['exit 1'], python_shell=True), 1)
def test_run_all_with_success_retcodes(self):
'''
cmd.run with success_retcodes
'''
ret = self.run_function('cmd.run_all',
['exit 42'],
success_retcodes=[42],
python_shell=True)
self.assertTrue('retcode' in ret)
self.assertEqual(ret.get('retcode'), 0)
def test_retcode_with_success_retcodes(self):
'''
cmd.run with success_retcodes
'''
ret = self.run_function('cmd.retcode',
['exit 42'],
success_retcodes=[42],
python_shell=True)
self.assertEqual(ret, 0)
def test_blacklist_glob(self):
'''
cmd_blacklist_glob