Instruction:
Write a Python 3 script for
setting the timezone of the current system process.

Response:
def set_zone(timezone):
    '''
    Unlinks, then symlinks /etc/localtime to the set timezone.

    The timezone is crucial to several system processes, each of which SHOULD
    be restarted (for instance, whatever you system uses as its cron and
    syslog daemons). This will not be automagically done and must be done
    manually!

    CLI Example:

    .. code-block:: bash

        salt '*' timezone.set_zone 'America/Denver'

    .. versionchanged:: 2016.11.4

    .. note::

        On AIX operating systems, Posix values are also allowed, see below

    .. code-block:: bash

        salt '*' timezone.set_zone 'CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00'

    '''
    if salt.utils.path.which('timedatectl'):
        try:
            __salt__['cmd.run']('timedatectl set-timezone {0}'.format(timezone))
        except CommandExecutionError:
            pass

    if 'Solaris' in __grains__['os_family'] or 'AIX' in __grains__['os_family']:
        zonepath = '/usr/share/lib/zoneinfo/{0}'.format(timezone)
    else:
        zonepath = '/usr/share/zoneinfo/{0}'.format(timezone)

    if not os.path.exists(zonepath) and 'AIX' not in __grains__['os_family']:
        return 'Zone does not exist: {0}'.format(zonepath)

    tzfile = _get_localtime_path()
    if os.path.exists(tzfile):
        os.unlink(tzfile)

    if 'Solaris' in __grains__['os_family']:
        __salt__['file.sed'](
            '/etc/default/init', '^TZ=.*', 'TZ={0}'.format(timezone))
    elif 'AIX' in __grains__['os_family']:
        # timezone could be Olson or Posix
        curtzstring = get_zone()
        cmd = ['chtz', timezone]
        result = __salt__['cmd.retcode'](cmd, python_shell=False)
        if result == 0:
            return True

        # restore orig timezone, since AIX chtz failure sets UTC
        cmd = ['chtz', curtzstring]
        __salt__['cmd.retcode'](cmd, python_shell=False)
        return False
    else:
        os.symlink(zonepath, tzfile)

    if 'RedHat' in __grains__['os_family']:
        __salt__['file.sed'](
            '/etc/sysconfig/clock', '^ZONE=.*', 'ZONE="{0}"'.format(timezone))
    elif 'Suse' in __grains__['os_family']:
        __salt__['file.sed'](
            '/etc/sysconfig/clock', '^TIMEZONE=.*', 'TIMEZONE="{0}"'.format(timezone))
    elif 'Debian' in __grains__['os_family'] or 'Gentoo' in __grains__['os_family']:
        with salt.utils.files.fopen('/etc/timezone', 'w') as ofh:
            ofh.write(salt.utils.stringutils.to_str(timezone).strip())
            ofh.write('\n')

    return True


Instruction:
Can you tell what is the following Python 3 function doing
def zone_compare(timezone):
    '''
    Compares the given timezone name with the system timezone name.
    Checks the hash sum between the given timezone, and the one set in
    /etc/localtime. Returns True if names and hash sums match, and False if not.
    Mostly useful for running state checks.

    .. versionchanged:: 2016.3.0

    .. note::

        On Solaris-link operating systems only a string comparison is done.

    .. versionchanged:: 2016.11.4

    .. note::

        On AIX operating systems only a string comparison is done.

    CLI Example:

    .. code-block:: bash

        salt '*' timezone.zone_compare 'America/Denver'
    '''
    if 'Solaris' in __grains__['os_family'] or 'AIX' in __grains__['os_family']:
        return timezone == get_zone()

    if 'FreeBSD' in __grains__['os_family']:
        if not os.path.isfile(_get_localtime_path()):
            return timezone == get_zone()

    tzfile = _get_localtime_path()
    zonepath = _get_zone_file(timezone)
    try:
        return filecmp.cmp(tzfile, zonepath, shallow=False)
    except OSError as exc:
        problematic_file = exc.filename
        if problematic_file == zonepath:
            raise SaltInvocationError(
                'Can\'t find a local timezone "{0}"'.format(timezone))
        elif problematic_file == tzfile:
            raise CommandExecutionError(
                'Failed to read {0} to determine current timezone: {1}'
                .format(tzfile, exc.strerror))
        raise

Response: Compare the given timezone name with the system timezone name.


Instruction:
Here you have a function in Python 3, explain what it does
def get_hwclock():
    '''
    Get current hardware clock setting (UTC or localtime)

    CLI Example:

    .. code-block:: bash

        salt '*' timezone.get_hwclock
    '''
    if salt.utils.path.which('timedatectl'):
        ret = _timedatectl()
        for line in (x.strip() for x in ret['stdout'].splitlines()):
            if 'rtc in local tz' in line.lower():
                try:
                    if line.split(':')[-1].strip().lower() == 'yes':
                        return 'localtime'
                    else:
                        return 'UTC'
                except IndexError:
                    pass

        msg = ('Failed to parse timedatectl output: {0}\n'
               'Please file an issue with SaltStack').format(ret['stdout'])
        raise CommandExecutionError(msg)

    else:
        os_family = __grains__['os_family']
        for family in ('RedHat', 'Suse', 'NILinuxRT'):
            if family in os_family:
                return _get_adjtime_timezone()

        if 'Debian' in __grains__['os_family']:
            # Original way to look up hwclock on Debian-based systems
            try:
                with salt.utils.files.fopen('/etc/default/rcS', 'r') as fp_:
                    for line in fp_:
                        line = salt.utils.stringutils.to_unicode(line)
                        if re.match(r'^\s*#', line):
                            continue
                        if 'UTC=' in line:
                            is_utc = line.rstrip('\n').split('=')[-1].lower()
                            if is_utc == 'yes':
                                return 'UTC'
                            else:
                                return 'localtime'
            except IOError as exc:
                pass
            # Since Wheezy
            return _get_adjtime_timezone()

        if 'Gentoo' in __grains__['os_family']:
            if not os.path.exists('/etc/adjtime'):
                offset_file = '/etc/conf.d/hwclock'
                try:
                    with salt.utils.files.fopen(offset_file, 'r') as fp_:
                        for line in fp_:
                            line = salt.utils.stringutils.to_unicode(line)
                            if line.startswith('clock='):
                                line = line.rstrip('\n')
                                line = line.split('=')[-1].strip('\'"')
                                if line == 'UTC':
                                    return line
                                if line == 'local':
                                    return 'LOCAL'
                        raise CommandExecutionError(
                            'Correct offset value not found in {0}'
                            .format(offset_file)
                        )
                except IOError as exc:
                    raise CommandExecutionError(
                        'Problem reading offset file {0}: {1}'
                        .format(offset_file, exc.strerror)
                    )
            return _get_adjtime_timezone()

        if 'Solaris' in __grains__['os_family']:
            offset_file = '/etc/rtc_config'
            try:
                with salt.utils.files.fopen(offset_file, 'r') as fp_:
                    for line in fp_:
                        line = salt.utils.stringutils.to_unicode(line)
                        if line.startswith('zone_info=GMT'):
                            return 'UTC'
                    return 'localtime'
            except IOError as exc:
                if exc.errno == errno.ENOENT:
                    # offset file does not exist
                    return 'UTC'
                raise CommandExecutionError(
                    'Problem reading offset file {0}: {1}'
                    .format(offset_file, exc.strerror)
                )

        if 'AIX' in __grains__['os_family']:
            offset_file = '/etc/environment'
            try:
                with salt.utils.files.fopen(offset_file, 'r') as fp_:
                    for line in fp_:
                        line = salt.utils.stringutils.to_unicode(line)
                        if line.startswith('TZ=UTC'):
                            return 'UTC'
                    return 'localtime'
            except IOError as exc:
                if exc.errno == errno.ENOENT:
                    # offset file does not exist
                    return 'UTC'
                raise CommandExecutionError(
                    'Problem reading offset file {0}: {1}'
                    .format(offset_file, exc.strerror)
                )

Response: Return the current hardware clock setting


Instruction:
Write a Python 3 script to
set the hardware clock for the current system to either UTC or localtime

Response:
def set_hwclock(clock):
    '''
    Sets the hardware clock to be either UTC or localtime

    CLI Example:

    .. code-block:: bash

        salt '*' timezone.set_hwclock UTC
    '''
    if salt.utils.path.which('timedatectl'):
        cmd = ['timedatectl', 'set-local-rtc',
               'true' if clock == 'localtime' else 'false']
        return __salt__['cmd.retcode'](cmd, python_shell=False) == 0
    else:
        os_family = __grains__['os_family']
        if os_family in ('AIX', 'NILinuxRT'):
            if clock.lower() != 'utc':
                raise SaltInvocationError(
                    'UTC is the only permitted value'
                )
            return True

        timezone = get_zone()

        if 'Solaris' in __grains__['os_family']:
            if clock.lower() not in ('localtime', 'utc'):
                raise SaltInvocationError(
                    'localtime and UTC are the only permitted values'
                )
            if 'sparc' in __grains__['cpuarch']:
                raise SaltInvocationError(
                    'UTC is the only choice for SPARC architecture'
                )
            cmd = ['rtc', '-z', 'GMT' if clock.lower() == 'utc' else timezone]
            return __salt__['cmd.retcode'](cmd, python_shell=False) == 0

        zonepath = '/usr/share/zoneinfo/{0}'.format(timezone)

        if not os.path.exists(zonepath):
            raise CommandExecutionError(
                'Zone \'{0}\' does not exist'.format(zonepath)
            )

        os.unlink('/etc/localtime')
        os.symlink(zonepath, '/etc/localtime')

        if 'Arch' in __grains__['os_family']:
            cmd = ['timezonectl', 'set-local-rtc',
                   'true' if clock == 'localtime' else 'false']
            return __salt__['cmd.retcode'](cmd, python_shell=False) == 0
        elif 'RedHat' in __grains__['os_family']:
            __salt__['file.sed'](
                '/etc/sysconfig/clock', '^ZONE=.*', 'ZONE="{0}"'.format(timezone))
        elif 'Suse' in __grains__['os_family']:
            __salt__['file.sed'](
                '/etc/sysconfig/clock', '^TIMEZONE=.*', 'TIMEZONE="{0}"'.format(timezone))
        elif 'Debian' in __grains__['os_family']:
            if clock == 'UTC':
                __salt__['file.sed']('/etc/default/rcS', '^UTC=.*', 'UTC=yes')
            elif clock == 'localtime':
                __salt__['file.sed']('/etc/default/rcS', '^UTC=.*', 'UTC=no')
        elif 'Gentoo' in __grains__['os_family']:
            if clock not in ('UTC', 'localtime'):
                raise SaltInvocationError(
                    'Only \'UTC\' and \'localtime\' are allowed'
                )
            if clock == 'localtime':
                clock = 'local'
            __salt__['file.sed'](
                '/etc/conf.d/hwclock', '^clock=.*', 'clock="{0}"'.format(clock))

    return True


Instruction:
How would you code a function in Python 3 to
return a new Chocolatey package if it is already installed.

Response:
def installed(name, version=None, source=None, force=False, pre_versions=False,
              install_args=None, override_args=False, force_x86=False,
              package_args=None, allow_multiple=False, execution_timeout=None):
    '''
    Installs a package if not already installed

    Args:

        name (str):
            The name of the package to be installed. Required.

        version (str):
            Install a specific version of the package. Defaults to latest
            version. If the version is different to the one installed then the
            specified version will be installed. Default is None.

        source (str):
            Chocolatey repository (directory, share or remote URL, feed).
            Defaults to the official Chocolatey feed. Default is None.

        force (bool):
            Reinstall the current version of an existing package. Do not use
            with ``allow_multiple``. Default is False.

        pre_versions (bool):
            Include pre-release packages. Default is False.

        install_args (str):
            Install arguments you want to pass to the installation process, i.e
            product key or feature list. Default is None.

        override_args (bool):
            Set to True if you want to override the original install arguments
            (for the native installer) in the package and use your own. When
            this is set to False install_args will be appended to the end of the
            default arguments. Default is False.

        force_x86 (bool):
            Force x86 (32bit) installation on 64 bit systems. Default is False.

        package_args (str):
            Arguments you want to pass to the package. Default is None.

        allow_multiple (bool):
            Allow mulitiple versions of the package to be installed. Do not use
            with ``force``. Does not work with all packages. Default is False.

            .. versionadded:: 2017.7.0

        execution_timeout (str):
            Chocolatey execution timeout value you want to pass to the
            installation process. Default is None.

    .. code-block:: yaml

        Installsomepackage:
          chocolatey.installed:
            - name: packagename
            - version: '12.04'
            - source: 'mychocolatey/source'
            - force: True
    '''
    if force and allow_multiple:
        raise SaltInvocationError(
            'Cannot use \'force\' in conjunction with \'allow_multiple\'')

    ret = {'name': name,
           'result': True,
           'changes': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_install = __salt__['chocolatey.list'](local_only=True)

    # Determine action
    # Package not installed
    if name.lower() not in [package.lower() for package in pre_install.keys()]:
        if version:
            ret['changes'] = {name: 'Version {0} will be installed'.format(version)}
        else:
            ret['changes'] = {name: 'Latest version will be installed'}

    # Package installed
    else:
        version_info = __salt__['chocolatey.version'](name=name,
                                                      check_remote=True,
                                                      source=source)

        full_name = name
        for pkg in version_info:
            if name.lower() == pkg.lower():
                full_name = pkg

        installed_version = version_info[full_name]['installed'][0]

        if version:
            if salt.utils.versions.compare(
                    ver1=installed_version, oper="==", ver2=version):
                if force:
                    ret['changes'] = {
                        name: 'Version {0} will be reinstalled'.format(version)}
                    ret['comment'] = 'Reinstall {0} {1}'.format(full_name, version)
                else:
                    ret['comment'] = '{0} {1} is already installed'.format(name, version)
                    if __opts__['test']:
                        ret['result'] = None
                    return ret
            else:
                if allow_multiple:
                    ret['changes'] = {
                        name: 'Version {0} will be installed side by side with '
                              'Version {1} if supported'.format(version, installed_version)
                    }
                    ret['comment'] = (
                        'Install {0} {1} side-by-side with {0} {2}'.format(
                            full_name, version, installed_version
                        )
                    )
                else:
                    ret['changes'] = {
                        name: 'Version {0} will be installed over Version {1}'.format(version, installed_version)
                    }
                    ret['comment'] = 'Install {0} {1} over {0} {2}'.format(
                        full_name, version, installed_version
                    )
                    force = True
        else:
            version = installed_version
            if force:
                ret['changes'] = {
                    name: 'Version {0} will be reinstalled'.format(version)}
                ret['comment'] = 'Reinstall {0} {1}'.format(full_name, version)
            else:
                ret['comment'] = '{0} {1} is already installed'.format(name, version)
                if __opts__['test']:
                    ret['result'] = None
                return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'The installation was tested'
        return ret

    # Install the package
    result = __salt__['chocolatey.install'](name=name,
                                            version=version,
                                            source=source,
                                            force=force,
                                            pre_versions=pre_versions,
                                            install_args=install_args,
                                            override_args=override_args,
                                            force_x86=force_x86,
                                            package_args=package_args,
                                            allow_multiple=allow_multiple,
                                            execution_timeout=execution_timeout)

    if 'Running chocolatey failed' not in result:
        ret['result'] = True
    else:
        ret['result'] = False

    if not ret['result']:
        ret['comment'] = 'Failed to install the package {0}'.format(name)

    # Get list of installed packages after 'chocolatey.install'
    post_install = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.data.compare_dicts(pre_install, post_install)

    return ret


Instruction:
Make a summary of the following Python 3 code
def uninstalled(name, version=None, uninstall_args=None, override_args=False):
    '''
    Uninstalls a package

    name
      The name of the package to be uninstalled

    version
      Uninstalls a specific version of the package. Defaults to latest
      version installed.

    uninstall_args
      A list of uninstall arguments you want to pass to the uninstallation
      process i.e product key or feature list

    override_args
      Set to true if you want to override the original uninstall arguments (
      for the native uninstaller)in the package and use your own.
      When this is set to False uninstall_args will be appended to the end of
      the default arguments

    .. code-block: yaml

      Removemypackage:
        chocolatey.uninstalled:
          - name: mypackage
          - version: '21.5'

    '''

    ret = {'name': name,
           'result': True,
           'changes': {},
           'comment': ''}

    # Get list of currently installed packages
    pre_uninstall = __salt__['chocolatey.list'](local_only=True)

    # Determine if package is installed
    if name.lower() in [package.lower() for package in pre_uninstall.keys()]:
        try:
            ret['changes'] = {
                name: '{0} version {1} will be removed'.format(
                    name, pre_uninstall[name][0]
                )
            }
        except KeyError:
            ret['changes'] = {name: '{0} will be removed'.format(name)}
    else:
        ret['comment'] = 'The package {0} is not installed'.format(name)
        return ret

    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'The uninstall was tested'
        return ret

    # Uninstall the package
    result = __salt__['chocolatey.uninstall'](name,
                                              version,
                                              uninstall_args,
                                              override_args)

    if 'Running chocolatey failed' not in result:
        ret['result'] = True
    else:
        ret['result'] = False

    if not ret['result']:
        ret['comment'] = 'Failed to uninstall the package {0}'.format(name)

    # Get list of installed packages after 'chocolatey.uninstall'
    post_uninstall = __salt__['chocolatey.list'](local_only=True)

    ret['changes'] = salt.utils.data.compare_dicts(pre_uninstall, post_uninstall)

    return ret

Response: Uninstalls a package from the chocolatey system


Instruction:
Implement a function in Python 3 to
store the job information using the configured master_job_cache

Response:
def store_job(opts, load, event=None, mminion=None):
    '''
    Store job information using the configured master_job_cache
    '''
    # Generate EndTime
    endtime = salt.utils.jid.jid_to_time(salt.utils.jid.gen_jid(opts))
    # If the return data is invalid, just ignore it
    if any(key not in load for key in ('return', 'jid', 'id')):
        return False
    if not salt.utils.verify.valid_id(opts, load['id']):
        return False
    if mminion is None:
        mminion = salt.minion.MasterMinion(opts, states=False, rend=False)

    job_cache = opts['master_job_cache']
    if load['jid'] == 'req':
        # The minion is returning a standalone job, request a jobid
        load['arg'] = load.get('arg', load.get('fun_args', []))
        load['tgt_type'] = 'glob'
        load['tgt'] = load['id']

        prep_fstr = '{0}.prep_jid'.format(opts['master_job_cache'])
        try:
            load['jid'] = mminion.returners[prep_fstr](nocache=load.get('nocache', False))
        except KeyError:
            emsg = "Returner '{0}' does not support function prep_jid".format(job_cache)
            log.error(emsg)
            raise KeyError(emsg)

        # save the load, since we don't have it
        saveload_fstr = '{0}.save_load'.format(job_cache)
        try:
            mminion.returners[saveload_fstr](load['jid'], load)
        except KeyError:
            emsg = "Returner '{0}' does not support function save_load".format(job_cache)
            log.error(emsg)
            raise KeyError(emsg)
    elif salt.utils.jid.is_jid(load['jid']):
        # Store the jid
        jidstore_fstr = '{0}.prep_jid'.format(job_cache)
        try:
            mminion.returners[jidstore_fstr](False, passed_jid=load['jid'])
        except KeyError:
            emsg = "Returner '{0}' does not support function prep_jid".format(job_cache)
            log.error(emsg)
            raise KeyError(emsg)

    if event:
        # If the return data is invalid, just ignore it
        log.info('Got return from %s for job %s', load['id'], load['jid'])
        event.fire_event(load,
                         salt.utils.event.tagify([load['jid'], 'ret', load['id']], 'job'))
        event.fire_ret_load(load)

    # if you have a job_cache, or an ext_job_cache, don't write to
    # the regular master cache
    if not opts['job_cache'] or opts.get('ext_job_cache'):
        return

    # do not cache job results if explicitly requested
    if load.get('jid') == 'nocache':
        log.debug('Ignoring job return with jid for caching %s from %s',
                  load['jid'], load['id'])
        return

    # otherwise, write to the master cache
    savefstr = '{0}.save_load'.format(job_cache)
    getfstr = '{0}.get_load'.format(job_cache)
    fstr = '{0}.returner'.format(job_cache)
    updateetfstr = '{0}.update_endtime'.format(job_cache)
    if 'fun' not in load and load.get('return', {}):
        ret_ = load.get('return', {})
        if 'fun' in ret_:
            load.update({'fun': ret_['fun']})
        if 'user' in ret_:
            load.update({'user': ret_['user']})

    # Try to reach returner methods
    try:
        savefstr_func = mminion.returners[savefstr]
        getfstr_func = mminion.returners[getfstr]
        fstr_func = mminion.returners[fstr]
    except KeyError as error:
        emsg = "Returner '{0}' does not support function {1}".format(job_cache, error)
        log.error(emsg)
        raise KeyError(emsg)

    if job_cache != 'local_cache':
        try:
            mminion.returners[savefstr](load['jid'], load)
        except KeyError as e:
            log.error("Load does not contain 'jid': %s", e)

    mminion.returners[fstr](load)

    if (opts.get('job_cache_store_endtime')
            and updateetfstr in mminion.returners):
        mminion.returners[updateetfstr](load['jid'], endtime)


Instruction:
Write a Python 3 function for
storing additional minions matched on lower - level masters using the configured master_job_cache

Response:
def store_minions(opts, jid, minions, mminion=None, syndic_id=None):
    '''
    Store additional minions matched on lower-level masters using the configured
    master_job_cache
    '''
    if mminion is None:
        mminion = salt.minion.MasterMinion(opts, states=False, rend=False)
    job_cache = opts['master_job_cache']
    minions_fstr = '{0}.save_minions'.format(job_cache)

    try:
        mminion.returners[minions_fstr](jid, minions, syndic_id=syndic_id)
    except KeyError:
        raise KeyError(
            'Returner \'{0}\' does not support function save_minions'.format(
                job_cache
            )
        )


Instruction:
Can you create a Python 3 function that
determines a retcode for a given return value

Response:
def get_retcode(ret):
    '''
    Determine a retcode for a given return
    '''
    retcode = 0
    # if there is a dict with retcode, use that
    if isinstance(ret, dict) and ret.get('retcode', 0) != 0:
        return ret['retcode']
    # if its a boolean, False means 1
    elif isinstance(ret, bool) and not ret:
        return 1
    return retcode


Instruction:
Given the following Python 3 function, write the documentation
def beacon(config):
    '''
    Checks for locked accounts due to too many invalid login attempts, 3 or higher.

    .. code-block:: yaml

        beacons:
          aix_account:
            user: ALL
            interval: 120

    '''

    ret = []

    user = config['user']

    locked_accounts = __salt__['shadow.login_failures'](user)
    ret.append({'accounts': locked_accounts})

    return ret

Response: Check for locked accounts due to too many invalid login attempts 3 or higher.


Instruction:
Implement a function in Python 3 to
post data to OpsGenie. It's designed for Salt's Event Reactor. After configuring the sls reaction file as shown above, you can trigger the module with your designated tag (og-tag in this case). CLI Example: .. code-block:: bash salt-call event.send 'og-tag' '{"reason" : "Overheating CPU!"}' Required parameters: api_key It's the API Key you've copied while adding integration in OpsGenie. reason It will be used as alert's default message in OpsGenie. action_type OpsGenie supports the default values Create/Close for action_type. You can customize this field with OpsGenie's custom actions for other purposes like adding notes or acknowledging alerts. Optional parameters: name It will be used as alert's alias. If you want to use the close functionality you must provide name field for both states like in this case.

Response:
def post_data(api_key=None, name='OpsGenie Execution Module', reason=None,
              action_type=None):
    '''
    Post data to OpsGenie. It's designed for Salt's Event Reactor.

    After configuring the sls reaction file as shown above, you can trigger the
    module with your designated tag (og-tag in this case).

    CLI Example:

    .. code-block:: bash

        salt-call event.send 'og-tag' '{"reason" : "Overheating CPU!"}'

    Required parameters:

    api_key
        It's the API Key you've copied while adding integration in OpsGenie.

    reason
        It will be used as alert's default message in OpsGenie.

    action_type
        OpsGenie supports the default values Create/Close for action_type. You
        can customize this field with OpsGenie's custom actions for other
        purposes like adding notes or acknowledging alerts.

    Optional parameters:

    name
        It will be used as alert's alias. If you want to use the close
        functionality you must provide name field for both states like in
        this case.
    '''
    if api_key is None or reason is None:
        raise salt.exceptions.SaltInvocationError(
            'API Key or Reason cannot be None.')

    data = dict()
    data['alias'] = name
    data['message'] = reason
    # data['actions'] = action_type
    data['cpuModel'] = __grains__['cpu_model']
    data['cpuArch'] = __grains__['cpuarch']
    data['fqdn'] = __grains__['fqdn']
    data['host'] = __grains__['host']
    data['id'] = __grains__['id']
    data['kernel'] = __grains__['kernel']
    data['kernelRelease'] = __grains__['kernelrelease']
    data['master'] = __grains__['master']
    data['os'] = __grains__['os']
    data['saltPath'] = __grains__['saltpath']
    data['saltVersion'] = __grains__['saltversion']
    data['username'] = __grains__['username']
    data['uuid'] = __grains__['uuid']

    log.debug('Below data will be posted:\n%s', data)
    log.debug('API Key: %s \t API Endpoint: %s', api_key, API_ENDPOINT)

    if action_type == "Create":
        response = requests.post(
            url=API_ENDPOINT,
            data=salt.utils.json.dumps(data),
            headers={'Content-Type': 'application/json',
                 'Authorization': 'GenieKey ' + api_key})
    else:
        response = requests.post(
            url=API_ENDPOINT + "/" + name + "/close?identifierType=alias",
            data=salt.utils.json.dumps(data),
            headers={'Content-Type': 'application/json',
                     'Authorization': 'GenieKey ' + api_key})

    return response.status_code, response.text


Instruction:
Create a Python 3 function for
installing a Mac OS Package from a pkg or dmg file.

Response:
def installed(name, target="LocalSystem", dmg=False, store=False, app=False, mpkg=False, user=None, onlyif=None,
              unless=None, force=False, allow_untrusted=False, version_check=None):
    '''
    Install a Mac OS Package from a pkg or dmg file, if given a dmg file it
    will first be mounted in a temporary location

    name
        The pkg or dmg file to install

    target
        The location in which to install the package. This can be a path or LocalSystem

    dmg
        Is the given file a dmg file?

    store
        Should the pkg be installed as if it was from the Mac OS Store?

    app
        Is the file a .app? If so then we'll just copy that to /Applications/ or the given
        target

    mpkg
        Is the file a .mpkg? If so then we'll check all of the .pkg files found are installed

    user
        Name of the user performing the unless or onlyif checks

    onlyif
        A command to run as a check, run the named command only if the command
        passed to the ``onlyif`` option returns true

    unless
        A command to run as a check, only run the named command if the command
        passed to the ``unless`` option returns false

    force
        Force the package to be installed even if its already been found installed

    allow_untrusted
        Allow the installation of untrusted packages

    version_check
        The command and version that we want to check against, the version number can use regex.

        .. code-block:: yaml

            version_check: python --version_check=2.7.[0-9]

    '''
    ret = {'name': name,
           'result': True,
           'comment': '',
           'changes': {}}
    found = []
    installing = []

    real_pkg = name

    # Check onlyif, unless first
    run_check_cmd_kwargs = {'runas': user, 'python_shell': True}
    if 'shell' in __grains__:
        run_check_cmd_kwargs['shell'] = __grains__['shell']

    cret = _mod_run_check(run_check_cmd_kwargs, onlyif, unless)

    if isinstance(cret, dict):
        ret.update(cret)
        return ret

    # Check version info
    if version_check is not None:
        split = version_check.split("=")
        if len(split) == 2:
            version_cmd = split[0]
            expected_version = split[1]
            try:
                version_out = __salt__['cmd.run'](version_cmd, output_loglevel="quiet", ignore_retcode=True)
                version_out = version_out.strip()
            except CommandExecutionError:
                version_out = ""

            if re.match(expected_version, version_out) is not None:
                ret['comment'] += "Version already matches {0}".format(expected_version)
                return ret
            else:
                ret['comment'] += "Version {0} doesn't match {1}. ".format(version_out, expected_version)

    if app and target == "LocalSystem":
        target = "/Applications/"

    # Mount the dmg first
    mount_point = None
    if dmg:
        out, mount_point = __salt__['macpackage.mount'](name)
        if 'attach failed' in out:
            ret['result'] = False
            ret['comment'] += 'Unable to mount {0}'.format(name)
            return ret

        if app:
            real_pkg = mount_point + "/*.app"
        elif mpkg:
            real_pkg = mount_point + "/*.mpkg"
        else:
            real_pkg = mount_point + "/*.pkg"

    try:
        # Check if we have already installed this
        if app:
            if dmg:
                # Run with python shell due to the wildcard
                cmd = 'ls -d *.app'
                out = __salt__['cmd.run'](cmd, cwd=mount_point, python_shell=True)

                if '.app' not in out:
                    ret['result'] = False
                    ret['comment'] += 'Unable to find .app in {0}'.format(mount_point)
                    return ret
                else:
                    pkg_ids = out.split("\n")
            else:
                pkg_ids = [os.path.basename(name)]
                mount_point = os.path.dirname(name)

            if onlyif is None and unless is None and version_check is None:
                for p in pkg_ids:
                    if target[-4:] == ".app":
                        install_dir = target
                    else:
                        install_dir = os.path.join(target, p)
                    if os.path.exists(install_dir) and force is False:
                        found.append(p)
                    else:
                        installing.append(p)
            else:
                installing = pkg_ids
        else:
            installed_pkgs = __salt__['macpackage.installed_pkgs']()

            if mpkg:
                pkg_ids = __salt__['macpackage.get_mpkg_ids'](real_pkg)
            else:
                pkg_ids = __salt__['macpackage.get_pkg_id'](real_pkg)

            if pkg_ids:
                for p in pkg_ids:
                    if p in installed_pkgs and force is False:
                        found.append(p)
                    else:
                        installing.append(p)
                if len(pkg_ids) == len(found):
                    return ret

        if app:
            def failed_pkg(f_pkg):
                ret['result'] = False
                ret['comment'] += '{0} failed to install: {1}'.format(name, out)

                if 'failed' in ret['changes']:
                    ret['changes']['failed'].append(f_pkg)
                else:
                    ret['changes']['failed'] = [f_pkg]

            for app in installing:
                try:
                    log.info('Copying %s to %s', app, target)

                    out = __salt__['macpackage.install_app'](os.path.join(mount_point, app), target)

                    if out:
                        failed_pkg(app)
                    else:
                        ret['comment'] += '{0} installed'.format(app)
                        if 'installed' in ret['changes']:
                            ret['changes']['installed'].append(app)
                        else:
                            ret['changes']['installed'] = [app]

                except OSError:
                    failed_pkg(app)
        else:
            out = __salt__['macpackage.install'](real_pkg, target, store, allow_untrusted)

            if out['retcode'] != 0:
                ret['result'] = False
                ret['comment'] += '. {0} failed to install: {1}'.format(name, out)
            else:
                ret['comment'] += '{0} installed'.format(name)
                ret['changes']['installed'] = installing

    finally:
        if dmg:
            # Unmount to be kind
            __salt__['macpackage.unmount'](mount_point)

    return ret


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _mod_run_check(cmd_kwargs, onlyif, unless):
    '''
    Execute the onlyif and unless logic.
    Return a result dict if:
    * onlyif failed (onlyif != 0)
    * unless succeeded (unless == 0)
    else return True
    '''
    if onlyif:
        if __salt__['cmd.retcode'](onlyif, **cmd_kwargs) != 0:
            return {'comment': 'onlyif condition is false',
                    'skip_watch': True,
                    'result': True}

    if unless:
        if __salt__['cmd.retcode'](unless, **cmd_kwargs) == 0:
            return {'comment': 'unless condition is true',
                    'skip_watch': True,
                    'result': True}

    # No reason to stop, return True
    return True

Response: Execute the onlyif and unless logic.


Instruction:
How would you implement a function in Python 3 that
returns the status of a service via rest_sample. service_status

Response:
def status(name, sig=None):
    '''
    Return the status for a service via rest_sample.
    If the name contains globbing, a dict mapping service name to True/False
    values is returned.

    .. versionadded:: 2015.8.0

    .. versionchanged:: 2018.3.0
        The service name can now be a glob (e.g. ``salt*``)

    Args:
        name (str): The name of the service to check
        sig (str): Not implemented

    Returns:
        bool: True if running, False otherwise
        dict: Maps service name to True if running, False otherwise

    CLI Example:

    .. code-block:: bash

        salt '*' service.status <service name>
    '''

    proxy_fn = 'rest_sample.service_status'
    contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name))
    if contains_globbing:
        services = fnmatch.filter(get_all(), name)
    else:
        services = [name]
    results = {}
    for service in services:
        resp = __proxy__[proxy_fn](service)
        if resp['comment'] == 'running':
            results[service] = True
        else:
            results[service] = False
    if contains_globbing:
        return results
    return results[name]


Instruction:
Can you tell what is the following Python 3 function doing
def clean_proc_dir(opts):

    '''
    Loop through jid files in the minion proc directory (default /var/cache/salt/minion/proc)
    and remove any that refer to processes that no longer exist
    '''

    for basefilename in os.listdir(salt.minion.get_proc_dir(opts['cachedir'])):
        fn_ = os.path.join(salt.minion.get_proc_dir(opts['cachedir']), basefilename)
        with salt.utils.files.fopen(fn_, 'rb') as fp_:
            job = None
            try:
                job = salt.payload.Serial(opts).load(fp_)
            except Exception:  # It's corrupted
                # Windows cannot delete an open file
                if salt.utils.platform.is_windows():
                    fp_.close()
                try:
                    os.unlink(fn_)
                    continue
                except OSError:
                    continue
            log.debug(
                'schedule.clean_proc_dir: checking job %s for process '
                'existence', job
            )
            if job is not None and 'pid' in job:
                if salt.utils.process.os_is_running(job['pid']):
                    log.debug(
                        'schedule.clean_proc_dir: Cleaning proc dir, pid %s '
                        'still exists.', job['pid']
                    )
                else:
                    # Windows cannot delete an open file
                    if salt.utils.platform.is_windows():
                        fp_.close()
                    # Maybe the file is already gone
                    try:
                        os.unlink(fn_)
                    except OSError:
                        pass

Response: Clean the proc directory and remove any processes that no longer exist.


Instruction:
Can you generate the documentation for the following Python 3 function
def option(self, opt):
        '''
        Return options merged from config and pillar
        '''
        if 'config.merge' in self.functions:
            return self.functions['config.merge'](opt, {}, omit_master=True)
        return self.opts.get(opt, {})

Response: Return options merged from config and pillar


Instruction:
How would you code a function in Python 3 to
return the schedule data structure

Response:
def _get_schedule(self,
                      include_opts=True,
                      include_pillar=True,
                      remove_hidden=False):
        '''
        Return the schedule data structure
        '''
        schedule = {}
        if include_pillar:
            pillar_schedule = self.opts.get('pillar', {}).get('schedule', {})
            if not isinstance(pillar_schedule, dict):
                raise ValueError('Schedule must be of type dict.')
            schedule.update(pillar_schedule)
        if include_opts:
            opts_schedule = self.opts.get('schedule', {})
            if not isinstance(opts_schedule, dict):
                raise ValueError('Schedule must be of type dict.')
            schedule.update(opts_schedule)

        if remove_hidden:
            _schedule = copy.deepcopy(schedule)
            for job in _schedule:
                if isinstance(_schedule[job], dict):
                    for item in _schedule[job]:
                        if item.startswith('_'):
                            del schedule[job][item]
        return schedule


Instruction:
Can you tell what is the following Python 3 function doing
def _check_max_running(self, func, data, opts, now):
        '''
        Return the schedule data structure
        '''
        # Check to see if there are other jobs with this
        # signature running.  If there are more than maxrunning
        # jobs present then don't start another.
        # If jid_include is False for this job we can ignore all this
        # NOTE--jid_include defaults to True, thus if it is missing from the data
        # dict we treat it like it was there and is True

        # Check if we're able to run
        if not data['run']:
            return data
        if 'jid_include' not in data or data['jid_include']:
            jobcount = 0
            if self.opts['__role'] == 'master':
                current_jobs = salt.utils.master.get_running_jobs(self.opts)
            else:
                current_jobs = salt.utils.minion.running(self.opts)
            for job in current_jobs:
                if 'schedule' in job:
                    log.debug(
                        'schedule.handle_func: Checking job against fun '
                        '%s: %s', func, job
                    )
                    if data['name'] == job['schedule'] \
                            and salt.utils.process.os_is_running(job['pid']):
                        jobcount += 1
                        log.debug(
                            'schedule.handle_func: Incrementing jobcount, '
                            'now %s, maxrunning is %s',
                            jobcount, data['maxrunning']
                        )
                        if jobcount >= data['maxrunning']:
                            log.debug(
                                'schedule.handle_func: The scheduled job '
                                '%s was not started, %s already running',
                                data['name'], data['maxrunning']
                            )
                            data['_skip_reason'] = 'maxrunning'
                            data['_skipped'] = True
                            data['_skipped_time'] = now
                            data['run'] = False
                            return data
        return data

Response: Check to see if the job is still running and if so start another job if not


Instruction:
How would you explain what the following Python 3 function does
def persist(self):
        '''
        Persist the modified schedule into <<configdir>>/<<default_include>>/_schedule.conf
        '''
        config_dir = self.opts.get('conf_dir', None)
        if config_dir is None and 'conf_file' in self.opts:
            config_dir = os.path.dirname(self.opts['conf_file'])
        if config_dir is None:
            config_dir = salt.syspaths.CONFIG_DIR

        minion_d_dir = os.path.join(
            config_dir,
            os.path.dirname(self.opts.get('default_include',
                                          salt.config.DEFAULT_MINION_OPTS['default_include'])))

        if not os.path.isdir(minion_d_dir):
            os.makedirs(minion_d_dir)

        schedule_conf = os.path.join(minion_d_dir, '_schedule.conf')
        log.debug('Persisting schedule')
        schedule_data = self._get_schedule(include_pillar=False,
                                           remove_hidden=True)
        try:
            with salt.utils.files.fopen(schedule_conf, 'wb+') as fp_:
                fp_.write(
                    salt.utils.stringutils.to_bytes(
                        salt.utils.yaml.safe_dump(
                            {'schedule': schedule_data}
                        )
                    )
                )
        except (IOError, OSError):
            log.error('Failed to persist the updated schedule',
                      exc_info_on_loglevel=logging.DEBUG)

Response: Persist the modified schedule into the _schedule. conf file


Instruction:
Can you create a Python 3 function that
deletes a job from the scheduler. Ignore jobs from pillar

Response:
def delete_job(self, name, persist=True):
        '''
        Deletes a job from the scheduler. Ignore jobs from pillar
        '''
        # ensure job exists, then delete it
        if name in self.opts['schedule']:
            del self.opts['schedule'][name]
        elif name in self._get_schedule(include_opts=False):
            log.warning("Cannot delete job %s, it's in the pillar!", name)

        # Fire the complete event back along with updated list of schedule
        evt = salt.utils.event.get_event('minion', opts=self.opts, listen=False)
        evt.fire_event({'complete': True,
                        'schedule': self._get_schedule()},
                       tag='/salt/minion/minion_schedule_delete_complete')

        # remove from self.intervals
        if name in self.intervals:
            del self.intervals[name]

        if persist:
            self.persist()


Instruction:
Can you create a Python 3 function that
resets the scheduler to defaults

Response:
def reset(self):
        '''
        Reset the scheduler to defaults
        '''
        self.skip_function = None
        self.skip_during_range = None
        self.enabled = True
        self.splay = None
        self.opts['schedule'] = {}


Instruction:
Make a summary of the following Python 3 code
def delete_job_prefix(self, name, persist=True):
        '''
        Deletes a job from the scheduler. Ignores jobs from pillar
        '''
        # ensure job exists, then delete it
        for job in list(self.opts['schedule'].keys()):
            if job.startswith(name):
                del self.opts['schedule'][job]
        for job in self._get_schedule(include_opts=False):
            if job.startswith(name):
                log.warning("Cannot delete job %s, it's in the pillar!", job)

        # Fire the complete event back along with updated list of schedule
        evt = salt.utils.event.get_event('minion', opts=self.opts, listen=False)
        evt.fire_event({'complete': True,
                        'schedule': self._get_schedule()},
                       tag='/salt/minion/minion_schedule_delete_complete')

        # remove from self.intervals
        for job in list(self.intervals.keys()):
            if job.startswith(name):
                del self.intervals[job]

        if persist:
            self.persist()

Response: Deletes a job from the scheduler. Ignores jobs from pillar


Instruction:
Can you generate a brief explanation for the following Python 3 code
def add_job(self, data, persist=True):
        '''
        Adds a new job to the scheduler. The format is the same as required in
        the configuration file. See the docs on how YAML is interpreted into
        python data-structures to make sure, you pass correct dictionaries.
        '''

        # we don't do any checking here besides making sure its a dict.
        # eval() already does for us and raises errors accordingly
        if not isinstance(data, dict):
            raise ValueError('Scheduled jobs have to be of type dict.')
        if not len(data) == 1:
            raise ValueError('You can only schedule one new job at a time.')

        # if enabled is not included in the job,
        # assume job is enabled.
        for job in data:
            if 'enabled' not in data[job]:
                data[job]['enabled'] = True

        new_job = next(six.iterkeys(data))

        if new_job in self._get_schedule(include_opts=False):
            log.warning("Cannot update job %s, it's in the pillar!", new_job)

        elif new_job in self.opts['schedule']:
            log.info('Updating job settings for scheduled job: %s', new_job)
            self.opts['schedule'].update(data)

        else:
            log.info('Added new job %s to scheduler', new_job)
            self.opts['schedule'].update(data)

        # Fire the complete event back along with updated list of schedule
        evt = salt.utils.event.get_event('minion', opts=self.opts, listen=False)
        evt.fire_event({'complete': True,
                        'schedule': self._get_schedule()},
                       tag='/salt/minion/minion_schedule_add_complete')

        if persist:
            self.persist()

Response: Adds a new job to the scheduler.


Instruction:
Write a Python 3 script for
modifying a job in the scheduler. Ignores jobs from pillar

Response:
def modify_job(self, name, schedule, persist=True):
        '''
        Modify a job in the scheduler. Ignores jobs from pillar
        '''
        # ensure job exists, then replace it
        if name in self.opts['schedule']:
            self.delete_job(name, persist)
        elif name in self._get_schedule(include_opts=False):
            log.warning("Cannot modify job %s, it's in the pillar!", name)
            return

        self.opts['schedule'][name] = schedule

        if persist:
            self.persist()


Instruction:
Given the following Python 3 function, write the documentation
def run_job(self, name):
        '''
        Run a schedule job now
        '''
        data = self._get_schedule().get(name, {})

        if 'function' in data:
            func = data['function']
        elif 'func' in data:
            func = data['func']
        elif 'fun' in data:
            func = data['fun']
        else:
            func = None
        if not isinstance(func, list):
            func = [func]
        for _func in func:
            if _func not in self.functions:
                log.error(
                    'Invalid function: %s in scheduled job %s.',
                    _func, name
                )

        if 'name' not in data:
            data['name'] = name
        log.info('Running Job: %s', name)

        # Grab run, assume True
        run = data.get('run', True)
        if run:
            self._run_job(_func, data)

Response: Run a scheduled job now


Instruction:
Can you implement a function in Python 3 that
reloads the schedule from saved schedule file.

Response:
def reload(self, schedule):
        '''
        Reload the schedule from saved schedule file.
        '''
        # Remove all jobs from self.intervals
        self.intervals = {}

        if 'schedule' in schedule:
            schedule = schedule['schedule']
        self.opts.setdefault('schedule', {}).update(schedule)


Instruction:
Write a Python 3 script to
list the current schedule items

Response:
def list(self, where):
        '''
        List the current schedule items
        '''
        if where == 'pillar':
            schedule = self._get_schedule(include_opts=False)
        elif where == 'opts':
            schedule = self._get_schedule(include_pillar=False)
        else:
            schedule = self._get_schedule()

        # Fire the complete event back along with the list of schedule
        evt = salt.utils.event.get_event('minion', opts=self.opts, listen=False)
        evt.fire_event({'complete': True, 'schedule': schedule},
                       tag='/salt/minion/minion_schedule_list_complete')


Instruction:
Here you have a function in Python 3, explain what it does
def save_schedule(self):
        '''
        Save the current schedule
        '''
        self.persist()

        # Fire the complete event back along with the list of schedule
        evt = salt.utils.event.get_event('minion', opts=self.opts, listen=False)
        evt.fire_event({'complete': True},
                       tag='/salt/minion/minion_schedule_saved')

Response: Save the current schedule


Instruction:
Explain what the following Python 3 code does
def skip_job(self, name, data):
        '''
        Skip a job at a specific time in the scheduler.
        Ignores jobs from pillar
        '''
        time = data['time']
        time_fmt = data.get('time_fmt', '%Y-%m-%dT%H:%M:%S')

        # ensure job exists, then disable it
        if name in self.opts['schedule']:
            if 'skip_explicit' not in self.opts['schedule'][name]:
                self.opts['schedule'][name]['skip_explicit'] = []
            self.opts['schedule'][name]['skip_explicit'].append({'time': time,
                                                                 'time_fmt': time_fmt})

        elif name in self._get_schedule(include_opts=False):
            log.warning("Cannot modify job %s, it's in the pillar!", name)

        # Fire the complete event back along with updated list of schedule
        evt = salt.utils.event.get_event('minion', opts=self.opts, listen=False)
        evt.fire_event({'complete': True,
                        'schedule': self._get_schedule()},
                       tag='/salt/minion/minion_schedule_skip_job_complete')

Response: Skip a job at a specific time in the scheduler.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_next_fire_time(self, name, fmt='%Y-%m-%dT%H:%M:%S'):
        '''
        Return the next fire time for the specified job
        '''

        schedule = self._get_schedule()
        _next_fire_time = None
        if schedule:
            _next_fire_time = schedule.get(name, {}).get('_next_fire_time', None)
            if _next_fire_time:
                _next_fire_time = _next_fire_time.strftime(fmt)

        # Fire the complete event back along with updated list of schedule
        evt = salt.utils.event.get_event('minion', opts=self.opts, listen=False)
        evt.fire_event({'complete': True, 'next_fire_time': _next_fire_time},
                       tag='/salt/minion/minion_schedule_next_fire_time_complete')

Response: Return the next fire time for the specified job


Instruction:
Can you generate the documentation for the following Python 3 function
def handle_func(self, multiprocessing_enabled, func, data):
        '''
        Execute this method in a multiprocess or thread
        '''
        if salt.utils.platform.is_windows() \
                or self.opts.get('transport') == 'zeromq':
            # Since function references can't be pickled and pickling
            # is required when spawning new processes on Windows, regenerate
            # the functions and returners.
            # This also needed for ZeroMQ transport to reset all functions
            # context data that could keep paretns connections. ZeroMQ will
            # hang on polling parents connections from the child process.
            if self.opts['__role'] == 'master':
                self.functions = salt.loader.runner(self.opts, utils=self.utils)
            else:
                self.functions = salt.loader.minion_mods(self.opts, proxy=self.proxy, utils=self.utils)
            self.returners = salt.loader.returners(self.opts, self.functions, proxy=self.proxy)
        ret = {'id': self.opts.get('id', 'master'),
               'fun': func,
               'fun_args': [],
               'schedule': data['name'],
               'jid': salt.utils.jid.gen_jid(self.opts)}

        if 'metadata' in data:
            if isinstance(data['metadata'], dict):
                ret['metadata'] = data['metadata']
                ret['metadata']['_TOS'] = self.time_offset
                ret['metadata']['_TS'] = time.ctime()
                ret['metadata']['_TT'] = time.strftime('%Y %B %d %a %H %m', time.gmtime())
            else:
                log.warning('schedule: The metadata parameter must be '
                            'specified as a dictionary.  Ignoring.')

        if multiprocessing_enabled:
            # We just want to modify the process name if we're on a different process
            salt.utils.process.appendproctitle('{0} {1}'.format(self.__class__.__name__, ret['jid']))
        data_returner = data.get('returner', None)

        if not self.standalone:
            proc_fn = os.path.join(
                salt.minion.get_proc_dir(self.opts['cachedir']),
                ret['jid']
            )

        if multiprocessing_enabled and not salt.utils.platform.is_windows():
            # Reconfigure multiprocessing logging after daemonizing
            log_setup.setup_multiprocessing_logging()

        if multiprocessing_enabled:
            # Don't *BEFORE* to go into try to don't let it triple execute the finally section.
            salt.utils.process.daemonize_if(self.opts)

        # TODO: Make it readable! Splt to funcs, remove nested try-except-finally sections.
        try:

            minion_blackout_violation = False
            if self.opts.get('pillar', {}).get('minion_blackout', False):
                whitelist = self.opts.get('pillar', {}).get('minion_blackout_whitelist', [])
                # this minion is blacked out. Only allow saltutil.refresh_pillar and the whitelist
                if func != 'saltutil.refresh_pillar' and func not in whitelist:
                    minion_blackout_violation = True
            elif self.opts.get('grains', {}).get('minion_blackout', False):
                whitelist = self.opts.get('grains', {}).get('minion_blackout_whitelist', [])
                if func != 'saltutil.refresh_pillar' and func not in whitelist:
                    minion_blackout_violation = True
            if minion_blackout_violation:
                raise SaltInvocationError('Minion in blackout mode. Set \'minion_blackout\' '
                                          'to False in pillar or grains to resume operations. Only '
                                          'saltutil.refresh_pillar allowed in blackout mode.')

            ret['pid'] = os.getpid()

            if not self.standalone:
                if 'jid_include' not in data or data['jid_include']:
                    log.debug(
                        'schedule.handle_func: adding this job to the '
                        'jobcache with data %s', ret
                    )
                    # write this to /var/cache/salt/minion/proc
                    with salt.utils.files.fopen(proc_fn, 'w+b') as fp_:
                        fp_.write(salt.payload.Serial(self.opts).dumps(ret))

            args = tuple()
            if 'args' in data:
                args = data['args']
                ret['fun_args'].extend(data['args'])

            kwargs = {}
            if 'kwargs' in data:
                kwargs = data['kwargs']
                ret['fun_args'].append(copy.deepcopy(kwargs))

            if func not in self.functions:
                ret['return'] = self.functions.missing_fun_string(func)
                salt.utils.error.raise_error(
                    message=self.functions.missing_fun_string(func))

            # if the func support **kwargs, lets pack in the pub data we have
            # TODO: pack the *same* pub data as a minion?
            argspec = salt.utils.args.get_function_argspec(self.functions[func])
            if argspec.keywords:
                # this function accepts **kwargs, pack in the publish data
                for key, val in six.iteritems(ret):
                    if key is not 'kwargs':
                        kwargs['__pub_{0}'.format(key)] = copy.deepcopy(val)

            # Only include these when running runner modules
            if self.opts['__role'] == 'master':
                jid = salt.utils.jid.gen_jid(self.opts)
                tag = salt.utils.event.tagify(jid, prefix='salt/scheduler/')

                event = salt.utils.event.get_event(
                        self.opts['__role'],
                        self.opts['sock_dir'],
                        self.opts['transport'],
                        opts=self.opts,
                        listen=False)

                namespaced_event = salt.utils.event.NamespacedEvent(
                    event,
                    tag,
                    print_func=None
                )

                func_globals = {
                    '__jid__': jid,
                    '__user__': salt.utils.user.get_user(),
                    '__tag__': tag,
                    '__jid_event__': weakref.proxy(namespaced_event),
                }
                self_functions = copy.copy(self.functions)
                salt.utils.lazy.verify_fun(self_functions, func)

                # Inject some useful globals to *all* the function's global
                # namespace only once per module-- not per func
                completed_funcs = []

                for mod_name in six.iterkeys(self_functions):
                    if '.' not in mod_name:
                        continue
                    mod, _ = mod_name.split('.', 1)
                    if mod in completed_funcs:
                        continue
                    completed_funcs.append(mod)
                    for global_key, value in six.iteritems(func_globals):
                        self.functions[mod_name].__globals__[global_key] = value

            self.functions.pack['__context__']['retcode'] = 0

            ret['return'] = self.functions[func](*args, **kwargs)

            if not self.standalone:
                # runners do not provide retcode
                if 'retcode' in self.functions.pack['__context__']:
                    ret['retcode'] = self.functions.pack['__context__']['retcode']

                ret['success'] = True

                if data_returner or self.schedule_returner:
                    if 'return_config' in data:
                        ret['ret_config'] = data['return_config']
                    if 'return_kwargs' in data:
                        ret['ret_kwargs'] = data['return_kwargs']
                    rets = []
                    for returner in [data_returner, self.schedule_returner]:
                        if isinstance(returner, six.string_types):
                            rets.append(returner)
                        elif isinstance(returner, list):
                            rets.extend(returner)
                    # simple de-duplication with order retained
                    for returner in OrderedDict.fromkeys(rets):
                        ret_str = '{0}.returner'.format(returner)
                        if ret_str in self.returners:
                            self.returners[ret_str](ret)
                        else:
                            log.info(
                                'Job %s using invalid returner: %s. Ignoring.',
                                func, returner
                            )

        except Exception:
            log.exception('Unhandled exception running %s', ret['fun'])
            # Although catch-all exception handlers are bad, the exception here
            # is to let the exception bubble up to the top of the thread context,
            # where the thread will die silently, which is worse.
            if 'return' not in ret:
                ret['return'] = "Unhandled exception running {0}".format(ret['fun'])
            ret['success'] = False
            ret['retcode'] = 254
        finally:
            # Only attempt to return data to the master if the scheduled job is running
            # on a master itself or a minion.
            if '__role' in self.opts and self.opts['__role'] in ('master', 'minion'):
                # The 'return_job' option is enabled by default even if not set
                if 'return_job' in data and not data['return_job']:
                    pass
                else:
                    # Send back to master so the job is included in the job list
                    mret = ret.copy()
                    # No returners defined, so we're only sending back to the master
                    if not data_returner and not self.schedule_returner:
                        mret['jid'] = 'req'
                        if data.get('return_job') == 'nocache':
                            # overwrite 'req' to signal to master that
                            # this job shouldn't be stored
                            mret['jid'] = 'nocache'
                    load = {'cmd': '_return', 'id': self.opts['id']}
                    for key, value in six.iteritems(mret):
                        load[key] = value

                    if '__role' in self.opts and self.opts['__role'] == 'minion':
                        event = salt.utils.event.get_event('minion',
                                                           opts=self.opts,
                                                           listen=False)
                    elif '__role' in self.opts and self.opts['__role'] == 'master':
                        event = salt.utils.event.get_master_event(self.opts,
                                                                  self.opts['sock_dir'])
                    try:
                        event.fire_event(load, '__schedule_return')
                    except Exception as exc:
                        log.exception('Unhandled exception firing __schedule_return event')

            if not self.standalone:
                log.debug('schedule.handle_func: Removing %s', proc_fn)

                try:
                    os.unlink(proc_fn)
                except OSError as exc:
                    if exc.errno == errno.EEXIST or exc.errno == errno.ENOENT:
                        # EEXIST and ENOENT are OK because the file is gone and that's what
                        # we wanted
                        pass
                    else:
                        log.error("Failed to delete '%s': %s", proc_fn, exc.errno)
                        # Otherwise, failing to delete this file is not something
                        # we can cleanly handle.
                        raise
                finally:
                    if multiprocessing_enabled:
                        # Let's make sure we exit the process!
                        sys.exit(salt.defaults.exitcodes.EX_GENERIC)

Response: Execute this method in a multiprocess or thread.