1"""
2Control the state system on the minion.
3
4State Caching
5-------------
6
7When a highstate is called, the minion automatically caches a copy of the last
8high data. If you then run a highstate with cache=True it will use that cached
9highdata and won't hit the fileserver except for ``salt://`` links in the
10states themselves.
11"""
12
13import logging
14import os
15import shutil
16import sys
17import tarfile
18import tempfile
19import time
20
21import salt.config
22import salt.defaults.exitcodes
23import salt.payload
24import salt.state
25import salt.utils.args
26import salt.utils.data
27import salt.utils.event
28import salt.utils.files
29import salt.utils.functools
30import salt.utils.hashutils
31import salt.utils.jid
32import salt.utils.json
33import salt.utils.msgpack
34import salt.utils.platform
35import salt.utils.state
36import salt.utils.stringutils
37import salt.utils.url
38import salt.utils.versions
39from salt.exceptions import CommandExecutionError, SaltInvocationError
40from salt.loader import _format_cached_grains
41from salt.runners.state import orchestrate as _orchestrate
42from salt.utils.odict import OrderedDict
43
44__proxyenabled__ = ["*"]
45
46__outputter__ = {
47    "sls": "highstate",
48    "sls_id": "highstate",
49    "pkg": "highstate",
50    "top": "highstate",
51    "single": "highstate",
52    "highstate": "highstate",
53    "template": "highstate",
54    "template_str": "highstate",
55    "apply_": "highstate",
56    "test": "highstate",
57    "request": "highstate",
58    "check_request": "highstate",
59    "run_request": "highstate",
60}
61
62__func_alias__ = {"apply_": "apply"}
63log = logging.getLogger(__name__)
64
65# Define the module's virtual name
66__virtualname__ = "state"
67
68
69def __virtual__():
70    """
71    Set the virtualname
72    """
73    # Update global namespace with functions that are cloned in this module
74    global _orchestrate
75    _orchestrate = salt.utils.functools.namespaced_function(_orchestrate, globals())
76
77    return __virtualname__
78
79
80def _filter_running(runnings):
81    """
82    Filter out the result: True + no changes data
83    """
84    ret = {
85        tag: value
86        for tag, value in runnings.items()
87        if not value["result"] or value["changes"]
88    }
89    return ret
90
91
92def _set_retcode(ret, highstate=None):
93    """
94    Set the return code based on the data back from the state system
95    """
96
97    # Set default retcode to 0
98    __context__["retcode"] = salt.defaults.exitcodes.EX_OK
99
100    if isinstance(ret, list):
101        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
102        return
103    if not __utils__["state.check_result"](ret, highstate=highstate):
104        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_FAILURE
105
106
107def _get_pillar_errors(kwargs, pillar=None):
108    """
109    Checks all pillars (external and internal) for errors.
110    Return an error message, if anywhere or None.
111
112    :param kwargs: dictionary of options
113    :param pillar: external pillar
114    :return: None or an error message
115    """
116    return (
117        None
118        if kwargs.get("force")
119        else (pillar or {}).get("_errors", __pillar__.get("_errors")) or None
120    )
121
122
123def _wait(jid):
124    """
125    Wait for all previously started state jobs to finish running
126    """
127    if jid is None:
128        jid = salt.utils.jid.gen_jid(__opts__)
129    states = _prior_running_states(jid)
130    while states:
131        time.sleep(1)
132        states = _prior_running_states(jid)
133
134
135def _snapper_pre(opts, jid):
136    """
137    Create a snapper pre snapshot
138    """
139    snapper_pre = None
140    try:
141        if not opts["test"] and __opts__.get("snapper_states"):
142            # Run the snapper pre snapshot
143            snapper_pre = __salt__["snapper.create_snapshot"](
144                config=__opts__.get("snapper_states_config", "root"),
145                snapshot_type="pre",
146                description="Salt State run for jid {}".format(jid),
147                __pub_jid=jid,
148            )
149    except Exception:  # pylint: disable=broad-except
150        log.error("Failed to create snapper pre snapshot for jid: %s", jid)
151    return snapper_pre
152
153
154def _snapper_post(opts, jid, pre_num):
155    """
156    Create the post states snapshot
157    """
158    try:
159        if not opts["test"] and __opts__.get("snapper_states") and pre_num:
160            # Run the snapper pre snapshot
161            __salt__["snapper.create_snapshot"](
162                config=__opts__.get("snapper_states_config", "root"),
163                snapshot_type="post",
164                pre_number=pre_num,
165                description="Salt State run for jid {}".format(jid),
166                __pub_jid=jid,
167            )
168    except Exception:  # pylint: disable=broad-except
169        log.error("Failed to create snapper pre snapshot for jid: %s", jid)
170
171
172def _get_pause(jid, state_id=None):
173    """
174    Return the pause information for a given jid
175    """
176    pause_dir = os.path.join(__opts__["cachedir"], "state_pause")
177    pause_path = os.path.join(pause_dir, jid)
178    if not os.path.exists(pause_dir):
179        try:
180            os.makedirs(pause_dir)
181        except OSError:
182            # File created in the gap
183            pass
184    data = {}
185    if state_id is not None:
186        if state_id not in data:
187            data[state_id] = {}
188    if os.path.exists(pause_path):
189        with salt.utils.files.fopen(pause_path, "rb") as fp_:
190            data = salt.utils.msgpack.loads(fp_.read())
191    return data, pause_path
192
193
194def get_pauses(jid=None):
195    """
196    Get a report on all of the currently paused state runs and pause
197    run settings.
198    Optionally send in a jid if you only desire to see a single pause
199    data set.
200    """
201    ret = {}
202    active = __salt__["saltutil.is_running"]("state.*")
203    pause_dir = os.path.join(__opts__["cachedir"], "state_pause")
204    if not os.path.exists(pause_dir):
205        return ret
206    if jid is None:
207        jids = os.listdir(pause_dir)
208    elif isinstance(jid, list):
209        jids = salt.utils.data.stringify(jid)
210    else:
211        jids = [str(jid)]
212    for scan_jid in jids:
213        is_active = False
214        for active_data in active:
215            if active_data["jid"] == scan_jid:
216                is_active = True
217        if not is_active:
218            try:
219                pause_path = os.path.join(pause_dir, scan_jid)
220                os.remove(pause_path)
221            except OSError:
222                # Already gone
223                pass
224            continue
225        data, pause_path = _get_pause(scan_jid)
226        ret[scan_jid] = data
227    return ret
228
229
230def soft_kill(jid, state_id=None):
231    """
232    Set up a state run to die before executing the given state id,
233    this instructs a running state to safely exit at a given
234    state id. This needs to pass in the jid of the running state.
235    If a state_id is not passed then the jid referenced will be safely exited
236    at the beginning of the next state run.
237
238    The given state id is the id got a given state execution, so given a state
239    that looks like this:
240
241    .. code-block:: yaml
242
243        vim:
244          pkg.installed: []
245
246    The state_id to pass to `soft_kill` is `vim`
247
248    CLI Examples:
249
250    .. code-block:: bash
251
252        salt '*' state.soft_kill 20171130110407769519
253        salt '*' state.soft_kill 20171130110407769519 vim
254    """
255    jid = str(jid)
256    if state_id is None:
257        state_id = "__all__"
258    data, pause_path = _get_pause(jid, state_id)
259    data[state_id]["kill"] = True
260    with salt.utils.files.fopen(pause_path, "wb") as fp_:
261        fp_.write(salt.utils.msgpack.dumps(data))
262
263
264def pause(jid, state_id=None, duration=None):
265    """
266    Set up a state id pause, this instructs a running state to pause at a given
267    state id. This needs to pass in the jid of the running state and can
268    optionally pass in a duration in seconds. If a state_id is not passed then
269    the jid referenced will be paused at the beginning of the next state run.
270
271    The given state id is the id got a given state execution, so given a state
272    that looks like this:
273
274    .. code-block:: yaml
275
276        vim:
277          pkg.installed: []
278
279    The state_id to pass to `pause` is `vim`
280
281    CLI Examples:
282
283    .. code-block:: bash
284
285        salt '*' state.pause 20171130110407769519
286        salt '*' state.pause 20171130110407769519 vim
287        salt '*' state.pause 20171130110407769519 vim 20
288    """
289    jid = str(jid)
290    if state_id is None:
291        state_id = "__all__"
292    data, pause_path = _get_pause(jid, state_id)
293    if duration:
294        data[state_id]["duration"] = int(duration)
295    with salt.utils.files.fopen(pause_path, "wb") as fp_:
296        fp_.write(salt.utils.msgpack.dumps(data))
297
298
299def resume(jid, state_id=None):
300    """
301    Remove a pause from a jid, allowing it to continue. If the state_id is
302    not specified then the a general pause will be resumed.
303
304    The given state_id is the id got a given state execution, so given a state
305    that looks like this:
306
307    .. code-block:: yaml
308
309        vim:
310          pkg.installed: []
311
312    The state_id to pass to `rm_pause` is `vim`
313
314    CLI Examples:
315
316    .. code-block:: bash
317
318        salt '*' state.resume 20171130110407769519
319        salt '*' state.resume 20171130110407769519 vim
320    """
321    jid = str(jid)
322    if state_id is None:
323        state_id = "__all__"
324    data, pause_path = _get_pause(jid, state_id)
325    if state_id in data:
326        data.pop(state_id)
327    if state_id == "__all__":
328        data = {}
329    with salt.utils.files.fopen(pause_path, "wb") as fp_:
330        fp_.write(salt.utils.msgpack.dumps(data))
331
332
333def orchestrate(
334    mods, saltenv="base", test=None, exclude=None, pillar=None, pillarenv=None
335):
336    """
337    .. versionadded:: 2016.11.0
338
339    Execute the orchestrate runner from a masterless minion.
340
341    .. seealso:: More Orchestrate documentation
342
343        * :ref:`Full Orchestrate Tutorial <orchestrate-runner>`
344        * Docs for the salt state module :py:mod:`salt.states.saltmod`
345
346    CLI Examples:
347
348    .. code-block:: bash
349
350        salt-call --local state.orchestrate webserver
351        salt-call --local state.orchestrate webserver saltenv=dev test=True
352        salt-call --local state.orchestrate webserver saltenv=dev pillarenv=aws
353    """
354    return _orchestrate(
355        mods=mods,
356        saltenv=saltenv,
357        test=test,
358        exclude=exclude,
359        pillar=pillar,
360        pillarenv=pillarenv,
361    )
362
363
364def running(concurrent=False):
365    """
366    Return a list of strings that contain state return data if a state function
367    is already running. This function is used to prevent multiple state calls
368    from being run at the same time.
369
370    CLI Example:
371
372    .. code-block:: bash
373
374        salt '*' state.running
375    """
376    ret = []
377    if concurrent:
378        return ret
379    active = __salt__["saltutil.is_running"]("state.*")
380    for data in active:
381        err = (
382            'The function "{}" is running as PID {} and was started at {} '
383            "with jid {}".format(
384                data["fun"],
385                data["pid"],
386                salt.utils.jid.jid_to_time(data["jid"]),
387                data["jid"],
388            )
389        )
390        ret.append(err)
391    return ret
392
393
394def _prior_running_states(jid):
395    """
396    Return a list of dicts of prior calls to state functions.  This function is
397    used to queue state calls so only one is run at a time.
398    """
399
400    ret = []
401    active = __salt__["saltutil.is_running"]("state.*")
402    for data in active:
403        try:
404            data_jid = int(data["jid"])
405        except ValueError:
406            continue
407        if data_jid < int(jid):
408            ret.append(data)
409    return ret
410
411
412def _check_queue(queue, kwargs):
413    """
414    Utility function to queue the state run if requested
415    and to check for conflicts in currently running states
416    """
417    if queue:
418        _wait(kwargs.get("__pub_jid"))
419    else:
420        conflict = running(concurrent=kwargs.get("concurrent", False))
421        if conflict:
422            __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
423            return conflict
424
425
426def _get_initial_pillar(opts):
427    return (
428        __pillar__.value()
429        if __opts__.get("__cli", None) == "salt-call"
430        and opts["pillarenv"] == __opts__["pillarenv"]
431        else None
432    )
433
434
435def low(data, queue=False, **kwargs):
436    """
437    Execute a single low data call
438
439    This function is mostly intended for testing the state system and is not
440    likely to be needed in everyday usage.
441
442    CLI Example:
443
444    .. code-block:: bash
445
446        salt '*' state.low '{"state": "pkg", "fun": "installed", "name": "vi"}'
447    """
448    conflict = _check_queue(queue, kwargs)
449    if conflict is not None:
450        return conflict
451    try:
452        st_ = salt.state.State(__opts__, proxy=__proxy__)
453    except NameError:
454        st_ = salt.state.State(__opts__)
455    err = st_.verify_data(data)
456    if err:
457        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
458        return err
459    ret = st_.call(data)
460    if isinstance(ret, list):
461        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
462    if __utils__["state.check_result"](ret):
463        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_FAILURE
464    return ret
465
466
467def _get_test_value(test=None, **kwargs):
468    """
469    Determine the correct value for the test flag.
470    """
471    ret = True
472    if test is None:
473        if salt.utils.args.test_mode(test=test, **kwargs):
474            ret = True
475        elif __salt__["config.get"]("test", omit_opts=True) is True:
476            ret = True
477        else:
478            ret = __opts__.get("test", None)
479    else:
480        ret = test
481    return ret
482
483
484def high(data, test=None, queue=False, **kwargs):
485    """
486    Execute the compound calls stored in a single set of high data
487
488    This function is mostly intended for testing the state system and is not
489    likely to be needed in everyday usage.
490
491    CLI Example:
492
493    .. code-block:: bash
494
495        salt '*' state.high '{"vim": {"pkg": ["installed"]}}'
496    """
497    conflict = _check_queue(queue, kwargs)
498    if conflict is not None:
499        return conflict
500    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
501
502    opts["test"] = _get_test_value(test, **kwargs)
503
504    pillar_override = kwargs.get("pillar")
505    pillar_enc = kwargs.get("pillar_enc")
506    if (
507        pillar_enc is None
508        and pillar_override is not None
509        and not isinstance(pillar_override, dict)
510    ):
511        raise SaltInvocationError(
512            "Pillar data must be formatted as a dictionary, unless pillar_enc "
513            "is specified."
514        )
515    try:
516        st_ = salt.state.State(
517            opts,
518            pillar_override,
519            pillar_enc=pillar_enc,
520            proxy=dict(__proxy__),
521            context=dict(__context__),
522            initial_pillar=_get_initial_pillar(opts),
523        )
524    except NameError:
525        st_ = salt.state.State(
526            opts,
527            pillar_override,
528            pillar_enc=pillar_enc,
529            initial_pillar=_get_initial_pillar(opts),
530        )
531
532    ret = st_.call_high(data)
533    _set_retcode(ret, highstate=data)
534    return ret
535
536
537def template(tem, queue=False, **kwargs):
538    """
539    Execute the information stored in a template file on the minion.
540
541    This function does not ask a master for a SLS file to render but
542    instead directly processes the file at the provided path on the minion.
543
544    CLI Example:
545
546    .. code-block:: bash
547
548        salt '*' state.template '<Path to template on the minion>'
549    """
550    if "env" in kwargs:
551        # "env" is not supported; Use "saltenv".
552        kwargs.pop("env")
553
554    conflict = _check_queue(queue, kwargs)
555    if conflict is not None:
556        return conflict
557
558    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
559    try:
560        st_ = salt.state.HighState(
561            opts,
562            context=dict(__context__),
563            proxy=dict(__proxy__),
564            initial_pillar=_get_initial_pillar(opts),
565        )
566    except NameError:
567        st_ = salt.state.HighState(
568            opts, context=dict(__context__), initial_pillar=_get_initial_pillar(opts)
569        )
570
571    with st_:
572        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
573        if errors:
574            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
575            raise CommandExecutionError("Pillar failed to render", info=errors)
576
577        if not tem.endswith(".sls"):
578            tem = "{sls}.sls".format(sls=tem)
579        high_state, errors = st_.render_state(
580            tem, kwargs.get("saltenv", ""), "", None, local=True
581        )
582        if errors:
583            __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
584            return errors
585        ret = st_.state.call_high(high_state)
586        _set_retcode(ret, highstate=high_state)
587        return ret
588
589
590def template_str(tem, queue=False, **kwargs):
591    """
592    Execute the information stored in a string from an sls template
593
594    CLI Example:
595
596    .. code-block:: bash
597
598        salt '*' state.template_str '<Template String>'
599    """
600    conflict = _check_queue(queue, kwargs)
601    if conflict is not None:
602        return conflict
603
604    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
605
606    try:
607        st_ = salt.state.State(
608            opts, proxy=__proxy__, initial_pillar=_get_initial_pillar(opts)
609        )
610    except NameError:
611        st_ = salt.state.State(opts, initial_pillar=_get_initial_pillar(opts))
612    ret = st_.call_template_str(tem)
613    _set_retcode(ret)
614    return ret
615
616
617def apply_(mods=None, **kwargs):
618    """
619    .. versionadded:: 2015.5.0
620
621    This function will call :mod:`state.highstate
622    <salt.modules.state.highstate>` or :mod:`state.sls
623    <salt.modules.state.sls>` based on the arguments passed to this function.
624    It exists as a more intuitive way of applying states.
625
626    .. rubric:: APPLYING ALL STATES CONFIGURED IN TOP.SLS (A.K.A. :ref:`HIGHSTATE <running-highstate>`)
627
628    To apply all configured states, simply run ``state.apply``:
629
630    .. code-block:: bash
631
632        salt '*' state.apply
633
634    The following additional arguments are also accepted when applying all
635    states configured in top.sls:
636
637    test
638        Run states in test-only (dry-run) mode
639
640    mock
641        The mock option allows for the state run to execute without actually
642        calling any states. This then returns a mocked return which will show
643        the requisite ordering as well as fully validate the state run.
644
645        .. versionadded:: 2015.8.4
646
647    pillar
648        Custom Pillar values, passed as a dictionary of key-value pairs
649
650        .. code-block:: bash
651
652            salt '*' state.apply stuff pillar='{"foo": "bar"}'
653
654        .. note::
655            Values passed this way will override Pillar values set via
656            ``pillar_roots`` or an external Pillar source.
657
658    exclude
659        Exclude specific states from execution. Accepts a list of sls names, a
660        comma-separated string of sls names, or a list of dictionaries
661        containing ``sls`` or ``id`` keys. Glob-patterns may be used to match
662        multiple states.
663
664        .. code-block:: bash
665
666            salt '*' state.apply exclude=bar,baz
667            salt '*' state.apply exclude=foo*
668            salt '*' state.apply exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
669
670    queue : False
671        Instead of failing immediately when another state run is in progress,
672        queue the new state run to begin running once the other has finished.
673
674        This option starts a new thread for each queued state run, so use this
675        option sparingly.
676
677    localconfig
678        Optionally, instead of using the minion config, load minion opts from
679        the file specified by this argument, and then merge them with the
680        options from the minion config. This functionality allows for specific
681        states to be run with their own custom minion configuration, including
682        different pillars, file_roots, etc.
683
684        .. code-block:: bash
685
686            salt '*' state.apply localconfig=/path/to/minion.yml
687
688
689    .. rubric:: APPLYING INDIVIDUAL SLS FILES (A.K.A. :py:func:`STATE.SLS <salt.modules.state.sls>`)
690
691    To apply individual SLS files, pass them as a comma-separated list:
692
693    .. code-block:: bash
694
695        # Run the states configured in salt://stuff.sls (or salt://stuff/init.sls)
696        salt '*' state.apply stuff
697
698        # Run the states configured in salt://stuff.sls (or salt://stuff/init.sls)
699        # and salt://pkgs.sls (or salt://pkgs/init.sls).
700        salt '*' state.apply stuff,pkgs
701
702        # Run the states configured in a more deeply nested directory such as salt://my/organized/stuff.sls (or salt://my/organized/stuff/init.sls)
703        salt '*' state.apply my.organized.stuff
704
705    The following additional arguments are also accepted when applying
706    individual SLS files:
707
708    test
709        Run states in test-only (dry-run) mode
710
711    mock
712        The mock option allows for the state run to execute without actually
713        calling any states. This then returns a mocked return which will show
714        the requisite ordering as well as fully validate the state run.
715
716        .. versionadded:: 2015.8.4
717
718    pillar
719        Custom Pillar values, passed as a dictionary of key-value pairs
720
721        .. code-block:: bash
722
723            salt '*' state.apply stuff pillar='{"foo": "bar"}'
724
725        .. note::
726            Values passed this way will override Pillar values set via
727            ``pillar_roots`` or an external Pillar source.
728
729    queue : False
730        Instead of failing immediately when another state run is in progress,
731        queue the new state run to begin running once the other has finished.
732
733        This option starts a new thread for each queued state run, so use this
734        option sparingly.
735
736    concurrent : False
737        Execute state runs concurrently instead of serially
738
739        .. warning::
740
741            This flag is potentially dangerous. It is designed for use when
742            multiple state runs can safely be run at the same time. Do *not*
743            use this flag for performance optimization.
744
745    saltenv
746        Specify a salt fileserver environment to be used when applying states
747
748        .. versionchanged:: 0.17.0
749            Argument name changed from ``env`` to ``saltenv``
750
751        .. versionchanged:: 2014.7.0
752            If no saltenv is specified, the minion config will be checked for an
753            ``environment`` parameter and if found, it will be used. If none is
754            found, ``base`` will be used. In prior releases, the minion config
755            was not checked and ``base`` would always be assumed when the
756            saltenv was not explicitly set.
757
758    pillarenv
759        Specify a Pillar environment to be used when applying states. This
760        can also be set in the minion config file using the
761        :conf_minion:`pillarenv` option. When neither the
762        :conf_minion:`pillarenv` minion config option nor this CLI argument is
763        used, all Pillar environments will be merged together.
764
765    localconfig
766        Optionally, instead of using the minion config, load minion opts from
767        the file specified by this argument, and then merge them with the
768        options from the minion config. This functionality allows for specific
769        states to be run with their own custom minion configuration, including
770        different pillars, file_roots, etc.
771
772        .. code-block:: bash
773
774            salt '*' state.apply stuff localconfig=/path/to/minion.yml
775
776    sync_mods
777        If specified, the desired custom module types will be synced prior to
778        running the SLS files:
779
780        .. code-block:: bash
781
782            salt '*' state.apply stuff sync_mods=states,modules
783            salt '*' state.apply stuff sync_mods=all
784
785        .. note::
786            This option is ignored when no SLS files are specified, as a
787            :ref:`highstate <running-highstate>` automatically syncs all custom
788            module types.
789
790        .. versionadded:: 2017.7.8,2018.3.3,2019.2.0
791    """
792    if mods:
793        return sls(mods, **kwargs)
794    return highstate(**kwargs)
795
796
797def test(*args, **kwargs):
798    """
799    .. versionadded:: 3001
800
801    Alias for `state.apply` with the kwarg `test` forced to `True`.
802
803    This is a nicety to avoid the need to type out `test=True` and the possibility of
804    a typo causing changes you do not intend.
805    """
806    kwargs["test"] = True
807    ret = apply_(*args, **kwargs)
808
809    return ret
810
811
812def request(mods=None, **kwargs):
813    """
814    .. versionadded:: 2015.5.0
815
816    Request that the local admin execute a state run via
817    `salt-call state.run_request`.
818    All arguments match those of state.apply.
819
820    CLI Example:
821
822    .. code-block:: bash
823
824        salt '*' state.request
825        salt '*' state.request stuff
826        salt '*' state.request stuff,pkgs
827    """
828    kwargs["test"] = True
829    ret = apply_(mods, **kwargs)
830    notify_path = os.path.join(__opts__["cachedir"], "req_state.p")
831    req = check_request()
832    req.update(
833        {
834            kwargs.get("name", "default"): {
835                "test_run": ret,
836                "mods": mods,
837                "kwargs": kwargs,
838            }
839        }
840    )
841    with salt.utils.files.set_umask(0o077):
842        try:
843            if salt.utils.platform.is_windows():
844                # Make sure cache file isn't read-only
845                __salt__["cmd.run"]('attrib -R "{}"'.format(notify_path))
846            with salt.utils.files.fopen(notify_path, "w+b") as fp_:
847                salt.payload.dump(req, fp_)
848        except OSError:
849            log.error(
850                "Unable to write state request file %s. Check permission.", notify_path
851            )
852    return ret
853
854
855def check_request(name=None):
856    """
857    .. versionadded:: 2015.5.0
858
859    Return the state request information, if any
860
861    CLI Example:
862
863    .. code-block:: bash
864
865        salt '*' state.check_request
866    """
867    notify_path = os.path.join(__opts__["cachedir"], "req_state.p")
868    if os.path.isfile(notify_path):
869        with salt.utils.files.fopen(notify_path, "rb") as fp_:
870            req = salt.payload.load(fp_)
871        if name:
872            return req[name]
873        return req
874    return {}
875
876
877def clear_request(name=None):
878    """
879    .. versionadded:: 2015.5.0
880
881    Clear out the state execution request without executing it
882
883    CLI Example:
884
885    .. code-block:: bash
886
887        salt '*' state.clear_request
888    """
889    notify_path = os.path.join(__opts__["cachedir"], "req_state.p")
890    if not os.path.isfile(notify_path):
891        return True
892    if not name:
893        try:
894            os.remove(notify_path)
895        except OSError:
896            pass
897    else:
898        req = check_request()
899        if name in req:
900            req.pop(name)
901        else:
902            return False
903        with salt.utils.files.set_umask(0o077):
904            try:
905                if salt.utils.platform.is_windows():
906                    # Make sure cache file isn't read-only
907                    __salt__["cmd.run"]('attrib -R "{}"'.format(notify_path))
908                with salt.utils.files.fopen(notify_path, "w+b") as fp_:
909                    salt.payload.dump(req, fp_)
910            except OSError:
911                log.error(
912                    "Unable to write state request file %s. Check permission.",
913                    notify_path,
914                )
915    return True
916
917
918def run_request(name="default", **kwargs):
919    """
920    .. versionadded:: 2015.5.0
921
922    Execute the pending state request
923
924    CLI Example:
925
926    .. code-block:: bash
927
928        salt '*' state.run_request
929    """
930    req = check_request()
931    if name not in req:
932        return {}
933    n_req = req[name]
934    if "mods" not in n_req or "kwargs" not in n_req:
935        return {}
936    req[name]["kwargs"].update(kwargs)
937    if "test" in n_req["kwargs"]:
938        n_req["kwargs"].pop("test")
939    if req:
940        ret = apply_(n_req["mods"], **n_req["kwargs"])
941        try:
942            os.remove(os.path.join(__opts__["cachedir"], "req_state.p"))
943        except OSError:
944            pass
945        return ret
946    return {}
947
948
949def highstate(test=None, queue=False, **kwargs):
950    """
951    Retrieve the state data from the salt master for this minion and execute it
952
953    test
954        Run states in test-only (dry-run) mode
955
956    pillar
957        Custom Pillar values, passed as a dictionary of key-value pairs
958
959        .. code-block:: bash
960
961            salt '*' state.highstate stuff pillar='{"foo": "bar"}'
962
963        .. note::
964            Values passed this way will override Pillar values set via
965            ``pillar_roots`` or an external Pillar source.
966
967        .. versionchanged:: 2016.3.0
968            GPG-encrypted CLI Pillar data is now supported via the GPG
969            renderer. See :ref:`here <encrypted-cli-pillar-data>` for details.
970
971    pillar_enc
972        Specify which renderer to use to decrypt encrypted data located within
973        the ``pillar`` value. Currently, only ``gpg`` is supported.
974
975        .. versionadded:: 2016.3.0
976
977    exclude
978        Exclude specific states from execution. Accepts a list of sls names, a
979        comma-separated string of sls names, or a list of dictionaries
980        containing ``sls`` or ``id`` keys. Glob-patterns may be used to match
981        multiple states.
982
983        .. code-block:: bash
984
985            salt '*' state.highstate exclude=bar,baz
986            salt '*' state.highstate exclude=foo*
987            salt '*' state.highstate exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
988
989    saltenv
990        Specify a salt fileserver environment to be used when applying states
991
992        .. versionchanged:: 0.17.0
993            Argument name changed from ``env`` to ``saltenv``.
994
995        .. versionchanged:: 2014.7.0
996            If no saltenv is specified, the minion config will be checked for a
997            ``saltenv`` parameter and if found, it will be used. If none is
998            found, ``base`` will be used. In prior releases, the minion config
999            was not checked and ``base`` would always be assumed when the
1000            saltenv was not explicitly set.
1001
1002    pillarenv
1003        Specify a Pillar environment to be used when applying states. This
1004        can also be set in the minion config file using the
1005        :conf_minion:`pillarenv` option. When neither the
1006        :conf_minion:`pillarenv` minion config option nor this CLI argument is
1007        used, all Pillar environments will be merged together.
1008
1009    queue : False
1010        Instead of failing immediately when another state run is in progress,
1011        queue the new state run to begin running once the other has finished.
1012
1013        This option starts a new thread for each queued state run, so use this
1014        option sparingly.
1015
1016    localconfig
1017        Optionally, instead of using the minion config, load minion opts from
1018        the file specified by this argument, and then merge them with the
1019        options from the minion config. This functionality allows for specific
1020        states to be run with their own custom minion configuration, including
1021        different pillars, file_roots, etc.
1022
1023    mock
1024        The mock option allows for the state run to execute without actually
1025        calling any states. This then returns a mocked return which will show
1026        the requisite ordering as well as fully validate the state run.
1027
1028        .. versionadded:: 2015.8.4
1029
1030    CLI Examples:
1031
1032    .. code-block:: bash
1033
1034        salt '*' state.highstate
1035
1036        salt '*' state.highstate whitelist=sls1_to_run,sls2_to_run
1037        salt '*' state.highstate exclude=sls_to_exclude
1038        salt '*' state.highstate exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
1039
1040        salt '*' state.highstate pillar="{foo: 'Foo!', bar: 'Bar!'}"
1041    """
1042    if _disabled(["highstate"]):
1043        log.debug(
1044            "Salt highstate run is disabled. To re-enable, run state.enable highstate"
1045        )
1046        ret = {
1047            "name": (
1048                "Salt highstate run is disabled. To re-enable, run state.enable"
1049                " highstate"
1050            ),
1051            "result": "False",
1052            "comment": "Disabled",
1053        }
1054        return ret
1055
1056    conflict = _check_queue(queue, kwargs)
1057    if conflict is not None:
1058        return conflict
1059
1060    orig_test = __opts__.get("test", None)
1061    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1062    opts["test"] = _get_test_value(test, **kwargs)
1063
1064    if "env" in kwargs:
1065        # "env" is not supported; Use "saltenv".
1066        kwargs.pop("env")
1067
1068    if "saltenv" in kwargs:
1069        opts["saltenv"] = kwargs["saltenv"]
1070
1071    if "pillarenv" in kwargs:
1072        opts["pillarenv"] = kwargs["pillarenv"]
1073
1074    pillar_override = kwargs.get("pillar")
1075    pillar_enc = kwargs.get("pillar_enc")
1076    if (
1077        pillar_enc is None
1078        and pillar_override is not None
1079        and not isinstance(pillar_override, dict)
1080    ):
1081        raise SaltInvocationError(
1082            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1083            "is specified."
1084        )
1085
1086    try:
1087        st_ = salt.state.HighState(
1088            opts,
1089            pillar_override,
1090            kwargs.get("__pub_jid"),
1091            pillar_enc=pillar_enc,
1092            proxy=dict(__proxy__),
1093            context=dict(__context__),
1094            mocked=kwargs.get("mock", False),
1095            initial_pillar=_get_initial_pillar(opts),
1096        )
1097    except NameError:
1098        st_ = salt.state.HighState(
1099            opts,
1100            pillar_override,
1101            kwargs.get("__pub_jid"),
1102            pillar_enc=pillar_enc,
1103            mocked=kwargs.get("mock", False),
1104            initial_pillar=_get_initial_pillar(opts),
1105        )
1106
1107    with st_:
1108        errors = _get_pillar_errors(kwargs, st_.opts["pillar"])
1109        if errors:
1110            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1111            return ["Pillar failed to render with the following messages:"] + errors
1112
1113        st_.push_active()
1114        orchestration_jid = kwargs.get("orchestration_jid")
1115        snapper_pre = _snapper_pre(opts, kwargs.get("__pub_jid", "called localy"))
1116        try:
1117            ret = st_.call_highstate(
1118                exclude=kwargs.get("exclude", []),
1119                cache=kwargs.get("cache", None),
1120                cache_name=kwargs.get("cache_name", "highstate"),
1121                force=kwargs.get("force", False),
1122                whitelist=kwargs.get("whitelist"),
1123                orchestration_jid=orchestration_jid,
1124            )
1125        finally:
1126            st_.pop_active()
1127
1128        if isinstance(ret, dict) and (
1129            __salt__["config.option"]("state_data", "") == "terse"
1130            or kwargs.get("terse")
1131        ):
1132            ret = _filter_running(ret)
1133
1134        _set_retcode(ret, highstate=st_.building_highstate)
1135        _snapper_post(opts, kwargs.get("__pub_jid", "called localy"), snapper_pre)
1136
1137        # Work around Windows multiprocessing bug, set __opts__['test'] back to
1138        # value from before this function was run.
1139        __opts__["test"] = orig_test
1140
1141        return ret
1142
1143
1144def sls(mods, test=None, exclude=None, queue=False, sync_mods=None, **kwargs):
1145    """
1146    Execute the states in one or more SLS files
1147
1148    test
1149        Run states in test-only (dry-run) mode
1150
1151    pillar
1152        Custom Pillar values, passed as a dictionary of key-value pairs
1153
1154        .. code-block:: bash
1155
1156            salt '*' state.sls stuff pillar='{"foo": "bar"}'
1157
1158        .. note::
1159            Values passed this way will override existing Pillar values set via
1160            ``pillar_roots`` or an external Pillar source.  Pillar values that
1161            are not included in the kwarg will not be overwritten.
1162
1163        .. versionchanged:: 2016.3.0
1164            GPG-encrypted CLI Pillar data is now supported via the GPG
1165            renderer. See :ref:`here <encrypted-cli-pillar-data>` for details.
1166
1167    pillar_enc
1168        Specify which renderer to use to decrypt encrypted data located within
1169        the ``pillar`` value. Currently, only ``gpg`` is supported.
1170
1171        .. versionadded:: 2016.3.0
1172
1173    exclude
1174        Exclude specific states from execution. Accepts a list of sls names, a
1175        comma-separated string of sls names, or a list of dictionaries
1176        containing ``sls`` or ``id`` keys. Glob-patterns may be used to match
1177        multiple states.
1178
1179        .. code-block:: bash
1180
1181            salt '*' state.sls foo,bar,baz exclude=bar,baz
1182            salt '*' state.sls foo,bar,baz exclude=ba*
1183            salt '*' state.sls foo,bar,baz exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
1184
1185    queue : False
1186        Instead of failing immediately when another state run is in progress,
1187        queue the new state run to begin running once the other has finished.
1188
1189        This option starts a new thread for each queued state run, so use this
1190        option sparingly.
1191
1192    concurrent : False
1193        Execute state runs concurrently instead of serially
1194
1195        .. warning::
1196
1197            This flag is potentially dangerous. It is designed for use when
1198            multiple state runs can safely be run at the same time. Do *not*
1199            use this flag for performance optimization.
1200
1201    saltenv
1202        Specify a salt fileserver environment to be used when applying states
1203
1204        .. versionchanged:: 0.17.0
1205            Argument name changed from ``env`` to ``saltenv``.
1206
1207        .. versionchanged:: 2014.7.0
1208            If no saltenv is specified, the minion config will be checked for an
1209            ``environment`` parameter and if found, it will be used. If none is
1210            found, ``base`` will be used. In prior releases, the minion config
1211            was not checked and ``base`` would always be assumed when the
1212            saltenv was not explicitly set.
1213
1214    pillarenv
1215        Specify a Pillar environment to be used when applying states. This
1216        can also be set in the minion config file using the
1217        :conf_minion:`pillarenv` option. When neither the
1218        :conf_minion:`pillarenv` minion config option nor this CLI argument is
1219        used, all Pillar environments will be merged together.
1220
1221    localconfig
1222        Optionally, instead of using the minion config, load minion opts from
1223        the file specified by this argument, and then merge them with the
1224        options from the minion config. This functionality allows for specific
1225        states to be run with their own custom minion configuration, including
1226        different pillars, file_roots, etc.
1227
1228    mock
1229        The mock option allows for the state run to execute without actually
1230        calling any states. This then returns a mocked return which will show
1231        the requisite ordering as well as fully validate the state run.
1232
1233        .. versionadded:: 2015.8.4
1234
1235    sync_mods
1236        If specified, the desired custom module types will be synced prior to
1237        running the SLS files:
1238
1239        .. code-block:: bash
1240
1241            salt '*' state.sls stuff sync_mods=states,modules
1242            salt '*' state.sls stuff sync_mods=all
1243
1244        .. versionadded:: 2017.7.8,2018.3.3,2019.2.0
1245
1246    CLI Example:
1247
1248    .. code-block:: bash
1249
1250        # Run the states configured in salt://example.sls (or salt://example/init.sls)
1251        salt '*' state.apply example
1252
1253        # Run the states configured in salt://core.sls (or salt://core/init.sls)
1254        # and salt://edit/vim.sls (or salt://edit/vim/init.sls)
1255        salt '*' state.sls core,edit.vim
1256
1257        # Run the states configured in a more deeply nested directory such as salt://my/nested/state.sls (or salt://my/nested/state/init.sls)
1258        salt '*' state.sls my.nested.state
1259
1260        salt '*' state.sls core exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
1261        salt '*' state.sls myslsfile pillar="{foo: 'Foo!', bar: 'Bar!'}"
1262    """
1263    concurrent = kwargs.get("concurrent", False)
1264    if "env" in kwargs:
1265        # "env" is not supported; Use "saltenv".
1266        kwargs.pop("env")
1267
1268    # Modification to __opts__ lost after this if-else
1269    if queue:
1270        _wait(kwargs.get("__pub_jid"))
1271    else:
1272        conflict = running(concurrent)
1273        if conflict:
1274            __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
1275            return conflict
1276
1277    if isinstance(mods, list):
1278        disabled = _disabled(mods)
1279    else:
1280        disabled = _disabled([mods])
1281
1282    if disabled:
1283        for state in disabled:
1284            log.debug(
1285                "Salt state %s is disabled. To re-enable, run state.enable %s",
1286                state,
1287                state,
1288            )
1289        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
1290        return disabled
1291
1292    orig_test = __opts__.get("test", None)
1293    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1294
1295    opts["test"] = _get_test_value(test, **kwargs)
1296
1297    # Since this is running a specific SLS file (or files), fall back to the
1298    # 'base' saltenv if none is configured and none was passed.
1299    if opts["saltenv"] is None:
1300        opts["saltenv"] = "base"
1301
1302    pillar_override = kwargs.get("pillar")
1303    pillar_enc = kwargs.get("pillar_enc")
1304    if (
1305        pillar_enc is None
1306        and pillar_override is not None
1307        and not isinstance(pillar_override, dict)
1308    ):
1309        raise SaltInvocationError(
1310            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1311            "is specified."
1312        )
1313
1314    cfn = os.path.join(
1315        __opts__["cachedir"],
1316        "{}.cache.p".format(kwargs.get("cache_name", "highstate")),
1317    )
1318
1319    if sync_mods is True:
1320        sync_mods = ["all"]
1321    if sync_mods is not None:
1322        sync_mods = salt.utils.args.split_input(sync_mods)
1323    else:
1324        sync_mods = []
1325
1326    if "all" in sync_mods and sync_mods != ["all"]:
1327        # Prevent unnecessary extra syncing
1328        sync_mods = ["all"]
1329
1330    for module_type in sync_mods:
1331        try:
1332            __salt__["saltutil.sync_{}".format(module_type)](saltenv=opts["saltenv"])
1333        except KeyError:
1334            log.warning("Invalid custom module type '%s', ignoring", module_type)
1335
1336    try:
1337        st_ = salt.state.HighState(
1338            opts,
1339            pillar_override,
1340            kwargs.get("__pub_jid"),
1341            pillar_enc=pillar_enc,
1342            proxy=dict(__proxy__),
1343            context=dict(__context__),
1344            mocked=kwargs.get("mock", False),
1345            initial_pillar=_get_initial_pillar(opts),
1346        )
1347    except NameError:
1348        st_ = salt.state.HighState(
1349            opts,
1350            pillar_override,
1351            kwargs.get("__pub_jid"),
1352            pillar_enc=pillar_enc,
1353            mocked=kwargs.get("mock", False),
1354            initial_pillar=_get_initial_pillar(opts),
1355        )
1356
1357    with st_:
1358        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
1359        if errors:
1360            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1361            return ["Pillar failed to render with the following messages:"] + errors
1362
1363        orchestration_jid = kwargs.get("orchestration_jid")
1364        with salt.utils.files.set_umask(0o077):
1365            if kwargs.get("cache"):
1366                if os.path.isfile(cfn):
1367                    with salt.utils.files.fopen(cfn, "rb") as fp_:
1368                        high_ = salt.payload.load(fp_)
1369                        return st_.state.call_high(high_, orchestration_jid)
1370
1371        # If the state file is an integer, convert to a string then to unicode
1372        if isinstance(mods, int):
1373            mods = salt.utils.stringutils.to_unicode(str(mods))
1374
1375        mods = salt.utils.args.split_input(mods)
1376
1377        st_.push_active()
1378        try:
1379            high_, errors = st_.render_highstate({opts["saltenv"]: mods})
1380
1381            if errors:
1382                __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
1383                return errors
1384
1385            if exclude:
1386                exclude = salt.utils.args.split_input(exclude)
1387                if "__exclude__" in high_:
1388                    high_["__exclude__"].extend(exclude)
1389                else:
1390                    high_["__exclude__"] = exclude
1391            snapper_pre = _snapper_pre(opts, kwargs.get("__pub_jid", "called localy"))
1392            ret = st_.state.call_high(high_, orchestration_jid)
1393        finally:
1394            st_.pop_active()
1395    if __salt__["config.option"]("state_data", "") == "terse" or kwargs.get("terse"):
1396        ret = _filter_running(ret)
1397    cache_file = os.path.join(__opts__["cachedir"], "sls.p")
1398    with salt.utils.files.set_umask(0o077):
1399        try:
1400            if salt.utils.platform.is_windows():
1401                # Make sure cache file isn't read-only
1402                __salt__["cmd.run"](["attrib", "-R", cache_file], python_shell=False)
1403            with salt.utils.files.fopen(cache_file, "w+b") as fp_:
1404                salt.payload.dump(ret, fp_)
1405        except OSError:
1406            log.error(
1407                "Unable to write to SLS cache file %s. Check permission.", cache_file
1408            )
1409        _set_retcode(ret, high_)
1410        # Work around Windows multiprocessing bug, set __opts__['test'] back to
1411        # value from before this function was run.
1412        __opts__["test"] = orig_test
1413
1414        try:
1415            with salt.utils.files.fopen(cfn, "w+b") as fp_:
1416                try:
1417                    salt.payload.dump(high_, fp_)
1418                except TypeError:
1419                    # Can't serialize pydsl
1420                    pass
1421        except OSError:
1422            log.error(
1423                "Unable to write to highstate cache file %s. Do you have permissions?",
1424                cfn,
1425            )
1426
1427    _snapper_post(opts, kwargs.get("__pub_jid", "called localy"), snapper_pre)
1428    return ret
1429
1430
1431def top(topfn, test=None, queue=False, **kwargs):
1432    """
1433    Execute a specific top file instead of the default. This is useful to apply
1434    configurations from a different environment (for example, dev or prod), without
1435    modifying the default top file.
1436
1437    queue : False
1438        Instead of failing immediately when another state run is in progress,
1439        queue the new state run to begin running once the other has finished.
1440
1441        This option starts a new thread for each queued state run, so use this
1442        option sparingly.
1443
1444    saltenv
1445        Specify a salt fileserver environment to be used when applying states
1446
1447    pillarenv
1448        Specify a Pillar environment to be used when applying states. This
1449        can also be set in the minion config file using the
1450        :conf_minion:`pillarenv` option. When neither the
1451        :conf_minion:`pillarenv` minion config option nor this CLI argument is
1452        used, all Pillar environments will be merged together.
1453
1454        .. versionadded:: 2017.7.0
1455
1456    CLI Example:
1457
1458    .. code-block:: bash
1459
1460        salt '*' state.top reverse_top.sls
1461        salt '*' state.top prod_top.sls exclude=sls_to_exclude
1462        salt '*' state.top dev_top.sls exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
1463    """
1464    conflict = _check_queue(queue, kwargs)
1465    if conflict is not None:
1466        return conflict
1467    orig_test = __opts__.get("test", None)
1468    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1469    opts["test"] = _get_test_value(test, **kwargs)
1470
1471    pillar_override = kwargs.get("pillar")
1472    pillar_enc = kwargs.get("pillar_enc")
1473    if (
1474        pillar_enc is None
1475        and pillar_override is not None
1476        and not isinstance(pillar_override, dict)
1477    ):
1478        raise SaltInvocationError(
1479            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1480            "is specified."
1481        )
1482    try:
1483        st_ = salt.state.HighState(
1484            opts,
1485            pillar_override,
1486            pillar_enc=pillar_enc,
1487            context=dict(__context__),
1488            proxy=dict(__proxy__),
1489            initial_pillar=_get_initial_pillar(opts),
1490        )
1491    except NameError:
1492        st_ = salt.state.HighState(
1493            opts,
1494            pillar_override,
1495            pillar_enc=pillar_enc,
1496            context=dict(__context__),
1497            initial_pillar=_get_initial_pillar(opts),
1498        )
1499
1500    with st_:
1501        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
1502        if errors:
1503            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1504            return ["Pillar failed to render with the following messages:"] + errors
1505
1506        st_.push_active()
1507        st_.opts["state_top"] = salt.utils.url.create(topfn)
1508        ret = {}
1509        orchestration_jid = kwargs.get("orchestration_jid")
1510        if "saltenv" in kwargs:
1511            st_.opts["state_top_saltenv"] = kwargs["saltenv"]
1512        try:
1513            snapper_pre = _snapper_pre(opts, kwargs.get("__pub_jid", "called localy"))
1514            ret = st_.call_highstate(
1515                exclude=kwargs.get("exclude", []),
1516                cache=kwargs.get("cache", None),
1517                cache_name=kwargs.get("cache_name", "highstate"),
1518                orchestration_jid=orchestration_jid,
1519            )
1520        finally:
1521            st_.pop_active()
1522
1523        _set_retcode(ret, highstate=st_.building_highstate)
1524        # Work around Windows multiprocessing bug, set __opts__['test'] back to
1525        # value from before this function was run.
1526        _snapper_post(opts, kwargs.get("__pub_jid", "called localy"), snapper_pre)
1527        __opts__["test"] = orig_test
1528        return ret
1529
1530
1531def show_highstate(queue=False, **kwargs):
1532    """
1533    Retrieve the highstate data from the salt master and display it
1534
1535    Custom Pillar data can be passed with the ``pillar`` kwarg.
1536
1537    CLI Example:
1538
1539    .. code-block:: bash
1540
1541        salt '*' state.show_highstate
1542    """
1543    conflict = _check_queue(queue, kwargs)
1544    if conflict is not None:
1545        return conflict
1546    pillar_override = kwargs.get("pillar")
1547    pillar_enc = kwargs.get("pillar_enc")
1548    if (
1549        pillar_enc is None
1550        and pillar_override is not None
1551        and not isinstance(pillar_override, dict)
1552    ):
1553        raise SaltInvocationError(
1554            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1555            "is specified."
1556        )
1557
1558    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1559    try:
1560        st_ = salt.state.HighState(
1561            opts,
1562            pillar_override,
1563            pillar_enc=pillar_enc,
1564            proxy=__proxy__,
1565            initial_pillar=_get_initial_pillar(opts),
1566        )
1567    except NameError:
1568        st_ = salt.state.HighState(
1569            opts,
1570            pillar_override,
1571            pillar_enc=pillar_enc,
1572            initial_pillar=_get_initial_pillar(opts),
1573        )
1574
1575    with st_:
1576        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
1577        if errors:
1578            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1579            raise CommandExecutionError("Pillar failed to render", info=errors)
1580
1581        st_.push_active()
1582        try:
1583            ret = st_.compile_highstate()
1584        finally:
1585            st_.pop_active()
1586        _set_retcode(ret)
1587        return ret
1588
1589
1590def show_lowstate(queue=False, **kwargs):
1591    """
1592    List out the low data that will be applied to this minion
1593
1594    CLI Example:
1595
1596    .. code-block:: bash
1597
1598        salt '*' state.show_lowstate
1599    """
1600    conflict = _check_queue(queue, kwargs)
1601    if conflict is not None:
1602        assert False
1603        return conflict
1604
1605    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1606    try:
1607        st_ = salt.state.HighState(
1608            opts, proxy=__proxy__, initial_pillar=_get_initial_pillar(opts)
1609        )
1610    except NameError:
1611        st_ = salt.state.HighState(opts, initial_pillar=_get_initial_pillar(opts))
1612
1613    with st_:
1614        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
1615        if errors:
1616            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1617            raise CommandExecutionError("Pillar failed to render", info=errors)
1618
1619        st_.push_active()
1620        try:
1621            ret = st_.compile_low_chunks()
1622        finally:
1623            st_.pop_active()
1624        return ret
1625
1626
1627def show_state_usage(queue=False, **kwargs):
1628    """
1629    Retrieve the highstate data from the salt master to analyse used and unused states
1630
1631    Custom Pillar data can be passed with the ``pillar`` kwarg.
1632
1633    CLI Example:
1634
1635    .. code-block:: bash
1636
1637        salt '*' state.show_state_usage
1638    """
1639    conflict = _check_queue(queue, kwargs)
1640    if conflict is not None:
1641        return conflict
1642    pillar = kwargs.get("pillar")
1643    pillar_enc = kwargs.get("pillar_enc")
1644    if pillar_enc is None and pillar is not None and not isinstance(pillar, dict):
1645        raise SaltInvocationError(
1646            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1647            "is specified."
1648        )
1649
1650    with salt.state.HighState(__opts__, pillar, pillar_enc=pillar_enc) as st_:
1651        st_.push_active()
1652
1653        try:
1654            ret = st_.compile_state_usage()
1655        finally:
1656            st_.pop_active()
1657        _set_retcode(ret)
1658        return ret
1659
1660
1661def show_states(queue=False, **kwargs):
1662    """
1663    Returns the list of states that will be applied on highstate.
1664
1665    CLI Example:
1666
1667    .. code-block:: bash
1668
1669        salt '*' state.show_states
1670
1671    .. versionadded:: 2019.2.0
1672
1673    """
1674    conflict = _check_queue(queue, kwargs)
1675    if conflict is not None:
1676        assert False
1677        return conflict
1678
1679    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1680    try:
1681        st_ = salt.state.HighState(
1682            opts, proxy=__proxy__, initial_pillar=_get_initial_pillar(opts)
1683        )
1684    except NameError:
1685        st_ = salt.state.HighState(opts, initial_pillar=_get_initial_pillar(opts))
1686
1687    with st_:
1688        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
1689        if errors:
1690            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1691            raise CommandExecutionError("Pillar failed to render", info=errors)
1692
1693        st_.push_active()
1694        states = OrderedDict()
1695        try:
1696            result = st_.compile_low_chunks()
1697
1698            if not isinstance(result, list):
1699                raise Exception(result)
1700
1701            for s in result:
1702                if not isinstance(s, dict):
1703                    _set_retcode(result)
1704                    return result
1705                states[s["__sls__"]] = True
1706        finally:
1707            st_.pop_active()
1708
1709        return list(states.keys())
1710
1711
1712def sls_id(id_, mods, test=None, queue=False, **kwargs):
1713    """
1714    Call a single ID from the named module(s) and handle all requisites
1715
1716    The state ID comes *before* the module ID(s) on the command line.
1717
1718    id
1719        ID to call
1720
1721    mods
1722        Comma-delimited list of modules to search for given id and its requisites
1723
1724    .. versionadded:: 2014.7.0
1725
1726    saltenv : base
1727        Specify a salt fileserver environment to be used when applying states
1728
1729    pillarenv
1730        Specify a Pillar environment to be used when applying states. This
1731        can also be set in the minion config file using the
1732        :conf_minion:`pillarenv` option. When neither the
1733        :conf_minion:`pillarenv` minion config option nor this CLI argument is
1734        used, all Pillar environments will be merged together.
1735
1736    pillar
1737        Custom Pillar values, passed as a dictionary of key-value pairs
1738
1739        .. code-block:: bash
1740
1741            salt '*' state.sls_id my_state my_module pillar='{"foo": "bar"}'
1742
1743        .. note::
1744            Values passed this way will override existing Pillar values set via
1745            ``pillar_roots`` or an external Pillar source.  Pillar values that
1746            are not included in the kwarg will not be overwritten.
1747
1748        .. versionadded:: 2018.3.0
1749
1750    CLI Example:
1751
1752    .. code-block:: bash
1753
1754        salt '*' state.sls_id my_state my_module
1755
1756        salt '*' state.sls_id my_state my_module,a_common_module
1757    """
1758    conflict = _check_queue(queue, kwargs)
1759    if conflict is not None:
1760        return conflict
1761    orig_test = __opts__.get("test", None)
1762    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1763    opts["test"] = _get_test_value(test, **kwargs)
1764
1765    # Since this is running a specific ID within a specific SLS file, fall back
1766    # to the 'base' saltenv if none is configured and none was passed.
1767    if opts["saltenv"] is None:
1768        opts["saltenv"] = "base"
1769
1770    pillar_override = kwargs.get("pillar")
1771    pillar_enc = kwargs.get("pillar_enc")
1772    if (
1773        pillar_enc is None
1774        and pillar_override is not None
1775        and not isinstance(pillar_override, dict)
1776    ):
1777        raise SaltInvocationError(
1778            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1779            "is specified."
1780        )
1781
1782    try:
1783        st_ = salt.state.HighState(
1784            opts,
1785            pillar_override,
1786            pillar_enc=pillar_enc,
1787            proxy=__proxy__,
1788            initial_pillar=_get_initial_pillar(opts),
1789        )
1790    except NameError:
1791        st_ = salt.state.HighState(
1792            opts,
1793            pillar_override,
1794            pillar_enc=pillar_enc,
1795            initial_pillar=_get_initial_pillar(opts),
1796        )
1797
1798    with st_:
1799        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
1800        if errors:
1801            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1802            return ["Pillar failed to render with the following messages:"] + errors
1803
1804        split_mods = salt.utils.args.split_input(mods)
1805        st_.push_active()
1806        try:
1807            high_, errors = st_.render_highstate({opts["saltenv"]: split_mods})
1808        finally:
1809            st_.pop_active()
1810        errors += st_.state.verify_high(high_)
1811        # Apply requisites to high data
1812        high_, req_in_errors = st_.state.requisite_in(high_)
1813        if req_in_errors:
1814            # This if statement should not be necessary if there were no errors,
1815            # but it is required to get the unit tests to pass.
1816            errors.extend(req_in_errors)
1817        if errors:
1818            __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
1819            return errors
1820        chunks = st_.state.compile_high_data(high_)
1821        ret = {}
1822        for chunk in chunks:
1823            if chunk.get("__id__", "") == id_:
1824                ret.update(st_.state.call_chunk(chunk, {}, chunks))
1825
1826        _set_retcode(ret, highstate=highstate)
1827        # Work around Windows multiprocessing bug, set __opts__['test'] back to
1828        # value from before this function was run.
1829        __opts__["test"] = orig_test
1830        if not ret:
1831            raise SaltInvocationError(
1832                "No matches for ID '{}' found in SLS '{}' within saltenv '{}'".format(
1833                    id_, mods, opts["saltenv"]
1834                )
1835            )
1836        return ret
1837
1838
1839def show_low_sls(mods, test=None, queue=False, **kwargs):
1840    """
1841    Display the low data from a specific sls. The default environment is
1842    ``base``, use ``saltenv`` to specify a different environment.
1843
1844    saltenv
1845        Specify a salt fileserver environment to be used when applying states
1846
1847    pillar
1848        Custom Pillar values, passed as a dictionary of key-value pairs
1849
1850        .. code-block:: bash
1851
1852            salt '*' state.show_low_sls stuff pillar='{"foo": "bar"}'
1853
1854        .. note::
1855            Values passed this way will override Pillar values set via
1856            ``pillar_roots`` or an external Pillar source.
1857
1858    pillarenv
1859        Specify a Pillar environment to be used when applying states. This
1860        can also be set in the minion config file using the
1861        :conf_minion:`pillarenv` option. When neither the
1862        :conf_minion:`pillarenv` minion config option nor this CLI argument is
1863        used, all Pillar environments will be merged together.
1864
1865    CLI Example:
1866
1867    .. code-block:: bash
1868
1869        salt '*' state.show_low_sls foo
1870        salt '*' state.show_low_sls foo saltenv=dev
1871    """
1872    if "env" in kwargs:
1873        # "env" is not supported; Use "saltenv".
1874        kwargs.pop("env")
1875
1876    conflict = _check_queue(queue, kwargs)
1877    if conflict is not None:
1878        return conflict
1879    orig_test = __opts__.get("test", None)
1880    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1881    opts["test"] = _get_test_value(test, **kwargs)
1882
1883    # Since this is dealing with a specific SLS file (or files), fall back to
1884    # the 'base' saltenv if none is configured and none was passed.
1885    if opts["saltenv"] is None:
1886        opts["saltenv"] = "base"
1887
1888    pillar_override = kwargs.get("pillar")
1889    pillar_enc = kwargs.get("pillar_enc")
1890    if (
1891        pillar_enc is None
1892        and pillar_override is not None
1893        and not isinstance(pillar_override, dict)
1894    ):
1895        raise SaltInvocationError(
1896            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1897            "is specified."
1898        )
1899
1900    try:
1901        st_ = salt.state.HighState(
1902            opts,
1903            pillar_override,
1904            proxy=__proxy__,
1905            initial_pillar=_get_initial_pillar(opts),
1906        )
1907    except NameError:
1908        st_ = salt.state.HighState(
1909            opts, pillar_override, initial_pillar=_get_initial_pillar(opts)
1910        )
1911
1912    with st_:
1913        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
1914        if errors:
1915            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
1916            raise CommandExecutionError("Pillar failed to render", info=errors)
1917
1918        mods = salt.utils.args.split_input(mods)
1919        st_.push_active()
1920        try:
1921            high_, errors = st_.render_highstate({opts["saltenv"]: mods})
1922        finally:
1923            st_.pop_active()
1924        errors += st_.state.verify_high(high_)
1925        if errors:
1926            __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
1927            return errors
1928        ret = st_.state.compile_high_data(high_)
1929        # Work around Windows multiprocessing bug, set __opts__['test'] back to
1930        # value from before this function was run.
1931        __opts__["test"] = orig_test
1932        return ret
1933
1934
1935def show_sls(mods, test=None, queue=False, **kwargs):
1936    """
1937    Display the state data from a specific sls or list of sls files on the
1938    master. The default environment is ``base``, use ``saltenv`` to specify a
1939    different environment.
1940
1941    This function does not support topfiles.  For ``top.sls`` please use
1942    ``show_top`` instead.
1943
1944    Custom Pillar data can be passed with the ``pillar`` kwarg.
1945
1946    saltenv
1947        Specify a salt fileserver environment to be used when applying states
1948
1949    pillarenv
1950        Specify a Pillar environment to be used when applying states. This
1951        can also be set in the minion config file using the
1952        :conf_minion:`pillarenv` option. When neither the
1953        :conf_minion:`pillarenv` minion config option nor this CLI argument is
1954        used, all Pillar environments will be merged together.
1955
1956    CLI Example:
1957
1958    .. code-block:: bash
1959
1960        salt '*' state.show_sls core,edit.vim saltenv=dev
1961    """
1962    if "env" in kwargs:
1963        # "env" is not supported; Use "saltenv".
1964        kwargs.pop("env")
1965
1966    conflict = _check_queue(queue, kwargs)
1967    if conflict is not None:
1968        return conflict
1969    orig_test = __opts__.get("test", None)
1970    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
1971
1972    opts["test"] = _get_test_value(test, **kwargs)
1973
1974    # Since this is dealing with a specific SLS file (or files), fall back to
1975    # the 'base' saltenv if none is configured and none was passed.
1976    if opts["saltenv"] is None:
1977        opts["saltenv"] = "base"
1978
1979    pillar_override = kwargs.get("pillar")
1980    pillar_enc = kwargs.get("pillar_enc")
1981    if (
1982        pillar_enc is None
1983        and pillar_override is not None
1984        and not isinstance(pillar_override, dict)
1985    ):
1986        raise SaltInvocationError(
1987            "Pillar data must be formatted as a dictionary, unless pillar_enc "
1988            "is specified."
1989        )
1990
1991    try:
1992        st_ = salt.state.HighState(
1993            opts,
1994            pillar_override,
1995            pillar_enc=pillar_enc,
1996            proxy=__proxy__,
1997            initial_pillar=_get_initial_pillar(opts),
1998        )
1999    except NameError:
2000        st_ = salt.state.HighState(
2001            opts,
2002            pillar_override,
2003            pillar_enc=pillar_enc,
2004            initial_pillar=_get_initial_pillar(opts),
2005        )
2006
2007    with st_:
2008        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
2009        if errors:
2010            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
2011            raise CommandExecutionError("Pillar failed to render", info=errors)
2012
2013        mods = salt.utils.args.split_input(mods)
2014        st_.push_active()
2015        try:
2016            high_, errors = st_.render_highstate({opts["saltenv"]: mods})
2017        finally:
2018            st_.pop_active()
2019        errors += st_.state.verify_high(high_)
2020        # Work around Windows multiprocessing bug, set __opts__['test'] back to
2021        # value from before this function was run.
2022        __opts__["test"] = orig_test
2023        if errors:
2024            __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
2025            return errors
2026        return high_
2027
2028
2029def sls_exists(mods, test=None, queue=False, **kwargs):
2030    """
2031    Tests for the existence the of a specific SLS or list of SLS files on the
2032    master. Similar to :py:func:`state.show_sls <salt.modules.state.show_sls>`,
2033    rather than returning state details, returns True or False. The default
2034    environment is ``base``, use ``saltenv`` to specify a different environment.
2035
2036    .. versionadded:: 2019.2.0
2037
2038    saltenv
2039        Specify a salt fileserver environment from which to look for the SLS files
2040        specified in the ``mods`` argument
2041
2042    CLI Example:
2043
2044    .. code-block:: bash
2045
2046        salt '*' state.sls_exists core,edit.vim saltenv=dev
2047    """
2048    return isinstance(show_sls(mods, test=test, queue=queue, **kwargs), dict)
2049
2050
2051def id_exists(ids, mods, test=None, queue=False, **kwargs):
2052    """
2053    Tests for the existence of a specific ID or list of IDs within the
2054    specified SLS file(s). Similar to :py:func:`state.sls_exists
2055    <salt.modules.state.sls_exists>`, returns True or False. The default
2056    environment is base``, use ``saltenv`` to specify a different environment.
2057
2058    .. versionadded:: 2019.2.0
2059
2060    saltenv
2061        Specify a salt fileserver environment from which to look for the SLS files
2062        specified in the ``mods`` argument
2063
2064    CLI Example:
2065
2066    .. code-block:: bash
2067
2068        salt '*' state.id_exists create_myfile,update_template filestate saltenv=dev
2069    """
2070    ids = salt.utils.args.split_input(ids)
2071    ids = set(ids)
2072    sls_ids = {
2073        x["__id__"] for x in show_low_sls(mods, test=test, queue=queue, **kwargs)
2074    }
2075    return ids.issubset(sls_ids)
2076
2077
2078def show_top(queue=False, **kwargs):
2079    """
2080    Return the top data that the minion will use for a highstate
2081
2082    CLI Example:
2083
2084    .. code-block:: bash
2085
2086        salt '*' state.show_top
2087    """
2088    if "env" in kwargs:
2089        # "env" is not supported; Use "saltenv".
2090        kwargs.pop("env")
2091
2092    conflict = _check_queue(queue, kwargs)
2093    if conflict is not None:
2094        return conflict
2095
2096    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
2097    try:
2098        st_ = salt.state.HighState(
2099            opts, proxy=__proxy__, initial_pillar=_get_initial_pillar(opts)
2100        )
2101    except NameError:
2102        st_ = salt.state.HighState(opts, initial_pillar=_get_initial_pillar(opts))
2103
2104    with st_:
2105        errors = _get_pillar_errors(kwargs, pillar=st_.opts["pillar"])
2106        if errors:
2107            __context__["retcode"] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
2108            raise CommandExecutionError("Pillar failed to render", info=errors)
2109
2110        errors = []
2111        top_ = st_.get_top()
2112        errors += st_.verify_tops(top_)
2113        if errors:
2114            __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
2115            return errors
2116        matches = st_.top_matches(top_)
2117        return matches
2118
2119
2120def single(fun, name, test=None, queue=False, **kwargs):
2121    """
2122    Execute a single state function with the named kwargs, returns False if
2123    insufficient data is sent to the command
2124
2125    By default, the values of the kwargs will be parsed as YAML. So, you can
2126    specify lists values, or lists of single entry key-value maps, as you
2127    would in a YAML salt file. Alternatively, JSON format of keyword values
2128    is also supported.
2129
2130    CLI Example:
2131
2132    .. code-block:: bash
2133
2134        salt '*' state.single pkg.installed name=vim
2135
2136    """
2137    conflict = _check_queue(queue, kwargs)
2138    if conflict is not None:
2139        return conflict
2140    comps = fun.split(".")
2141    if len(comps) < 2:
2142        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
2143        return "Invalid function passed"
2144    kwargs.update({"state": comps[0], "fun": comps[1], "__id__": name, "name": name})
2145    orig_test = __opts__.get("test", None)
2146    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
2147    opts["test"] = _get_test_value(test, **kwargs)
2148
2149    pillar_override = kwargs.get("pillar")
2150    pillar_enc = kwargs.get("pillar_enc")
2151    if (
2152        pillar_enc is None
2153        and pillar_override is not None
2154        and not isinstance(pillar_override, dict)
2155    ):
2156        raise SaltInvocationError(
2157            "Pillar data must be formatted as a dictionary, unless pillar_enc "
2158            "is specified."
2159        )
2160
2161    try:
2162        st_ = salt.state.State(
2163            opts,
2164            pillar_override,
2165            pillar_enc=pillar_enc,
2166            proxy=__proxy__,
2167            initial_pillar=_get_initial_pillar(opts),
2168        )
2169    except NameError:
2170        st_ = salt.state.State(
2171            opts,
2172            pillar_override,
2173            pillar_enc=pillar_enc,
2174            initial_pillar=_get_initial_pillar(opts),
2175        )
2176    err = st_.verify_data(kwargs)
2177    if err:
2178        __context__["retcode"] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
2179        return err
2180
2181    st_._mod_init(kwargs)
2182    snapper_pre = _snapper_pre(opts, kwargs.get("__pub_jid", "called localy"))
2183    ret = {
2184        "{0[state]}_|-{0[__id__]}_|-{0[name]}_|-{0[fun]}".format(kwargs): st_.call(
2185            kwargs
2186        )
2187    }
2188    _set_retcode(ret)
2189    # Work around Windows multiprocessing bug, set __opts__['test'] back to
2190    # value from before this function was run.
2191    _snapper_post(opts, kwargs.get("__pub_jid", "called localy"), snapper_pre)
2192    __opts__["test"] = orig_test
2193    return ret
2194
2195
2196def clear_cache():
2197    """
2198    Clear out cached state files, forcing even cache runs to refresh the cache
2199    on the next state execution.
2200
2201    Remember that the state cache is completely disabled by default, this
2202    execution only applies if cache=True is used in states
2203
2204    CLI Example:
2205
2206    .. code-block:: bash
2207
2208        salt '*' state.clear_cache
2209    """
2210    ret = []
2211    for fn_ in os.listdir(__opts__["cachedir"]):
2212        if fn_.endswith(".cache.p"):
2213            path = os.path.join(__opts__["cachedir"], fn_)
2214            if not os.path.isfile(path):
2215                continue
2216            os.remove(path)
2217            ret.append(fn_)
2218    return ret
2219
2220
2221def pkg(pkg_path, pkg_sum, hash_type, test=None, **kwargs):
2222    """
2223    Execute a packaged state run, the packaged state run will exist in a
2224    tarball available locally. This packaged state
2225    can be generated using salt-ssh.
2226
2227    CLI Example:
2228
2229    .. code-block:: bash
2230
2231        salt '*' state.pkg /tmp/salt_state.tgz 760a9353810e36f6d81416366fc426dc md5
2232    """
2233    # TODO - Add ability to download from salt master or other source
2234    popts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
2235    if not os.path.isfile(pkg_path):
2236        return {}
2237    if not salt.utils.hashutils.get_hash(pkg_path, hash_type) == pkg_sum:
2238        return {}
2239    root = tempfile.mkdtemp()
2240    s_pkg = tarfile.open(pkg_path, "r:gz")
2241    # Verify that the tarball does not extract outside of the intended root
2242    members = s_pkg.getmembers()
2243    for member in members:
2244        if salt.utils.stringutils.to_unicode(member.path).startswith(
2245            (os.sep, "..{}".format(os.sep))
2246        ):
2247            return {}
2248        elif "..{}".format(os.sep) in salt.utils.stringutils.to_unicode(member.path):
2249            return {}
2250    s_pkg.extractall(root)
2251    s_pkg.close()
2252    lowstate_json = os.path.join(root, "lowstate.json")
2253    with salt.utils.files.fopen(lowstate_json, "r") as fp_:
2254        lowstate = salt.utils.json.load(fp_)
2255    # Check for errors in the lowstate
2256    for chunk in lowstate:
2257        if not isinstance(chunk, dict):
2258            return lowstate
2259    pillar_json = os.path.join(root, "pillar.json")
2260    if os.path.isfile(pillar_json):
2261        with salt.utils.files.fopen(pillar_json, "r") as fp_:
2262            pillar_override = salt.utils.json.load(fp_)
2263    else:
2264        pillar_override = None
2265
2266    roster_grains_json = os.path.join(root, "roster_grains.json")
2267    if os.path.isfile(roster_grains_json):
2268        with salt.utils.files.fopen(roster_grains_json, "r") as fp_:
2269            roster_grains = _format_cached_grains(salt.utils.json.load(fp_))
2270
2271    if os.path.isfile(roster_grains_json):
2272        popts["grains"] = roster_grains
2273    popts["fileclient"] = "local"
2274    popts["file_roots"] = {}
2275    popts["test"] = _get_test_value(test, **kwargs)
2276    envs = os.listdir(root)
2277    for fn_ in envs:
2278        full = os.path.join(root, fn_)
2279        if not os.path.isdir(full):
2280            continue
2281        popts["file_roots"][fn_] = [full]
2282    st_ = salt.state.State(popts, pillar_override=pillar_override)
2283    snapper_pre = _snapper_pre(popts, kwargs.get("__pub_jid", "called localy"))
2284    ret = st_.call_chunks(lowstate)
2285    ret = st_.call_listen(lowstate, ret)
2286    try:
2287        shutil.rmtree(root)
2288    except OSError:
2289        pass
2290    _set_retcode(ret)
2291    _snapper_post(popts, kwargs.get("__pub_jid", "called localy"), snapper_pre)
2292    return ret
2293
2294
2295def disable(states):
2296    """
2297    Disable state runs.
2298
2299    CLI Example:
2300
2301    .. code-block:: bash
2302
2303        salt '*' state.disable highstate
2304
2305        salt '*' state.disable highstate,test.succeed_without_changes
2306
2307    .. note::
2308        To disable a state file from running provide the same name that would
2309        be passed in a state.sls call.
2310
2311        salt '*' state.disable bind.config
2312
2313    """
2314    ret = {"res": True, "msg": ""}
2315
2316    states = salt.utils.args.split_input(states)
2317
2318    msg = []
2319    _disabled_state_runs = __salt__["grains.get"]("state_runs_disabled")
2320    if not isinstance(_disabled_state_runs, list):
2321        _disabled_state_runs = []
2322
2323    _changed = False
2324    for _state in states:
2325        if _state in _disabled_state_runs:
2326            msg.append("Info: {} state already disabled.".format(_state))
2327        else:
2328            msg.append("Info: {} state disabled.".format(_state))
2329            _disabled_state_runs.append(_state)
2330            _changed = True
2331
2332    if _changed:
2333        __salt__["grains.setval"]("state_runs_disabled", _disabled_state_runs)
2334
2335    ret["msg"] = "\n".join(msg)
2336
2337    # refresh the grains
2338    __salt__["saltutil.refresh_modules"]()
2339
2340    return ret
2341
2342
2343def enable(states):
2344    """
2345    Enable state function or sls run
2346
2347    CLI Example:
2348
2349    .. code-block:: bash
2350
2351        salt '*' state.enable highstate
2352
2353        salt '*' state.enable test.succeed_without_changes
2354
2355    .. note::
2356        To enable a state file from running provide the same name that would
2357        be passed in a state.sls call.
2358
2359        salt '*' state.disable bind.config
2360
2361    """
2362    ret = {"res": True, "msg": ""}
2363
2364    states = salt.utils.args.split_input(states)
2365    log.debug("states %s", states)
2366
2367    msg = []
2368    _disabled_state_runs = __salt__["grains.get"]("state_runs_disabled")
2369    if not isinstance(_disabled_state_runs, list):
2370        _disabled_state_runs = []
2371
2372    _changed = False
2373    for _state in states:
2374        log.debug("_state %s", _state)
2375        if _state not in _disabled_state_runs:
2376            msg.append("Info: {} state already enabled.".format(_state))
2377        else:
2378            msg.append("Info: {} state enabled.".format(_state))
2379            _disabled_state_runs.remove(_state)
2380            _changed = True
2381
2382    if _changed:
2383        __salt__["grains.setval"]("state_runs_disabled", _disabled_state_runs)
2384
2385    ret["msg"] = "\n".join(msg)
2386
2387    # refresh the grains
2388    __salt__["saltutil.refresh_modules"]()
2389
2390    return ret
2391
2392
2393def list_disabled():
2394    """
2395    List the states which are currently disabled
2396
2397    CLI Example:
2398
2399    .. code-block:: bash
2400
2401        salt '*' state.list_disabled
2402    """
2403    return __salt__["grains.get"]("state_runs_disabled")
2404
2405
2406def _disabled(funs):
2407    """
2408    Return messages for disabled states
2409    that match state functions in funs.
2410    """
2411    ret = []
2412    _disabled_state_runs = __salt__["grains.get"]("state_runs_disabled")
2413    if not isinstance(_disabled_state_runs, list):
2414        _disabled_state_runs = []
2415    for state in funs:
2416        for _state in _disabled_state_runs:
2417            if ".*" in _state:
2418                target_state = _state.split(".")[0]
2419                target_state = (
2420                    target_state + "."
2421                    if not target_state.endswith(".")
2422                    else target_state
2423                )
2424                if state.startswith(target_state):
2425                    err = (
2426                        'The state file "{0}" is currently disabled by "{1}", '
2427                        "to re-enable, run state.enable {1}.".format(
2428                            state,
2429                            _state,
2430                        )
2431                    )
2432                    ret.append(err)
2433                    continue
2434            else:
2435                if _state == state:
2436                    err = (
2437                        'The state file "{0}" is currently disabled, '
2438                        "to re-enable, run state.enable {0}.".format(
2439                            _state,
2440                        )
2441                    )
2442                    ret.append(err)
2443                    continue
2444    return ret
2445
2446
2447def event(
2448    tagmatch="*", count=-1, quiet=False, sock_dir=None, pretty=False, node="minion"
2449):
2450    r"""
2451    Watch Salt's event bus and block until the given tag is matched
2452
2453    .. versionadded:: 2016.3.0
2454    .. versionchanged:: 2019.2.0
2455        ``tagmatch`` can now be either a glob or regular expression.
2456
2457    This is useful for utilizing Salt's event bus from shell scripts or for
2458    taking simple actions directly from the CLI.
2459
2460    Enable debug logging to see ignored events.
2461
2462    :param tagmatch: the event is written to stdout for each tag that matches
2463        this glob or regular expression.
2464    :param count: this number is decremented for each event that matches the
2465        ``tagmatch`` parameter; pass ``-1`` to listen forever.
2466    :param quiet: do not print to stdout; just block
2467    :param sock_dir: path to the Salt master's event socket file.
2468    :param pretty: Output the JSON all on a single line if ``False`` (useful
2469        for shell tools); pretty-print the JSON output if ``True``.
2470    :param node: Watch the minion-side or master-side event bus.
2471
2472    CLI Example:
2473
2474    .. code-block:: bash
2475
2476        salt-call --local state.event pretty=True
2477    """
2478    with salt.utils.event.get_event(
2479        node,
2480        sock_dir or __opts__["sock_dir"],
2481        __opts__["transport"],
2482        opts=__opts__,
2483        listen=True,
2484    ) as sevent:
2485
2486        while True:
2487            ret = sevent.get_event(full=True, auto_reconnect=True)
2488            if ret is None:
2489                continue
2490
2491            if salt.utils.stringutils.expr_match(ret["tag"], tagmatch):
2492                if not quiet:
2493                    salt.utils.stringutils.print_cli(
2494                        "{}\t{}".format(
2495                            salt.utils.stringutils.to_str(ret["tag"]),
2496                            salt.utils.json.dumps(
2497                                salt.utils.data.decode(ret["data"]),
2498                                sort_keys=pretty,
2499                                indent=None if not pretty else 4,
2500                            ),
2501                        )
2502                    )
2503                    sys.stdout.flush()
2504
2505                if count > 0:
2506                    count -= 1
2507                    log.debug("Remaining event matches: %s", count)
2508
2509                if count == 0:
2510                    break
2511            else:
2512                log.debug("Skipping event tag: %s", ret["tag"])
2513                continue
2514