Execute a wheel module and function. This function must be run against a
    minion that is local to the master.

    .. versionadded:: 2014.7.0

    name
        The name of the function to run

    args
        Any positional arguments to pass to the wheel function. A common example
        of this would be the ``match`` arg needed for key functions.

        .. versionadded:: v2015.8.11

    kwargs
        Any keyword arguments to pass to the wheel function

    asynchronous
        Run the salt command but don't wait for a reply.

        .. versionadded:: neon

    CLI Example:

    .. code-block:: bash

        salt my-local-minion saltutil.wheel key.accept jerry
        salt my-local-minion saltutil.wheel minions.connected

    .. note::

        Since this function must be run against a minion that is running locally
        on the master in order to get accurate returns, if this function is run
        against minions that are not local to the master, "empty" returns are
        expected. The remote minion does not have access to wheel functions and
        their return data.

def wheel(name, *args, **kwargs):
    '''
    Execute a wheel module and function. This function must be run against a
    minion that is local to the master.

    .. versionadded:: 2014.7.0

    name
        The name of the function to run

    args
        Any positional arguments to pass to the wheel function. A common example
        of this would be the ``match`` arg needed for key functions.

        .. versionadded:: v2015.8.11

    kwargs
        Any keyword arguments to pass to the wheel function

    asynchronous
        Run the salt command but don't wait for a reply.

        .. versionadded:: neon

    CLI Example:

    .. code-block:: bash

        salt my-local-minion saltutil.wheel key.accept jerry
        salt my-local-minion saltutil.wheel minions.connected

    .. note::

        Since this function must be run against a minion that is running locally
        on the master in order to get accurate returns, if this function is run
        against minions that are not local to the master, "empty" returns are
        expected. The remote minion does not have access to wheel functions and
        their return data.

    '''
    jid = kwargs.pop('__orchestration_jid__', None)
    saltenv = kwargs.pop('__env__', 'base')

    if __opts__['__role'] == 'minion':
        master_config = os.path.join(os.path.dirname(__opts__['conf_file']),
                                     'master')
        master_opts = salt.config.client_config(master_config)
        wheel_client = salt.wheel.WheelClient(master_opts)
    else:
        wheel_client = salt.wheel.WheelClient(__opts__)

    # The WheelClient cmd needs args, kwargs, and pub_data separated out from
    # the "normal" kwargs structure, which at this point contains __pub_x keys.
    pub_data = {}
    valid_kwargs = {}
    for key, val in six.iteritems(kwargs):
        if key.startswith('__'):
            pub_data[key] = val
        else:
            valid_kwargs[key] = val

    try:
        if name in wheel_client.functions:
            aspec = salt.utils.args.get_function_argspec(
                wheel_client.functions[name]
            )
            if 'saltenv' in aspec.args:
                valid_kwargs['saltenv'] = saltenv

        if jid:
            salt.utils.event.fire_args(
                __opts__,
                jid,
                {'type': 'wheel', 'name': name, 'args': valid_kwargs},
                prefix='run'
            )

        if kwargs.pop('asynchronous', False):
            master_key = salt.utils.master.get_master_key('root', __opts__)
            low = {'arg': args, 'kwarg': kwargs, 'fun': name, 'key': master_key}
            ret = wheel_client.cmd_async(low)
        else:
            ret = wheel_client.cmd(name,
                                   arg=args,
                                   pub_data=pub_data,
                                   kwarg=valid_kwargs,
                                   print_event=False,
                                   full_return=True)
    except SaltInvocationError as e:
        raise CommandExecutionError(
            'This command can only be executed on a minion that is located on '
            'the master.'
        )

    return ret