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