1"""
2Execution of arbitrary commands
3===============================
4
5The cmd state module manages the enforcement of executed commands, this
6state can tell a command to run under certain circumstances.
7
8
9A simple example to execute a command:
10
11.. code-block:: yaml
12
13    # Store the current date in a file
14    'date > /tmp/salt-run':
15      cmd.run
16
17Only run if another execution failed, in this case truncate syslog if there is
18no disk space:
19
20.. code-block:: yaml
21
22    '> /var/log/messages/':
23      cmd.run:
24        - unless: echo 'foo' > /tmp/.test && rm -f /tmp/.test
25
26Only run if the file specified by ``creates`` does not exist, in this case
27touch /tmp/foo if it does not exist:
28
29.. code-block:: yaml
30
31    touch /tmp/foo:
32      cmd.run:
33        - creates: /tmp/foo
34
35``creates`` also accepts a list of files, in which case this state will
36run if **any** of the files do not exist:
37
38.. code-block:: yaml
39
40    "echo 'foo' | tee /tmp/bar > /tmp/baz":
41      cmd.run:
42        - creates:
43          - /tmp/bar
44          - /tmp/baz
45
46.. note::
47
48    The ``creates`` option was added to the cmd state in version 2014.7.0,
49    and made a global requisite in 3001.
50
51Sometimes when running a command that starts up a daemon, the init script
52doesn't return properly which causes Salt to wait indefinitely for a response.
53In situations like this try the following:
54
55.. code-block:: yaml
56
57    run_installer:
58      cmd.run:
59        - name: /tmp/installer.bin > /dev/null 2>&1
60
61Salt determines whether the ``cmd`` state is successfully enforced based on the exit
62code returned by the command. If the command returns a zero exit code, then salt
63determines that the state was successfully enforced. If the script returns a non-zero
64exit code, then salt determines that it failed to successfully enforce the state.
65If a command returns a non-zero exit code but you wish to treat this as a success,
66then you must place the command in a script and explicitly set the exit code of
67the script to zero.
68
69Please note that the success or failure of the state is not affected by whether a state
70change occurred nor the stateful argument.
71
72When executing a command or script, the state (i.e., changed or not)
73of the command is unknown to Salt's state system. Therefore, by default, the
74``cmd`` state assumes that any command execution results in a changed state.
75
76This means that if a ``cmd`` state is watched by another state then the
77state that's watching will always be executed due to the `changed` state in
78the ``cmd`` state.
79
80.. _stateful-argument:
81
82Using the "Stateful" Argument
83-----------------------------
84
85Many state functions in this module now also accept a ``stateful`` argument.
86If ``stateful`` is specified to be true then it is assumed that the command
87or script will determine its own state and communicate it back by following
88a simple protocol described below:
89
901. :strong:`If there's nothing in the stdout of the command, then assume no
91   changes.` Otherwise, the stdout must be either in JSON or its `last`
92   non-empty line must be a string of key=value pairs delimited by spaces (no
93   spaces on either side of ``=``).
94
952. :strong:`If it's JSON then it must be a JSON object (e.g., {}).` If it's
96   key=value pairs then quoting may be used to include spaces.  (Python's shlex
97   module is used to parse the key=value string)
98
99   Two special keys or attributes are recognized in the output::
100
101    changed: bool (i.e., 'yes', 'no', 'true', 'false', case-insensitive)
102    comment: str  (i.e., any string)
103
104   So, only if ``changed`` is ``True`` then assume the command execution has
105   changed the state, and any other key values or attributes in the output will
106   be set as part of the changes.
107
1083. :strong:`If there's a comment then it will be used as the comment of the
109   state.`
110
111   Here's an example of how one might write a shell script for use with a
112   stateful command:
113
114   .. code-block:: bash
115
116       #!/bin/bash
117       #
118       echo "Working hard..."
119
120       # writing the state line
121       echo  # an empty line here so the next line will be the last.
122       echo "changed=yes comment='something has changed' whatever=123"
123
124   And an example SLS file using this module:
125
126   .. code-block:: yaml
127
128       Run myscript:
129         cmd.run:
130           - name: /path/to/myscript
131           - cwd: /
132           - stateful: True
133
134       Run only if myscript changed something:
135         cmd.run:
136           - name: echo hello
137           - cwd: /
138           - onchanges:
139               - cmd: Run myscript
140
141   Note that if the second ``cmd.run`` state also specifies ``stateful: True`` it can
142   then be watched by some other states as well.
143
1444. :strong:`The stateful argument can optionally include a test_name parameter.`
145
146   This is used to specify a command to run in test mode.  This command should
147   return stateful data for changes that would be made by the command in the
148   name parameter.
149
150   .. versionadded:: 2015.2.0
151
152   .. code-block:: yaml
153
154       Run myscript:
155         cmd.run:
156           - name: /path/to/myscript
157           - cwd: /
158           - stateful:
159             - test_name: /path/to/myscript test
160
161       Run masterscript:
162         cmd.script:
163           - name: masterscript
164           - source: salt://path/to/masterscript
165           - cwd: /
166           - stateful:
167             - test_name: masterscript test
168
169
170Should I use :mod:`cmd.run <salt.states.cmd.run>` or :mod:`cmd.wait <salt.states.cmd.wait>`?
171--------------------------------------------------------------------------------------------
172
173.. note::
174
175    Use :mod:`cmd.run <salt.states.cmd.run>` together with :ref:`onchanges <requisites-onchanges>`
176    instead of :mod:`cmd.wait <salt.states.cmd.wait>`.
177
178These two states are often confused. The important thing to remember about them
179is that :mod:`cmd.run <salt.states.cmd.run>` states are run each time the SLS
180file that contains them is applied. If it is more desirable to have a command
181that only runs after some other state changes, then :mod:`cmd.wait
182<salt.states.cmd.wait>` does just that. :mod:`cmd.wait <salt.states.cmd.wait>`
183is designed to :ref:`watch <requisites-watch>` other states, and is
184executed when the state it is watching changes. Example:
185
186.. code-block:: yaml
187
188    /usr/local/bin/postinstall.sh:
189      cmd.wait:
190        - watch:
191          - pkg: mycustompkg
192      file.managed:
193        - source: salt://utils/scripts/postinstall.sh
194
195    mycustompkg:
196      pkg.installed:
197        - require:
198          - file: /usr/local/bin/postinstall.sh
199
200``cmd.wait`` itself do not do anything; all functionality is inside its ``mod_watch``
201function, which is called by ``watch`` on changes.
202
203The preferred format is using the :ref:`onchanges Requisite <requisites-onchanges>`, which
204works on ``cmd.run`` as well as on any other state. The example would then look as follows:
205
206.. code-block:: yaml
207
208    /usr/local/bin/postinstall.sh:
209      cmd.run:
210        - onchanges:
211          - pkg: mycustompkg
212      file.managed:
213        - source: salt://utils/scripts/postinstall.sh
214
215    mycustompkg:
216      pkg.installed:
217        - require:
218          - file: /usr/local/bin/postinstall.sh
219
220How do I create an environment from a pillar map?
221-------------------------------------------------
222
223The map that comes from a pillar can be directly consumed by the env option!
224To use it, one may pass it like this. Example:
225
226.. code-block:: yaml
227
228    printenv:
229      cmd.run:
230        - env: {{ salt['pillar.get']('example:key', {}) }}
231
232"""
233
234
235import copy
236import logging
237import os
238
239import salt.utils.args
240import salt.utils.functools
241import salt.utils.json
242import salt.utils.platform
243from salt.exceptions import CommandExecutionError, SaltRenderError
244
245log = logging.getLogger(__name__)
246
247
248def _reinterpreted_state(state):
249    """
250    Re-interpret the state returned by salt.state.run using our protocol.
251    """
252    ret = state["changes"]
253    state["changes"] = {}
254    state["comment"] = ""
255
256    out = ret.get("stdout")
257    if not out:
258        if ret.get("stderr"):
259            state["comment"] = ret["stderr"]
260        return state
261
262    is_json = False
263    try:
264        data = salt.utils.json.loads(out)
265        if not isinstance(data, dict):
266            return _failout(
267                state, "script JSON output must be a JSON object (e.g., {})!"
268            )
269        is_json = True
270    except ValueError:
271        idx = out.rstrip().rfind("\n")
272        if idx != -1:
273            out = out[idx + 1 :]
274        data = {}
275        try:
276            for item in salt.utils.args.shlex_split(out):
277                key, val = item.split("=")
278                data[key] = val
279        except ValueError:
280            state = _failout(
281                state,
282                "Failed parsing script output! "
283                "Stdout must be JSON or a line of name=value pairs.",
284            )
285            state["changes"].update(ret)
286            return state
287
288    changed = _is_true(data.get("changed", "no"))
289
290    if "comment" in data:
291        state["comment"] = data["comment"]
292        del data["comment"]
293
294    if changed:
295        for key in ret:
296            data.setdefault(key, ret[key])
297
298        # if stdout is the state output in JSON, don't show it.
299        # otherwise it contains the one line name=value pairs, strip it.
300        data["stdout"] = "" if is_json else data.get("stdout", "")[:idx]
301        state["changes"] = data
302
303    # FIXME: if it's not changed but there's stdout and/or stderr then those
304    #       won't be shown as the function output. (though, they will be shown
305    #       inside INFO logs).
306    return state
307
308
309def _failout(state, msg):
310    state["comment"] = msg
311    state["result"] = False
312    return state
313
314
315def _is_true(val):
316    if val and str(val).lower() in ("true", "yes", "1"):
317        return True
318    elif str(val).lower() in ("false", "no", "0"):
319        return False
320    raise ValueError("Failed parsing boolean value: {}".format(val))
321
322
323def wait(
324    name,
325    cwd=None,
326    root=None,
327    runas=None,
328    shell=None,
329    env=(),
330    stateful=False,
331    umask=None,
332    output_loglevel="debug",
333    hide_output=False,
334    use_vt=False,
335    success_retcodes=None,
336    success_stdout=None,
337    success_stderr=None,
338    **kwargs
339):
340    """
341    Run the given command only if the watch statement calls it.
342
343    .. note::
344
345        Use :mod:`cmd.run <salt.states.cmd.run>` together with :mod:`onchanges </ref/states/requisites#onchanges>`
346        instead of :mod:`cmd.wait <salt.states.cmd.wait>`.
347
348    name
349        The command to execute, remember that the command will execute with the
350        path and permissions of the salt-minion.
351
352    cwd
353        The current working directory to execute the command in, defaults to
354        /root
355
356    root
357        Path to the root of the jail to use. If this parameter is set, the command
358        will run inside a chroot
359
360    runas
361        The user name to run the command as
362
363    shell
364        The shell to use for execution, defaults to /bin/sh
365
366    env
367        A list of environment variables to be set prior to execution.
368        Example:
369
370        .. code-block:: yaml
371
372            script-foo:
373              cmd.wait:
374                - env:
375                  - BATCH: 'yes'
376
377        .. warning::
378
379            The above illustrates a common PyYAML pitfall, that **yes**,
380            **no**, **on**, **off**, **true**, and **false** are all loaded as
381            boolean ``True`` and ``False`` values, and must be enclosed in
382            quotes to be used as strings. More info on this (and other) PyYAML
383            idiosyncrasies can be found :ref:`here <yaml-idiosyncrasies>`.
384
385        Variables as values are not evaluated. So $PATH in the following
386        example is a literal '$PATH':
387
388        .. code-block:: yaml
389
390            script-bar:
391              cmd.wait:
392                - env: "PATH=/some/path:$PATH"
393
394        One can still use the existing $PATH by using a bit of Jinja:
395
396        .. code-block:: jinja
397
398            {% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}
399
400            mycommand:
401              cmd.run:
402                - name: ls -l /
403                - env:
404                  - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
405
406        .. note::
407            When using environment variables on Windows, case-sensitivity
408            matters, i.e. Windows uses `Path` as opposed to `PATH` for other
409            systems.
410
411    umask
412         The umask (in octal) to use when running the command.
413
414    stateful
415        The command being executed is expected to return data about executing
416        a state. For more information, see the :ref:`stateful-argument` section.
417
418    creates
419        Only run if the file specified by ``creates`` do not exist. If you
420        specify a list of files then this state will only run if **any** of
421        the files do not exist.
422
423        .. versionadded:: 2014.7.0
424
425    output_loglevel : debug
426        Control the loglevel at which the output from the command is logged to
427        the minion log.
428
429        .. note::
430            The command being run will still be logged at the ``debug``
431            loglevel regardless, unless ``quiet`` is used for this value.
432
433    hide_output : False
434        Suppress stdout and stderr in the state's results.
435
436        .. note::
437            This is separate from ``output_loglevel``, which only handles how
438            Salt logs to the minion log.
439
440        .. versionadded:: 2018.3.0
441
442    use_vt
443        Use VT utils (saltstack) to stream the command output more
444        interactively to the console and the logs.
445        This is experimental.
446
447    success_retcodes: This parameter will allow a list of
448        non-zero return codes that should be considered a success.  If the
449        return code returned from the run matches any in the provided list,
450        the return code will be overridden with zero.
451
452      .. versionadded:: 2019.2.0
453
454    success_stdout: This parameter will allow a list of
455        strings that when found in standard out should be considered a success.
456        If stdout returned from the run matches any in the provided list,
457        the return code will be overridden with zero.
458
459      .. versionadded:: 3004
460
461    success_stderr: This parameter will allow a list of
462        strings that when found in standard error should be considered a success.
463        If stderr returned from the run matches any in the provided list,
464        the return code will be overridden with zero.
465
466      .. versionadded:: 3004
467    """
468    # Ignoring our arguments is intentional.
469    return {"name": name, "changes": {}, "result": True, "comment": ""}
470
471
472# Alias "cmd.watch" to "cmd.wait", as this is a common misconfiguration
473watch = salt.utils.functools.alias_function(wait, "watch")
474
475
476def wait_script(
477    name,
478    source=None,
479    template=None,
480    cwd=None,
481    runas=None,
482    shell=None,
483    env=None,
484    stateful=False,
485    umask=None,
486    use_vt=False,
487    output_loglevel="debug",
488    hide_output=False,
489    success_retcodes=None,
490    success_stdout=None,
491    success_stderr=None,
492    **kwargs
493):
494    """
495    Download a script from a remote source and execute it only if a watch
496    statement calls it.
497
498    source
499        The source script being downloaded to the minion, this source script is
500        hosted on the salt master server.  If the file is located on the master
501        in the directory named spam, and is called eggs, the source string is
502        salt://spam/eggs
503
504    template
505        If this setting is applied then the named templating engine will be
506        used to render the downloaded file, currently jinja, mako, and wempy
507        are supported
508
509    name
510        The command to execute, remember that the command will execute with the
511        path and permissions of the salt-minion.
512
513    cwd
514        The current working directory to execute the command in, defaults to
515        /root
516
517    runas
518        The user name to run the command as
519
520    shell
521        The shell to use for execution, defaults to the shell grain
522
523    env
524        A list of environment variables to be set prior to execution.
525        Example:
526
527        .. code-block:: yaml
528
529            salt://scripts/foo.sh:
530              cmd.wait_script:
531                - env:
532                  - BATCH: 'yes'
533
534        .. warning::
535
536            The above illustrates a common PyYAML pitfall, that **yes**,
537            **no**, **on**, **off**, **true**, and **false** are all loaded as
538            boolean ``True`` and ``False`` values, and must be enclosed in
539            quotes to be used as strings. More info on this (and other) PyYAML
540            idiosyncrasies can be found :ref:`here <yaml-idiosyncrasies>`.
541
542        Variables as values are not evaluated. So $PATH in the following
543        example is a literal '$PATH':
544
545        .. code-block:: yaml
546
547            salt://scripts/bar.sh:
548              cmd.wait_script:
549                - env: "PATH=/some/path:$PATH"
550
551        One can still use the existing $PATH by using a bit of Jinja:
552
553        .. code-block:: jinja
554
555            {% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}
556
557            mycommand:
558              cmd.run:
559                - name: ls -l /
560                - env:
561                  - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
562
563        .. note::
564            When using environment variables on Windows, case-sensitivity
565            matters, i.e. Windows uses `Path` as opposed to `PATH` for other
566            systems.
567
568    umask
569         The umask (in octal) to use when running the command.
570
571    stateful
572        The command being executed is expected to return data about executing
573        a state. For more information, see the :ref:`stateful-argument` section.
574
575    use_vt
576        Use VT utils (saltstack) to stream the command output more
577        interactively to the console and the logs.
578        This is experimental.
579
580    output_loglevel : debug
581        Control the loglevel at which the output from the command is logged to
582        the minion log.
583
584        .. note::
585            The command being run will still be logged at the ``debug``
586            loglevel regardless, unless ``quiet`` is used for this value.
587
588    hide_output : False
589        Suppress stdout and stderr in the state's results.
590
591        .. note::
592            This is separate from ``output_loglevel``, which only handles how
593            Salt logs to the minion log.
594
595        .. versionadded:: 2018.3.0
596
597    success_retcodes: This parameter will allow a list of
598        non-zero return codes that should be considered a success.  If the
599        return code returned from the run matches any in the provided list,
600        the return code will be overridden with zero.
601
602      .. versionadded:: 2019.2.0
603
604    success_stdout: This parameter will allow a list of
605        strings that when found in standard out should be considered a success.
606        If stdout returned from the run matches any in the provided list,
607        the return code will be overridden with zero.
608
609      .. versionadded:: 3004
610
611    success_stderr: This parameter will allow a list of
612        strings that when found in standard error should be considered a success.
613        If stderr returned from the run matches any in the provided list,
614        the return code will be overridden with zero.
615
616      .. versionadded:: 3004
617    """
618    # Ignoring our arguments is intentional.
619    return {"name": name, "changes": {}, "result": True, "comment": ""}
620
621
622def run(
623    name,
624    cwd=None,
625    root=None,
626    runas=None,
627    shell=None,
628    env=None,
629    prepend_path=None,
630    stateful=False,
631    umask=None,
632    output_loglevel="debug",
633    hide_output=False,
634    timeout=None,
635    ignore_timeout=False,
636    use_vt=False,
637    success_retcodes=None,
638    success_stdout=None,
639    success_stderr=None,
640    **kwargs
641):
642    """
643    Run a command if certain circumstances are met.  Use ``cmd.wait`` if you
644    want to use the ``watch`` requisite.
645
646    .. note::
647
648       The ``**kwargs`` of ``cmd.run`` are passed down to one of the following
649       exec modules:
650
651       * ``cmdmod.run_all``: If used with default ``runas``
652       * ``cmdmod.run_chroot``: If used with non-``root`` value for ``runas``
653
654       For more information on what args are available for either of these,
655       refer to the :ref:`cmdmod documentation <cmdmod-module>`.
656
657    name
658        The command to execute, remember that the command will execute with the
659        path and permissions of the salt-minion.
660
661    cwd
662        The current working directory to execute the command in, defaults to
663        /root
664
665    root
666        Path to the root of the jail to use. If this parameter is set, the command
667        will run inside a chroot
668
669    runas
670        The user name (or uid) to run the command as
671
672    shell
673        The shell to use for execution, defaults to the shell grain
674
675    env
676        A list of environment variables to be set prior to execution.
677        Example:
678
679        .. code-block:: yaml
680
681            script-foo:
682              cmd.run:
683                - env:
684                  - BATCH: 'yes'
685
686        .. warning::
687
688            The above illustrates a common PyYAML pitfall, that **yes**,
689            **no**, **on**, **off**, **true**, and **false** are all loaded as
690            boolean ``True`` and ``False`` values, and must be enclosed in
691            quotes to be used as strings. More info on this (and other) PyYAML
692            idiosyncrasies can be found :ref:`here <yaml-idiosyncrasies>`.
693
694        Variables as values are not evaluated. So $PATH in the following
695        example is a literal '$PATH':
696
697        .. code-block:: yaml
698
699            script-bar:
700              cmd.run:
701                - env: "PATH=/some/path:$PATH"
702
703        One can still use the existing $PATH by using a bit of Jinja:
704
705        .. code-block:: jinja
706
707            {% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}
708
709            mycommand:
710              cmd.run:
711                - name: ls -l /
712                - env:
713                  - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
714
715        .. note::
716            When using environment variables on Windows, case-sensitivity
717            matters, i.e. Windows uses `Path` as opposed to `PATH` for other
718            systems.
719
720    prepend_path
721        $PATH segment to prepend (trailing ':' not necessary) to $PATH. This is
722        an easier alternative to the Jinja workaround.
723
724        .. versionadded:: 2018.3.0
725
726    stateful
727        The command being executed is expected to return data about executing
728        a state. For more information, see the :ref:`stateful-argument` section.
729
730    umask
731        The umask (in octal) to use when running the command.
732
733    output_loglevel : debug
734        Control the loglevel at which the output from the command is logged to
735        the minion log.
736
737        .. note::
738            The command being run will still be logged at the ``debug``
739            loglevel regardless, unless ``quiet`` is used for this value.
740
741    hide_output : False
742        Suppress stdout and stderr in the state's results.
743
744        .. note::
745            This is separate from ``output_loglevel``, which only handles how
746            Salt logs to the minion log.
747
748        .. versionadded:: 2018.3.0
749
750    timeout
751        If the command has not terminated after timeout seconds, send the
752        subprocess sigterm, and if sigterm is ignored, follow up with sigkill
753
754    ignore_timeout
755        Ignore the timeout of commands, which is useful for running nohup
756        processes.
757
758        .. versionadded:: 2015.8.0
759
760    creates
761        Only run if the file specified by ``creates`` do not exist. If you
762        specify a list of files then this state will only run if **any** of
763        the files do not exist.
764
765        .. versionadded:: 2014.7.0
766
767    use_vt : False
768        Use VT utils (saltstack) to stream the command output more
769        interactively to the console and the logs.
770        This is experimental.
771
772    bg : False
773        If ``True``, run command in background and do not await or deliver its
774        results.
775
776        .. versionadded:: 2016.3.6
777
778    success_retcodes: This parameter will allow a list of
779        non-zero return codes that should be considered a success.  If the
780        return code returned from the run matches any in the provided list,
781        the return code will be overridden with zero.
782
783      .. versionadded:: 2019.2.0
784
785    success_stdout: This parameter will allow a list of
786        strings that when found in standard out should be considered a success.
787        If stdout returned from the run matches any in the provided list,
788        the return code will be overridden with zero.
789
790      .. versionadded:: 3004
791
792    success_stderr: This parameter will allow a list of
793        strings that when found in standard error should be considered a success.
794        If stderr returned from the run matches any in the provided list,
795        the return code will be overridden with zero.
796
797      .. versionadded:: 3004
798
799    .. note::
800
801        cmd.run supports the usage of ``reload_modules``. This functionality
802        allows you to force Salt to reload all modules. You should only use
803        ``reload_modules`` if your cmd.run does some sort of installation
804        (such as ``pip``), if you do not reload the modules future items in
805        your state which rely on the software being installed will fail.
806
807        .. code-block:: yaml
808
809            getpip:
810              cmd.run:
811                - name: /usr/bin/python /usr/local/sbin/get-pip.py
812                - unless: which pip
813                - require:
814                  - pkg: python
815                  - file: /usr/local/sbin/get-pip.py
816                - reload_modules: True
817
818    """
819    ### NOTE: The keyword arguments in **kwargs are passed directly to the
820    ###       ``cmd.run_all`` function and cannot be removed from the function
821    ###       definition, otherwise the use of unsupported arguments in a
822    ###       ``cmd.run`` state will result in a traceback.
823
824    ret = {"name": name, "changes": {}, "result": False, "comment": ""}
825
826    test_name = None
827    if not isinstance(stateful, list):
828        stateful = stateful is True
829    elif isinstance(stateful, list) and "test_name" in stateful[0]:
830        test_name = stateful[0]["test_name"]
831    if __opts__["test"] and test_name:
832        name = test_name
833
834    # Need the check for None here, if env is not provided then it falls back
835    # to None and it is assumed that the environment is not being overridden.
836    if env is not None and not isinstance(env, (list, dict)):
837        ret["comment"] = "Invalidly-formatted 'env' parameter. See documentation."
838        return ret
839
840    cmd_kwargs = copy.deepcopy(kwargs)
841    cmd_kwargs.update(
842        {
843            "cwd": cwd,
844            "root": root,
845            "runas": runas,
846            "use_vt": use_vt,
847            "shell": shell or __grains__["shell"],
848            "env": env,
849            "prepend_path": prepend_path,
850            "umask": umask,
851            "output_loglevel": output_loglevel,
852            "hide_output": hide_output,
853            "success_retcodes": success_retcodes,
854            "success_stdout": success_stdout,
855            "success_stderr": success_stderr,
856        }
857    )
858
859    if __opts__["test"] and not test_name:
860        ret["result"] = None
861        ret["comment"] = 'Command "{}" would have been executed'.format(name)
862        return _reinterpreted_state(ret) if stateful else ret
863
864    if cwd and not os.path.isdir(cwd):
865        ret["comment"] = 'Desired working directory "{}" is not available'.format(cwd)
866        return ret
867
868    # Wow, we passed the test, run this sucker!
869    try:
870        run_cmd = "cmd.run_all" if not root else "cmd.run_chroot"
871        cmd_all = __salt__[run_cmd](
872            cmd=name, timeout=timeout, python_shell=True, **cmd_kwargs
873        )
874    except Exception as err:  # pylint: disable=broad-except
875        ret["comment"] = str(err)
876        return ret
877
878    ret["changes"] = cmd_all
879    ret["result"] = not bool(cmd_all["retcode"])
880    ret["comment"] = 'Command "{}" run'.format(name)
881
882    # Ignore timeout errors if asked (for nohups) and treat cmd as a success
883    if ignore_timeout:
884        trigger = "Timed out after"
885        if ret["changes"].get("retcode") == 1 and trigger in ret["changes"].get(
886            "stdout"
887        ):
888            ret["changes"]["retcode"] = 0
889            ret["result"] = True
890
891    if stateful:
892        ret = _reinterpreted_state(ret)
893    if __opts__["test"] and cmd_all["retcode"] == 0 and ret["changes"]:
894        ret["result"] = None
895    return ret
896
897
898def script(
899    name,
900    source=None,
901    template=None,
902    cwd=None,
903    runas=None,
904    password=None,
905    shell=None,
906    env=None,
907    stateful=False,
908    umask=None,
909    timeout=None,
910    use_vt=False,
911    output_loglevel="debug",
912    hide_output=False,
913    defaults=None,
914    context=None,
915    success_retcodes=None,
916    success_stdout=None,
917    success_stderr=None,
918    **kwargs
919):
920    """
921    Download a script and execute it with specified arguments.
922
923    source
924        The location of the script to download. If the file is located on the
925        master in the directory named spam, and is called eggs, the source
926        string is salt://spam/eggs
927
928    template
929        If this setting is applied then the named templating engine will be
930        used to render the downloaded file. Currently jinja, mako, and wempy
931        are supported
932
933    name
934        Either "cmd arg1 arg2 arg3..." (cmd is not used) or a source
935        "salt://...".
936
937    cwd
938        The current working directory to execute the command in, defaults to
939        /root
940
941    runas
942        Specify an alternate user to run the command. The default
943        behavior is to run as the user under which Salt is running. If running
944        on a Windows minion you must also use the ``password`` argument, and
945        the target user account must be in the Administrators group.
946
947        .. note::
948
949            For Windows users, specifically Server users, it may be necessary
950            to specify your runas user using the User Logon Name instead of the
951            legacy logon name. Traditionally, logons would be in the following
952            format.
953
954                ``Domain/user``
955
956            In the event this causes issues when executing scripts, use the UPN
957            format which looks like the following.
958
959                ``user@domain.local``
960
961            More information <https://github.com/saltstack/salt/issues/55080>
962
963    password
964
965    .. versionadded:: 3000
966
967        Windows only. Required when specifying ``runas``. This
968        parameter will be ignored on non-Windows platforms.
969
970    shell
971        The shell to use for execution. The default is set in grains['shell']
972
973    env
974        A list of environment variables to be set prior to execution.
975        Example:
976
977        .. code-block:: yaml
978
979            salt://scripts/foo.sh:
980              cmd.script:
981                - env:
982                  - BATCH: 'yes'
983
984        .. warning::
985
986            The above illustrates a common PyYAML pitfall, that **yes**,
987            **no**, **on**, **off**, **true**, and **false** are all loaded as
988            boolean ``True`` and ``False`` values, and must be enclosed in
989            quotes to be used as strings. More info on this (and other) PyYAML
990            idiosyncrasies can be found :ref:`here <yaml-idiosyncrasies>`.
991
992        Variables as values are not evaluated. So $PATH in the following
993        example is a literal '$PATH':
994
995        .. code-block:: yaml
996
997            salt://scripts/bar.sh:
998              cmd.script:
999                - env: "PATH=/some/path:$PATH"
1000
1001        One can still use the existing $PATH by using a bit of Jinja:
1002
1003        .. code-block:: jinja
1004
1005            {% set current_path = salt['environ.get']('PATH', '/bin:/usr/bin') %}
1006
1007            mycommand:
1008              cmd.run:
1009                - name: ls -l /
1010                - env:
1011                  - PATH: {{ [current_path, '/my/special/bin']|join(':') }}
1012
1013        .. note::
1014            When using environment variables on Windows, case-sensitivity
1015            matters, i.e. Windows uses `Path` as opposed to `PATH` for other
1016            systems.
1017
1018    saltenv : ``base``
1019        The Salt environment to use
1020
1021    umask
1022         The umask (in octal) to use when running the command.
1023
1024    stateful
1025        The command being executed is expected to return data about executing
1026        a state. For more information, see the :ref:`stateful-argument` section.
1027
1028    timeout
1029        If the command has not terminated after timeout seconds, send the
1030        subprocess sigterm, and if sigterm is ignored, follow up with sigkill
1031
1032    args
1033        String of command line args to pass to the script.  Only used if no
1034        args are specified as part of the `name` argument. To pass a string
1035        containing spaces in YAML, you will need to doubly-quote it:  "arg1
1036        'arg two' arg3"
1037
1038    creates
1039        Only run if the file specified by ``creates`` do not exist. If you
1040        specify a list of files then this state will only run if **any** of
1041        the files do not exist.
1042
1043        .. versionadded:: 2014.7.0
1044
1045    use_vt
1046        Use VT utils (saltstack) to stream the command output more
1047        interactively to the console and the logs.
1048        This is experimental.
1049
1050    context
1051        .. versionadded:: 2016.3.0
1052
1053        Overrides default context variables passed to the template.
1054
1055    defaults
1056        .. versionadded:: 2016.3.0
1057
1058        Default context passed to the template.
1059
1060    output_loglevel : debug
1061        Control the loglevel at which the output from the command is logged to
1062        the minion log.
1063
1064        .. note::
1065            The command being run will still be logged at the ``debug``
1066            loglevel regardless, unless ``quiet`` is used for this value.
1067
1068    hide_output : False
1069        Suppress stdout and stderr in the state's results.
1070
1071        .. note::
1072            This is separate from ``output_loglevel``, which only handles how
1073            Salt logs to the minion log.
1074
1075        .. versionadded:: 2018.3.0
1076
1077    success_retcodes: This parameter will allow a list of
1078        non-zero return codes that should be considered a success.  If the
1079        return code returned from the run matches any in the provided list,
1080        the return code will be overridden with zero.
1081
1082      .. versionadded:: 2019.2.0
1083
1084    success_stdout: This parameter will allow a list of
1085        strings that when found in standard out should be considered a success.
1086        If stdout returned from the run matches any in the provided list,
1087        the return code will be overridden with zero.
1088
1089      .. versionadded:: 3004
1090
1091    success_stderr: This parameter will allow a list of
1092        strings that when found in standard error should be considered a success.
1093        If stderr returned from the run matches any in the provided list,
1094        the return code will be overridden with zero.
1095
1096      .. versionadded:: 3004
1097    """
1098    test_name = None
1099    if not isinstance(stateful, list):
1100        stateful = stateful is True
1101    elif isinstance(stateful, list) and "test_name" in stateful[0]:
1102        test_name = stateful[0]["test_name"]
1103    if __opts__["test"] and test_name:
1104        name = test_name
1105
1106    ret = {"name": name, "changes": {}, "result": False, "comment": ""}
1107
1108    # Need the check for None here, if env is not provided then it falls back
1109    # to None and it is assumed that the environment is not being overridden.
1110    if env is not None and not isinstance(env, (list, dict)):
1111        ret["comment"] = "Invalidly-formatted 'env' parameter. See documentation."
1112        return ret
1113
1114    if context and not isinstance(context, dict):
1115        ret[
1116            "comment"
1117        ] = "Invalidly-formatted 'context' parameter. Must be formed as a dict."
1118        return ret
1119    if defaults and not isinstance(defaults, dict):
1120        ret[
1121            "comment"
1122        ] = "Invalidly-formatted 'defaults' parameter. Must be formed as a dict."
1123        return ret
1124
1125    if runas and salt.utils.platform.is_windows() and not password:
1126        ret["comment"] = "Must supply a password if runas argument is used on Windows."
1127        return ret
1128
1129    tmpctx = defaults if defaults else {}
1130    if context:
1131        tmpctx.update(context)
1132
1133    cmd_kwargs = copy.deepcopy(kwargs)
1134    cmd_kwargs.update(
1135        {
1136            "runas": runas,
1137            "password": password,
1138            "shell": shell or __grains__["shell"],
1139            "env": env,
1140            "cwd": cwd,
1141            "template": template,
1142            "umask": umask,
1143            "timeout": timeout,
1144            "output_loglevel": output_loglevel,
1145            "hide_output": hide_output,
1146            "use_vt": use_vt,
1147            "context": tmpctx,
1148            "saltenv": __env__,
1149            "success_retcodes": success_retcodes,
1150            "success_stdout": success_stdout,
1151            "success_stderr": success_stderr,
1152        }
1153    )
1154
1155    run_check_cmd_kwargs = {
1156        "cwd": cwd,
1157        "runas": runas,
1158        "shell": shell or __grains__["shell"],
1159    }
1160
1161    # Change the source to be the name arg if it is not specified
1162    if source is None:
1163        source = name
1164
1165    # If script args present split from name and define args
1166    if not cmd_kwargs.get("args", None) and len(name.split()) > 1:
1167        cmd_kwargs.update({"args": name.split(" ", 1)[1]})
1168
1169    if __opts__["test"] and not test_name:
1170        ret["result"] = None
1171        ret["comment"] = "Command '{}' would have been executed".format(name)
1172        return _reinterpreted_state(ret) if stateful else ret
1173
1174    if cwd and not os.path.isdir(cwd):
1175        ret["comment"] = 'Desired working directory "{}" is not available'.format(cwd)
1176        return ret
1177
1178    # Wow, we passed the test, run this sucker!
1179    try:
1180        cmd_all = __salt__["cmd.script"](source, python_shell=True, **cmd_kwargs)
1181    except (CommandExecutionError, SaltRenderError, OSError) as err:
1182        ret["comment"] = str(err)
1183        return ret
1184
1185    ret["changes"] = cmd_all
1186    if kwargs.get("retcode", False):
1187        ret["result"] = not bool(cmd_all)
1188    else:
1189        ret["result"] = not bool(cmd_all["retcode"])
1190    if ret.get("changes", {}).get("cache_error"):
1191        ret["comment"] = "Unable to cache script {} from saltenv '{}'".format(
1192            source, __env__
1193        )
1194    else:
1195        ret["comment"] = "Command '{}' run".format(name)
1196    if stateful:
1197        ret = _reinterpreted_state(ret)
1198    if __opts__["test"] and cmd_all["retcode"] == 0 and ret["changes"]:
1199        ret["result"] = None
1200    return ret
1201
1202
1203def call(
1204    name,
1205    func,
1206    args=(),
1207    kws=None,
1208    output_loglevel="debug",
1209    hide_output=False,
1210    use_vt=False,
1211    **kwargs
1212):
1213    """
1214    Invoke a pre-defined Python function with arguments specified in the state
1215    declaration. This function is mainly used by the
1216    :mod:`salt.renderers.pydsl` renderer.
1217
1218    In addition, the ``stateful`` argument has no effects here.
1219
1220    The return value of the invoked function will be interpreted as follows.
1221
1222    If it's a dictionary then it will be passed through to the state system,
1223    which expects it to have the usual structure returned by any salt state
1224    function.
1225
1226    Otherwise, the return value (denoted as ``result`` in the code below) is
1227    expected to be a JSON serializable object, and this dictionary is returned:
1228
1229    .. code-block:: python
1230
1231        {
1232            'name': name
1233            'changes': {'retval': result},
1234            'result': True if result is None else bool(result),
1235            'comment': result if isinstance(result, str) else ''
1236        }
1237    """
1238    ret = {"name": name, "changes": {}, "result": False, "comment": ""}
1239
1240    cmd_kwargs = {
1241        "cwd": kwargs.get("cwd"),
1242        "runas": kwargs.get("user"),
1243        "shell": kwargs.get("shell") or __grains__["shell"],
1244        "env": kwargs.get("env"),
1245        "use_vt": use_vt,
1246        "output_loglevel": output_loglevel,
1247        "hide_output": hide_output,
1248        "umask": kwargs.get("umask"),
1249    }
1250
1251    if not kws:
1252        kws = {}
1253    result = func(*args, **kws)
1254    if isinstance(result, dict):
1255        ret.update(result)
1256        return ret
1257    else:
1258        # result must be JSON serializable else we get an error
1259        ret["changes"] = {"retval": result}
1260        ret["result"] = True if result is None else bool(result)
1261        if isinstance(result, str):
1262            ret["comment"] = result
1263        return ret
1264
1265
1266def wait_call(
1267    name,
1268    func,
1269    args=(),
1270    kws=None,
1271    stateful=False,
1272    use_vt=False,
1273    output_loglevel="debug",
1274    hide_output=False,
1275    **kwargs
1276):
1277    # Ignoring our arguments is intentional.
1278    return {"name": name, "changes": {}, "result": True, "comment": ""}
1279
1280
1281def mod_watch(name, **kwargs):
1282    """
1283    Execute a cmd function based on a watch call
1284
1285    .. note::
1286        This state exists to support special handling of the ``watch``
1287        :ref:`requisite <requisites>`. It should not be called directly.
1288
1289        Parameters for this function should be set by the state being triggered.
1290    """
1291    if kwargs["sfun"] in ("wait", "run", "watch"):
1292        if kwargs.get("stateful"):
1293            kwargs.pop("stateful")
1294            return _reinterpreted_state(run(name, **kwargs))
1295        return run(name, **kwargs)
1296
1297    elif kwargs["sfun"] == "wait_script" or kwargs["sfun"] == "script":
1298        if kwargs.get("stateful"):
1299            kwargs.pop("stateful")
1300            return _reinterpreted_state(script(name, **kwargs))
1301        return script(name, **kwargs)
1302
1303    elif kwargs["sfun"] == "wait_call" or kwargs["sfun"] == "call":
1304        if kwargs.get("func"):
1305            func = kwargs.pop("func")
1306            return call(name, func, **kwargs)
1307        else:
1308            return {
1309                "name": name,
1310                "changes": {},
1311                "comment": "cmd.{0[sfun]} needs a named parameter func".format(kwargs),
1312                "result": False,
1313            }
1314
1315    return {
1316        "name": name,
1317        "changes": {},
1318        "comment": (
1319            "cmd.{0[sfun]} does not work with the watch requisite, "
1320            "please use cmd.wait or cmd.wait_script".format(kwargs)
1321        ),
1322        "result": False,
1323    }
1324