Call a single ID from the named module(s) and handle all requisites

    The state ID comes *before* the module ID(s) on the command line.

    id
        ID to call

    mods
        Comma-delimited list of modules to search for given id and its requisites

    .. versionadded:: 2014.7.0

    saltenv : base
        Specify a salt fileserver environment to be used when applying states

    pillarenv
        Specify a Pillar environment to be used when applying states. This
        can also be set in the minion config file using the
        :conf_minion:`pillarenv` option. When neither the
        :conf_minion:`pillarenv` minion config option nor this CLI argument is
        used, all Pillar environments will be merged together.

    pillar
        Custom Pillar values, passed as a dictionary of key-value pairs

        .. code-block:: bash

            salt '*' state.sls_id my_state my_module pillar='{"foo": "bar"}'

        .. note::
            Values passed this way will override existing Pillar values set via
            ``pillar_roots`` or an external Pillar source.  Pillar values that
            are not included in the kwarg will not be overwritten.

        .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: bash

        salt '*' state.sls_id my_state my_module

        salt '*' state.sls_id my_state my_module,a_common_module

def sls_id(id_, mods, test=None, queue=False, **kwargs):
    '''
    Call a single ID from the named module(s) and handle all requisites

    The state ID comes *before* the module ID(s) on the command line.

    id
        ID to call

    mods
        Comma-delimited list of modules to search for given id and its requisites

    .. versionadded:: 2014.7.0

    saltenv : base
        Specify a salt fileserver environment to be used when applying states

    pillarenv
        Specify a Pillar environment to be used when applying states. This
        can also be set in the minion config file using the
        :conf_minion:`pillarenv` option. When neither the
        :conf_minion:`pillarenv` minion config option nor this CLI argument is
        used, all Pillar environments will be merged together.

    pillar
        Custom Pillar values, passed as a dictionary of key-value pairs

        .. code-block:: bash

            salt '*' state.sls_id my_state my_module pillar='{"foo": "bar"}'

        .. note::
            Values passed this way will override existing Pillar values set via
            ``pillar_roots`` or an external Pillar source.  Pillar values that
            are not included in the kwarg will not be overwritten.

        .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: bash

        salt '*' state.sls_id my_state my_module

        salt '*' state.sls_id my_state my_module,a_common_module
    '''
    conflict = _check_queue(queue, kwargs)
    if conflict is not None:
        return conflict
    orig_test = __opts__.get('test', None)
    opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
    opts['test'] = _get_test_value(test, **kwargs)

    # Since this is running a specific ID within a specific SLS file, fall back
    # to the 'base' saltenv if none is configured and none was passed.
    if opts['saltenv'] is None:
        opts['saltenv'] = 'base'

    pillar_override = kwargs.get('pillar')
    pillar_enc = kwargs.get('pillar_enc')
    if pillar_enc is None \
            and pillar_override is not None \
            and not isinstance(pillar_override, dict):
        raise SaltInvocationError(
            'Pillar data must be formatted as a dictionary, unless pillar_enc '
            'is specified.'
        )

    try:
        st_ = salt.state.HighState(opts,
                                   pillar_override,
                                   pillar_enc=pillar_enc,
                                   proxy=__proxy__,
                                   initial_pillar=_get_initial_pillar(opts))
    except NameError:
        st_ = salt.state.HighState(opts,
                                   pillar_override,
                                   pillar_enc=pillar_enc,
                                   initial_pillar=_get_initial_pillar(opts))

    errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
    if errors:
        __context__['retcode'] = salt.defaults.exitcodes.EX_PILLAR_FAILURE
        return ['Pillar failed to render with the following messages:'] + errors

    split_mods = salt.utils.args.split_input(mods)
    st_.push_active()
    try:
        high_, errors = st_.render_highstate({opts['saltenv']: split_mods})
    finally:
        st_.pop_active()
    errors += st_.state.verify_high(high_)
    # Apply requisites to high data
    high_, req_in_errors = st_.state.requisite_in(high_)
    if req_in_errors:
        # This if statement should not be necessary if there were no errors,
        # but it is required to get the unit tests to pass.
        errors.extend(req_in_errors)
    if errors:
        __context__['retcode'] = salt.defaults.exitcodes.EX_STATE_COMPILER_ERROR
        return errors
    chunks = st_.state.compile_high_data(high_)
    ret = {}
    for chunk in chunks:
        if chunk.get('__id__', '') == id_:
            ret.update(st_.state.call_chunk(chunk, {}, chunks))

    _set_retcode(ret, highstate=highstate)
    # Work around Windows multiprocessing bug, set __opts__['test'] back to
    # value from before this function was run.
    __opts__['test'] = orig_test
    if not ret:
        raise SaltInvocationError(
            'No matches for ID \'{0}\' found in SLS \'{1}\' within saltenv '
            '\'{2}\''.format(id_, mods, opts['saltenv'])
        )
    return ret