Instruction:
Can you implement a function in Python 3 that
ensures that the named package is installed and that it is compatible with the version number specified.

Response:
def installed(
        name,
        version=None,
        refresh=None,
        fromrepo=None,
        skip_verify=False,
        skip_suggestions=False,
        pkgs=None,
        sources=None,
        allow_updates=False,
        pkg_verify=False,
        normalize=True,
        ignore_epoch=False,
        reinstall=False,
        update_holds=False,
        bypass_file=None,
        bypass_file_contains=None,
        **kwargs):
    '''
    Ensure that the package is installed, and that it is the correct version
    (if specified).

    :param str name:
        The name of the package to be installed. This parameter is ignored if
        either "pkgs" or "sources" is used. Additionally, please note that this
        option can only be used to install packages from a software repository.
        To install a package file manually, use the "sources" option detailed
        below.

    :param str version:
        Install a specific version of a package. This option is ignored if
        "sources" is used. Currently, this option is supported
        for the following pkg providers: :mod:`apt <salt.modules.aptpkg>`,
        :mod:`ebuild <salt.modules.ebuild>`,
        :mod:`pacman <salt.modules.pacman>`,
        :mod:`pkgin <salt.modules.pkgin>`,
        :mod:`win_pkg <salt.modules.win_pkg>`,
        :mod:`yumpkg <salt.modules.yumpkg>`, and
        :mod:`zypper <salt.modules.zypper>`. The version number includes the
        release designation where applicable, to allow Salt to target a
        specific release of a given version. When in doubt, using the
        ``pkg.latest_version`` function for an uninstalled package will tell
        you the version available.

        .. code-block:: bash

            # salt myminion pkg.latest_version vim-enhanced
            myminion:
                2:7.4.160-1.el7

        .. important::
            As of version 2015.8.7, for distros which use yum/dnf, packages
            which have a version with a nonzero epoch (that is, versions which
            start with a number followed by a colon like in the
            ``pkg.latest_version`` output above) must have the epoch included
            when specifying the version number. For example:

            .. code-block:: yaml

                vim-enhanced:
                  pkg.installed:
                    - version: 2:7.4.160-1.el7

            In version 2015.8.9, an **ignore_epoch** argument has been added to
            :py:mod:`pkg.installed <salt.states.pkg.installed>`,
            :py:mod:`pkg.removed <salt.states.pkg.removed>`, and
            :py:mod:`pkg.purged <salt.states.pkg.purged>` states, which
            causes the epoch to be disregarded when the state checks to see if
            the desired version was installed.

        Also, while this function is not yet implemented for all pkg frontends,
        :mod:`pkg.list_repo_pkgs <salt.modules.yumpkg.list_repo_pkgs>` will
        show all versions available in the various repositories for a given
        package, irrespective of whether or not it is installed.

        .. code-block:: bash

            # salt myminion pkg.list_repo_pkgs bash
            myminion:
            ----------
                bash:
                    - 4.2.46-21.el7_3
                    - 4.2.46-20.el7_2

        This function was first added for :mod:`pkg.list_repo_pkgs
        <salt.modules.yumpkg.list_repo_pkgs>` in 2014.1.0, and was expanded to
        :py:func:`Debian/Ubuntu <salt.modules.aptpkg.list_repo_pkgs>` and
        :py:func:`Arch Linux <salt.modules.pacman.list_repo_pkgs>`-based
        distros in the 2017.7.0 release.

        The version strings returned by either of these functions can be used
        as version specifiers in pkg states.

        You can install a specific version when using the ``pkgs`` argument by
        including the version after the package:

        .. code-block:: yaml

            common_packages:
              pkg.installed:
                - pkgs:
                  - unzip
                  - dos2unix
                  - salt-minion: 2015.8.5-1.el6

        If the version given is the string ``latest``, the latest available
        package version will be installed à la ``pkg.latest``.

        **WILDCARD VERSIONS**

        As of the 2017.7.0 release, this state now supports wildcards in
        package versions for SUSE SLES/Leap/Tumbleweed, Debian/Ubuntu,
        RHEL/CentOS, Arch Linux, and their derivatives. Using wildcards can be
        useful for packages where the release name is built into the version in
        some way, such as for RHEL/CentOS which typically has version numbers
        like ``1.2.34-5.el7``. An example of the usage for this would be:

        .. code-block:: yaml

            mypkg:
              pkg.installed:
                - version: '1.2.34*'

        Keep in mind that using wildcard versions will result in a slower state
        run since Salt must gather the available versions of the specified
        packages and figure out which of them match the specified wildcard
        expression.

    :param bool refresh:
        This parameter controls whether or not the package repo database is
        updated prior to installing the requested package(s).

        If ``True``, the package database will be refreshed (``apt-get
        update`` or equivalent, depending on platform) before installing.

        If ``False``, the package database will *not* be refreshed before
        installing.

        If unset, then Salt treats package database refreshes differently
        depending on whether or not a ``pkg`` state has been executed already
        during the current Salt run. Once a refresh has been performed in a
        ``pkg`` state, for the remainder of that Salt run no other refreshes
        will be performed for ``pkg`` states which do not explicitly set
        ``refresh`` to ``True``. This prevents needless additional refreshes
        from slowing down the Salt run.

    :param str cache_valid_time:

        .. versionadded:: 2016.11.0

        This parameter sets the value in seconds after which the cache is
        marked as invalid, and a cache update is necessary. This overwrites
        the ``refresh`` parameter's default behavior.

        Example:

        .. code-block:: yaml

            httpd:
              pkg.installed:
                - fromrepo: mycustomrepo
                - skip_verify: True
                - skip_suggestions: True
                - version: 2.0.6~ubuntu3
                - refresh: True
                - cache_valid_time: 300
                - allow_updates: True
                - hold: False

        In this case, a refresh will not take place for 5 minutes since the last
        ``apt-get update`` was executed on the system.

        .. note::

            This parameter is available only on Debian based distributions and
            has no effect on the rest.

    :param str fromrepo:
        Specify a repository from which to install

        .. note::

            Distros which use APT (Debian, Ubuntu, etc.) do not have a concept
            of repositories, in the same way as YUM-based distros do. When a
            source is added, it is assigned to a given release. Consider the
            following source configuration:

            .. code-block:: text

                deb http://ppa.launchpad.net/saltstack/salt/ubuntu precise main

            The packages provided by this source would be made available via
            the ``precise`` release, therefore ``fromrepo`` would need to be
            set to ``precise`` for Salt to install the package from this
            source.

            Having multiple sources in the same release may result in the
            default install candidate being newer than what is desired. If this
            is the case, the desired version must be specified using the
            ``version`` parameter.

            If the ``pkgs`` parameter is being used to install multiple
            packages in the same state, then instead of using ``version``,
            use the method of version specification described in the **Multiple
            Package Installation Options** section below.

            Running the shell command ``apt-cache policy pkgname`` on a minion
            can help elucidate the APT configuration and aid in properly
            configuring states:

            .. code-block:: bash

                root@saltmaster:~# salt ubuntu01 cmd.run 'apt-cache policy ffmpeg'
                ubuntu01:
                    ffmpeg:
                    Installed: (none)
                    Candidate: 7:0.10.11-1~precise1
                    Version table:
                        7:0.10.11-1~precise1 0
                            500 http://ppa.launchpad.net/jon-severinsson/ffmpeg/ubuntu/ precise/main amd64 Packages
                        4:0.8.10-0ubuntu0.12.04.1 0
                            500 http://us.archive.ubuntu.com/ubuntu/ precise-updates/main amd64 Packages
                            500 http://security.ubuntu.com/ubuntu/ precise-security/main amd64 Packages
                        4:0.8.1-0ubuntu1 0
                            500 http://us.archive.ubuntu.com/ubuntu/ precise/main amd64 Packages

            The release is located directly after the source's URL. The actual
            release name is the part before the slash, so to install version
            **4:0.8.10-0ubuntu0.12.04.1** either ``precise-updates`` or
            ``precise-security`` could be used for the ``fromrepo`` value.

    :param bool skip_verify:
        Skip the GPG verification check for the package to be installed

    :param bool skip_suggestions:
        Force strict package naming. Disables lookup of package alternatives.

        .. versionadded:: 2014.1.1

    :param bool resolve_capabilities:
        Turn on resolving capabilities. This allow one to name "provides" or alias names for packages.

        .. versionadded:: 2018.3.0

    :param bool allow_updates:
        Allow the package to be updated outside Salt's control (e.g. auto
        updates on Windows). This means a package on the Minion can have a
        newer version than the latest available in the repository without
        enforcing a re-installation of the package.

        .. versionadded:: 2014.7.0

        Example:

        .. code-block:: yaml

            httpd:
              pkg.installed:
                - fromrepo: mycustomrepo
                - skip_verify: True
                - skip_suggestions: True
                - version: 2.0.6~ubuntu3
                - refresh: True
                - allow_updates: True
                - hold: False

    :param bool pkg_verify:

        .. versionadded:: 2014.7.0

        For requested packages that are already installed and would not be
        targeted for upgrade or downgrade, use pkg.verify to determine if any
        of the files installed by the package have been altered. If files have
        been altered, the reinstall option of pkg.install is used to force a
        reinstall. Types to ignore can be passed to pkg.verify. Additionally,
        ``verify_options`` can be used to modify further the behavior of
        pkg.verify. See examples below.  Currently, this option is supported
        for the following pkg providers: :mod:`yumpkg <salt.modules.yumpkg>`.

        Examples:

        .. code-block:: yaml

            httpd:
              pkg.installed:
                - version: 2.2.15-30.el6.centos
                - pkg_verify: True

        .. code-block:: yaml

            mypkgs:
              pkg.installed:
                - pkgs:
                  - foo
                  - bar: 1.2.3-4
                  - baz
                - pkg_verify:
                  - ignore_types:
                    - config
                    - doc

        .. code-block:: yaml

            mypkgs:
              pkg.installed:
                - pkgs:
                  - foo
                  - bar: 1.2.3-4
                  - baz
                - pkg_verify:
                  - ignore_types:
                    - config
                    - doc
                  - verify_options:
                    - nodeps
                    - nofiledigest

    :param list ignore_types:
        List of types to ignore when verifying the package

        .. versionadded:: 2014.7.0

    :param list verify_options:
        List of additional options to pass when verifying the package. These
        options will be added to the ``rpm -V`` command, prepended with ``--``
        (for example, when ``nodeps`` is passed in this option, ``rpm -V`` will
        be run with ``--nodeps``).

        .. versionadded:: 2016.11.0

    :param bool normalize:
        Normalize the package name by removing the architecture, if the
        architecture of the package is different from the architecture of the
        operating system. The ability to disable this behavior is useful for
        poorly-created packages which include the architecture as an actual
        part of the name, such as kernel modules which match a specific kernel
        version.

        .. versionadded:: 2014.7.0

        Example:

        .. code-block:: yaml

            gpfs.gplbin-2.6.32-279.31.1.el6.x86_64:
              pkg.installed:
                - normalize: False

    :param bool ignore_epoch:
        When a package version contains an non-zero epoch (e.g.
        ``1:3.14.159-2.el7``, and a specific version of a package is desired,
        set this option to ``True`` to ignore the epoch when comparing
        versions. This allows for the following SLS to be used:

        .. code-block:: yaml

            # Actual vim-enhanced version: 2:7.4.160-1.el7
            vim-enhanced:
              pkg.installed:
                - version: 7.4.160-1.el7
                - ignore_epoch: True

        Without this option set to ``True`` in the above example, the package
        would be installed, but the state would report as failed because the
        actual installed version would be ``2:7.4.160-1.el7``. Alternatively,
        this option can be left as ``False`` and the full version string (with
        epoch) can be specified in the SLS file:

        .. code-block:: yaml

            vim-enhanced:
              pkg.installed:
                - version: 2:7.4.160-1.el7

        .. versionadded:: 2015.8.9

    |

    **MULTIPLE PACKAGE INSTALLATION OPTIONS: (not supported in pkgng)**

    :param list pkgs:
        A list of packages to install from a software repository. All packages
        listed under ``pkgs`` will be installed via a single command.

        .. code-block:: yaml

            mypkgs:
              pkg.installed:
                - pkgs:
                  - foo
                  - bar
                  - baz
                - hold: True

        ``NOTE:`` For :mod:`apt <salt.modules.aptpkg>`,
        :mod:`ebuild <salt.modules.ebuild>`,
        :mod:`pacman <salt.modules.pacman>`,
        :mod:`winrepo <salt.modules.win_pkg>`,
        :mod:`yumpkg <salt.modules.yumpkg>`, and
        :mod:`zypper <salt.modules.zypper>`,
        version numbers can be specified
        in the ``pkgs`` argument. For example:

        .. code-block:: yaml

            mypkgs:
              pkg.installed:
                - pkgs:
                  - foo
                  - bar: 1.2.3-4
                  - baz

        Additionally, :mod:`ebuild <salt.modules.ebuild>`, :mod:`pacman
        <salt.modules.pacman>`, :mod:`zypper <salt.modules.zypper>`,
        :mod:`yum/dnf <salt.modules.yumpkg>`, and :mod:`apt
        <salt.modules.aptpkg>` support the ``<``, ``<=``, ``>=``, and ``>``
        operators for more control over what versions will be installed. For
        example:

        .. code-block:: yaml

            mypkgs:
              pkg.installed:
                - pkgs:
                  - foo
                  - bar: '>=1.2.3-4'
                  - baz

        ``NOTE:`` When using comparison operators, the expression must be enclosed
        in quotes to avoid a YAML render error.

        With :mod:`ebuild <salt.modules.ebuild>` is also possible to specify a
        use flag list and/or if the given packages should be in
        package.accept_keywords file and/or the overlay from which you want the
        package to be installed. For example:

        .. code-block:: yaml

            mypkgs:
              pkg.installed:
                - pkgs:
                  - foo: '~'
                  - bar: '~>=1.2:slot::overlay[use,-otheruse]'
                  - baz

    :param list sources:
        A list of packages to install, along with the source URI or local path
        from which to install each package. In the example below, ``foo``,
        ``bar``, ``baz``, etc. refer to the name of the package, as it would
        appear in the output of the ``pkg.version`` or ``pkg.list_pkgs`` salt
        CLI commands.

        .. code-block:: yaml

            mypkgs:
              pkg.installed:
                - sources:
                  - foo: salt://rpms/foo.rpm
                  - bar: http://somesite.org/bar.rpm
                  - baz: ftp://someothersite.org/baz.rpm
                  - qux: /minion/path/to/qux.rpm

    **PLATFORM-SPECIFIC ARGUMENTS**

    These are specific to each OS. If it does not apply to the execution
    module for your OS, it is ignored.

    :param bool hold:
        Force the package to be held at the current installed version.
        Currently works with YUM/DNF & APT based systems.

        .. versionadded:: 2014.7.0

    :param bool update_holds:
        If ``True``, and this function would update the package version, any
        packages which are being held will be temporarily unheld so that they
        can be updated. Otherwise, if this function attempts to update a held
        package, the held package(s) will be skipped and the state will fail.
        By default, this parameter is set to ``False``.

        Currently works with YUM/DNF & APT based systems.

        .. versionadded:: 2016.11.0

    :param list names:
        A list of packages to install from a software repository. Each package
        will be installed individually by the package manager.

        .. warning::

            Unlike ``pkgs``, the ``names`` parameter cannot specify a version.
            In addition, it makes a separate call to the package management
            frontend to install each package, whereas ``pkgs`` makes just a
            single call. It is therefore recommended to use ``pkgs`` instead of
            ``names`` to install multiple packages, both for the additional
            features and the performance improvement that it brings.

    :param bool install_recommends:
        Whether to install the packages marked as recommended. Default is
        ``True``. Currently only works with APT-based systems.

        .. versionadded:: 2015.5.0

        .. code-block:: yaml

            httpd:
              pkg.installed:
                - install_recommends: False

    :param bool only_upgrade:
        Only upgrade the packages, if they are already installed. Default is
        ``False``. Currently only works with APT-based systems.

        .. versionadded:: 2015.5.0

        .. code-block:: yaml

            httpd:
              pkg.installed:
                - only_upgrade: True

        .. note::
            If this parameter is set to True and the package is not already
            installed, the state will fail.

    :param bool report_reboot_exit_codes:
       If the installer exits with a recognized exit code indicating that
       a reboot is required, the module function

           *win_system.set_reboot_required_witnessed*

       will be called, preserving the knowledge of this event
       for the remainder of the current boot session. For the time being,
       ``3010`` is the only recognized exit code,
       but this is subject to future refinement.
       The value of this param
       defaults to ``True``. This parameter has no effect
       on non-Windows systems.

       .. versionadded:: 2016.11.0

       .. code-block:: yaml

           ms vcpp installed:
             pkg.installed:
               - name: ms-vcpp
               - version: 10.0.40219
               - report_reboot_exit_codes: False

    :param str bypass_file:
       If you wish to bypass the full package validation process, you can
       specify a file related to the installed pacakge as a way to
       validate the pacakge has already been installed. A good example
       would be a config file that is deployed with the package. Another
       bypass_file could be ``/run/salt-minon.pid``.

       .. code-block:: yaml

           install_ntp:
             pkg.installed:
               - name: ntp
               - bypass_file: /etc/ntp.conf

       The use case for this feature is when running salt at significant scale.
       Each state that has a requisite for a ``pkg.installed`` will have salt
       querying the package manager of the system. Compared to simple diff
       checks, querying the pacakge manager is a lengthy process. This feature
       is an attempt to reduce the run time of states. If only a config change
       is being made but you wish to keep all of the self resolving requisites
       this bypasses the lenghty cost of the package manager. The assumption is
       that if this file is present, the package should already be installed.

    :param str bypass_file_contains:
       This option can only be used in conjunction with the ``bypass_file``
       option. It is to provide a second layer of validation before bypassing
       the ``pkg.installed`` process.

       .. code-block:: yaml

           install_ntp:
             pkg.installed:
               - name: ntp
               - bypass_file: /etc/ntp.conf
               - bypass_file_contains: version-20181218

       The will have salt check to see if the file contains the specified
       string. If the value is found, the ``pkg.installed`` process will be
       bypassed under the assumption that two pieces of validation have passed
       and the package is already installed.

       .. warning::

           Do not try and use ``{{ salt['pkg.version']('ntp') }}`` in a jinja
           template as part of your bypass_file_contains match. This will
           trigger a ``pkg.version`` lookup with the pacakge manager and negate
           any time saved by trying to use the bypass feature.

    :return:
        A dictionary containing the state of the software installation
    :rtype dict:

    .. note::

        The ``pkg.installed`` state supports the usage of ``reload_modules``.
        This functionality allows you to force Salt to reload all modules. In
        many cases, Salt is clever enough to transparently reload the modules.
        For example, if you install a package, Salt reloads modules because some
        other module or state might require the package which was installed.
        However, there are some edge cases where this may not be the case, which
        is what ``reload_modules`` is meant to resolve.

        You should only use ``reload_modules`` if your ``pkg.installed`` does some
        sort of installation where if you do not reload the modules future items
        in your state which rely on the software being installed will fail. Please
        see the :ref:`Reloading Modules <reloading-modules>` documentation for more
        information.

    '''
    if not pkgs and isinstance(pkgs, list):
        return {'name': name,
                'changes': {},
                'result': True,
                'comment': 'No packages to install provided'}

    # If just a name (and optionally a version) is passed, just pack them into
    # the pkgs argument.
    if name and not any((pkgs, sources)):
        if version:
            pkgs = [{name: version}]
            version = None
        else:
            pkgs = [name]

    kwargs['saltenv'] = __env__
    refresh = salt.utils.pkg.check_refresh(__opts__, refresh)

    if bypass_file is not None and bypass_file_contains is not None:
        if os.path.isfile(bypass_file):
            with salt.utils.fopen(bypass_file) as bypass_file_open:
                if bypass_file_contains in bypass_file_open.read():
                    return {'name': name,
                            'changes': {},
                            'result': True,
                            'comment': 'pkg.installed was bypassed as {} was present in {}'.format(bypass_file_contains, bypass_file)}
    if bypass_file is not None and bypass_file_contains is None:
        if os.path.isfile(bypass_file):
            return {'name': name,
                    'changes': {},
                    'result': True,
                    'comment': 'pkg.installed was bypassed as bypass_file {} was present'.format(bypass_file)}

    # check if capabilities should be checked and modify the requested packages
    # accordingly.
    if pkgs:
        pkgs, refresh = _resolve_capabilities(pkgs, refresh=refresh, **kwargs)

    if not isinstance(pkg_verify, list):
        pkg_verify = pkg_verify is True
    if (pkg_verify or isinstance(pkg_verify, list)) \
            and 'pkg.verify' not in __salt__:
        return {'name': name,
                'changes': {},
                'result': False,
                'comment': 'pkg.verify not implemented'}

    if not isinstance(version, six.string_types) and version is not None:
        version = six.text_type(version)

    kwargs['allow_updates'] = allow_updates

    result = _find_install_targets(name, version, pkgs, sources,
                                   fromrepo=fromrepo,
                                   skip_suggestions=skip_suggestions,
                                   pkg_verify=pkg_verify,
                                   normalize=normalize,
                                   ignore_epoch=ignore_epoch,
                                   reinstall=reinstall,
                                   refresh=refresh,
                                   **kwargs)

    try:
        (desired, targets, to_unpurge, to_reinstall,
         altered_files, warnings, was_refreshed) = result
        if was_refreshed:
            refresh = False
    except ValueError:
        # _find_install_targets() found no targets or encountered an error

        # check that the hold function is available
        if 'pkg.hold' in __salt__ and 'hold' in kwargs:
            try:
                action = 'pkg.hold' if kwargs['hold'] else 'pkg.unhold'
                hold_ret = __salt__[action](
                    name=name, pkgs=pkgs, sources=sources
                )
            except (CommandExecutionError, SaltInvocationError) as exc:
                return {'name': name,
                        'changes': {},
                        'result': False,
                        'comment': six.text_type(exc)}

            if 'result' in hold_ret and not hold_ret['result']:
                return {'name': name,
                        'changes': {},
                        'result': False,
                        'comment': 'An error was encountered while '
                                   'holding/unholding package(s): {0}'
                                   .format(hold_ret['comment'])}
            else:
                modified_hold = [hold_ret[x] for x in hold_ret
                                 if hold_ret[x]['changes']]
                not_modified_hold = [hold_ret[x] for x in hold_ret
                                     if not hold_ret[x]['changes']
                                     and hold_ret[x]['result']]
                failed_hold = [hold_ret[x] for x in hold_ret
                               if not hold_ret[x]['result']]

                for i in modified_hold:
                    result['comment'] += '.\n{0}'.format(i['comment'])
                    result['result'] = i['result']
                    result['changes'][i['name']] = i['changes']

                for i in not_modified_hold:
                    result['comment'] += '.\n{0}'.format(i['comment'])
                    result['result'] = i['result']

                for i in failed_hold:
                    result['comment'] += '.\n{0}'.format(i['comment'])
                    result['result'] = i['result']
        return result

    if to_unpurge and 'lowpkg.unpurge' not in __salt__:
        ret = {'name': name,
               'changes': {},
               'result': False,
               'comment': 'lowpkg.unpurge not implemented'}
        if warnings:
            ret.setdefault('warnings', []).extend(warnings)
        return ret

    # Remove any targets not returned by _find_install_targets
    if pkgs:
        pkgs = [dict([(x, y)]) for x, y in six.iteritems(targets)]
        pkgs.extend([dict([(x, y)]) for x, y in six.iteritems(to_reinstall)])
    elif sources:
        oldsources = sources
        sources = [x for x in oldsources
                   if next(iter(list(x.keys()))) in targets]
        sources.extend([x for x in oldsources
                        if next(iter(list(x.keys()))) in to_reinstall])

    comment = []
    if __opts__['test']:
        if targets:
            if sources:
                summary = ', '.join(targets)
            else:
                summary = ', '.join([_get_desired_pkg(x, targets)
                                     for x in targets])
            comment.append('The following packages would be '
                           'installed/updated: {0}'.format(summary))
        if to_unpurge:
            comment.append(
                'The following packages would have their selection status '
                'changed from \'purge\' to \'install\': {0}'
                .format(', '.join(to_unpurge))
            )
        if to_reinstall:
            # Add a comment for each package in to_reinstall with its
            # pkg.verify output
            if reinstall:
                reinstall_targets = []
                for reinstall_pkg in to_reinstall:
                    if sources:
                        reinstall_targets.append(reinstall_pkg)
                    else:
                        reinstall_targets.append(
                            _get_desired_pkg(reinstall_pkg, to_reinstall)
                        )
                msg = 'The following packages would be reinstalled: '
                msg += ', '.join(reinstall_targets)
                comment.append(msg)
            else:
                for reinstall_pkg in to_reinstall:
                    if sources:
                        pkgstr = reinstall_pkg
                    else:
                        pkgstr = _get_desired_pkg(reinstall_pkg, to_reinstall)
                    comment.append(
                        'Package \'{0}\' would be reinstalled because the '
                        'following files have been altered:'.format(pkgstr)
                    )
                    comment.append(
                        _nested_output(altered_files[reinstall_pkg])
                    )
        ret = {'name': name,
               'changes': {},
               'result': None,
               'comment': '\n'.join(comment)}
        if warnings:
            ret.setdefault('warnings', []).extend(warnings)
        return ret

    changes = {'installed': {}}
    modified_hold = None
    not_modified_hold = None
    failed_hold = None
    if targets or to_reinstall:
        try:
            pkg_ret = __salt__['pkg.install'](name=None,
                                              refresh=refresh,
                                              version=version,
                                              fromrepo=fromrepo,
                                              skip_verify=skip_verify,
                                              pkgs=pkgs,
                                              sources=sources,
                                              reinstall=bool(to_reinstall),
                                              normalize=normalize,
                                              update_holds=update_holds,
                                              ignore_epoch=ignore_epoch,
                                              **kwargs)
        except CommandExecutionError as exc:
            ret = {'name': name, 'result': False}
            if exc.info:
                # Get information for state return from the exception.
                ret['changes'] = exc.info.get('changes', {})
                ret['comment'] = exc.strerror_without_changes
            else:
                ret['changes'] = {}
                ret['comment'] = ('An error was encountered while installing '
                                  'package(s): {0}'.format(exc))
            if warnings:
                ret.setdefault('warnings', []).extend(warnings)
            return ret

        if refresh:
            refresh = False

        if isinstance(pkg_ret, dict):
            changes['installed'].update(pkg_ret)
        elif isinstance(pkg_ret, six.string_types):
            comment.append(pkg_ret)
            # Code below will be looking for a dictionary. If this is a string
            # it means that there was an exception raised and that no packages
            # changed, so now that we have added this error to the comments we
            # set this to an empty dictionary so that the code below which
            # checks reinstall targets works.
            pkg_ret = {}

    if 'pkg.hold' in __salt__ and 'hold' in kwargs:
        try:
            action = 'pkg.hold' if kwargs['hold'] else 'pkg.unhold'
            hold_ret = __salt__[action](
                name=name, pkgs=desired
            )
        except (CommandExecutionError, SaltInvocationError) as exc:
            comment.append(six.text_type(exc))
            ret = {'name': name,
                   'changes': changes,
                   'result': False,
                   'comment': '\n'.join(comment)}
            if warnings:
                ret.setdefault('warnings', []).extend(warnings)
            return ret
        else:
            if 'result' in hold_ret and not hold_ret['result']:
                ret = {'name': name,
                       'changes': {},
                       'result': False,
                       'comment': 'An error was encountered while '
                                  'holding/unholding package(s): {0}'
                                  .format(hold_ret['comment'])}
                if warnings:
                    ret.setdefault('warnings', []).extend(warnings)
                return ret
            else:
                modified_hold = [hold_ret[x] for x in hold_ret
                                 if hold_ret[x]['changes']]
                not_modified_hold = [hold_ret[x] for x in hold_ret
                                     if not hold_ret[x]['changes']
                                     and hold_ret[x]['result']]
                failed_hold = [hold_ret[x] for x in hold_ret
                               if not hold_ret[x]['result']]

    if to_unpurge:
        changes['purge_desired'] = __salt__['lowpkg.unpurge'](*to_unpurge)

    # Analyze pkg.install results for packages in targets
    if sources:
        modified = [x for x in changes['installed'] if x in targets]
        not_modified = [x for x in desired
                        if x not in targets
                        and x not in to_reinstall]
        failed = [x for x in targets if x not in modified]
    else:
        if __grains__['os'] == 'FreeBSD':
            kwargs['with_origin'] = True
        new_pkgs = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs)
        if kwargs.get('resolve_capabilities', False) and 'pkg.list_provides' in __salt__:
            new_caps = __salt__['pkg.list_provides'](**kwargs)
        else:
            new_caps = {}
        ok, failed = _verify_install(desired, new_pkgs,
                                     ignore_epoch=ignore_epoch,
                                     new_caps=new_caps)
        modified = [x for x in ok if x in targets]
        not_modified = [x for x in ok
                        if x not in targets
                        and x not in to_reinstall]
        failed = [x for x in failed if x in targets]

    # If there was nothing unpurged, just set the changes dict to the contents
    # of changes['installed'].
    if not changes.get('purge_desired'):
        changes = changes['installed']

    if modified:
        if sources:
            summary = ', '.join(modified)
        else:
            summary = ', '.join([_get_desired_pkg(x, desired)
                                 for x in modified])
        if len(summary) < 20:
            comment.append('The following packages were installed/updated: '
                           '{0}'.format(summary))
        else:
            comment.append(
                '{0} targeted package{1} {2} installed/updated.'.format(
                    len(modified),
                    's' if len(modified) > 1 else '',
                    'were' if len(modified) > 1 else 'was'
                )
            )

    if modified_hold:
        for i in modified_hold:
            change_name = i['name']
            if change_name in changes:
                comment.append(i['comment'])
                if changes[change_name]['new']:
                    changes[change_name]['new'] += '\n'
                changes[change_name]['new'] += '{0}'.format(i['changes']['new'])
                if changes[change_name]['old']:
                    changes[change_name]['old'] += '\n'
                changes[change_name]['old'] += '{0}'.format(i['changes']['old'])
            else:
                comment.append(i['comment'])
                changes[change_name] = {}
                changes[change_name]['new'] = '{0}'.format(i['changes']['new'])

    # Any requested packages that were not targeted for install or reinstall
    if not_modified:
        if sources:
            summary = ', '.join(not_modified)
        else:
            summary = ', '.join([_get_desired_pkg(x, desired)
                                 for x in not_modified])
        if len(not_modified) <= 20:
            comment.append('The following packages were already installed: '
                           '{0}'.format(summary))
        else:
            comment.append(
                '{0} targeted package{1} {2} already installed'.format(
                    len(not_modified),
                    's' if len(not_modified) > 1 else '',
                    'were' if len(not_modified) > 1 else 'was'
                )
            )

    if not_modified_hold:
        for i in not_modified_hold:
            comment.append(i['comment'])

    result = True

    if failed:
        if sources:
            summary = ', '.join(failed)
        else:
            summary = ', '.join([_get_desired_pkg(x, desired)
                                 for x in failed])
        comment.insert(0, 'The following packages failed to '
                          'install/update: {0}'.format(summary))
        result = False

    if failed_hold:
        for i in failed_hold:
            comment.append(i['comment'])
        result = False

    # Get the ignore_types list if any from the pkg_verify argument
    if isinstance(pkg_verify, list) \
            and any(x.get('ignore_types') is not None
                    for x in pkg_verify
                    if isinstance(x, _OrderedDict)
                    and 'ignore_types' in x):
        ignore_types = next(x.get('ignore_types')
                            for x in pkg_verify
                            if 'ignore_types' in x)
    else:
        ignore_types = []

    # Get the verify_options list if any from the pkg_verify argument
    if isinstance(pkg_verify, list) \
            and any(x.get('verify_options') is not None
                    for x in pkg_verify
                    if isinstance(x, _OrderedDict)
                    and 'verify_options' in x):
        verify_options = next(x.get('verify_options')
                            for x in pkg_verify
                            if 'verify_options' in x)
    else:
        verify_options = []

    # Rerun pkg.verify for packages in to_reinstall to determine failed
    modified = []
    failed = []
    for reinstall_pkg in to_reinstall:
        if reinstall:
            if reinstall_pkg in pkg_ret:
                modified.append(reinstall_pkg)
            else:
                failed.append(reinstall_pkg)
        elif pkg_verify:
            # No need to wrap this in a try/except because we would already
            # have caught invalid arguments earlier.
            verify_result = __salt__['pkg.verify'](reinstall_pkg,
                                                   ignore_types=ignore_types,
                                                   verify_options=verify_options,
                                                   **kwargs)
            if verify_result:
                failed.append(reinstall_pkg)
                altered_files[reinstall_pkg] = verify_result
            else:
                modified.append(reinstall_pkg)

    if modified:
        # Add a comment for each package in modified with its pkg.verify output
        for modified_pkg in modified:
            if sources:
                pkgstr = modified_pkg
            else:
                pkgstr = _get_desired_pkg(modified_pkg, desired)
            msg = 'Package {0} was reinstalled.'.format(pkgstr)
            if modified_pkg in altered_files:
                msg += ' The following files were remediated:'
                comment.append(msg)
                comment.append(_nested_output(altered_files[modified_pkg]))
            else:
                comment.append(msg)

    if failed:
        # Add a comment for each package in failed with its pkg.verify output
        for failed_pkg in failed:
            if sources:
                pkgstr = failed_pkg
            else:
                pkgstr = _get_desired_pkg(failed_pkg, desired)
            msg = ('Reinstall was not successful for package {0}.'
                   .format(pkgstr))
            if failed_pkg in altered_files:
                msg += ' The following files could not be remediated:'
                comment.append(msg)
                comment.append(_nested_output(altered_files[failed_pkg]))
            else:
                comment.append(msg)
        result = False

    ret = {'name': name,
           'changes': changes,
           'result': result,
           'comment': '\n'.join(comment)}
    if warnings:
        ret.setdefault('warnings', []).extend(warnings)
    return ret


Instruction:
Here you have a function in Python 3, explain what it does
def downloaded(name,
               version=None,
               pkgs=None,
               fromrepo=None,
               ignore_epoch=None,
               **kwargs):
    '''
    .. versionadded:: 2017.7.0

    Ensure that the package is downloaded, and that it is the correct version
    (if specified).

    Currently supported for the following pkg providers:
    :mod:`yumpkg <salt.modules.yumpkg>` and :mod:`zypper <salt.modules.zypper>`

    :param str name:
        The name of the package to be downloaded. This parameter is ignored if
        either "pkgs" is used. Additionally, please note that this option can
        only be used to download packages from a software repository.

    :param str version:
        Download a specific version of a package.

        .. important::
            As of version 2015.8.7, for distros which use yum/dnf, packages
            which have a version with a nonzero epoch (that is, versions which
            start with a number followed by a colon must have the epoch included
            when specifying the version number. For example:

            .. code-block:: yaml

                vim-enhanced:
                  pkg.downloaded:
                    - version: 2:7.4.160-1.el7

            An **ignore_epoch** argument has been added to which causes the
            epoch to be disregarded when the state checks to see if the desired
            version was installed.

            You can install a specific version when using the ``pkgs`` argument by
            including the version after the package:

            .. code-block:: yaml

                common_packages:
                  pkg.downloaded:
                    - pkgs:
                      - unzip
                      - dos2unix
                      - salt-minion: 2015.8.5-1.el6

    :param bool resolve_capabilities:
        Turn on resolving capabilities. This allow one to name "provides" or alias names for packages.

        .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: yaml

        zsh:
          pkg.downloaded:
            - version: 5.0.5-4.63
            - fromrepo: "myrepository"
    '''
    ret = {'name': name,
           'changes': {},
           'result': None,
           'comment': ''}

    if 'pkg.list_downloaded' not in __salt__:
        ret['result'] = False
        ret['comment'] = 'The pkg.downloaded state is not available on ' \
                         'this platform'
        return ret

    if not pkgs and isinstance(pkgs, list):
        ret['result'] = True
        ret['comment'] = 'No packages to download provided'
        return ret

    # If just a name (and optionally a version) is passed, just pack them into
    # the pkgs argument.
    if name and not pkgs:
        if version:
            pkgs = [{name: version}]
            version = None
        else:
            pkgs = [name]

    # It doesn't make sense here to received 'downloadonly' as kwargs
    # as we're explicitly passing 'downloadonly=True' to execution module.
    if 'downloadonly' in kwargs:
        del kwargs['downloadonly']

    pkgs, _refresh = _resolve_capabilities(pkgs, **kwargs)

    # Only downloading not yet downloaded packages
    targets = _find_download_targets(name,
                                     version,
                                     pkgs,
                                     fromrepo=fromrepo,
                                     ignore_epoch=ignore_epoch,
                                     **kwargs)
    if isinstance(targets, dict) and 'result' in targets:
        return targets
    elif not isinstance(targets, dict):
        ret['result'] = False
        ret['comment'] = 'An error was encountered while checking targets: ' \
                         '{0}'.format(targets)
        return ret

    if __opts__['test']:
        summary = ', '.join(targets)
        ret['comment'] = 'The following packages would be ' \
                         'downloaded: {0}'.format(summary)
        return ret

    try:
        pkg_ret = __salt__['pkg.install'](name=name,
                                          pkgs=pkgs,
                                          version=version,
                                          downloadonly=True,
                                          fromrepo=fromrepo,
                                          ignore_epoch=ignore_epoch,
                                          **kwargs)
        ret['result'] = True
        ret['changes'].update(pkg_ret)
    except CommandExecutionError as exc:
        ret = {'name': name, 'result': False}
        if exc.info:
            # Get information for state return from the exception.
            ret['changes'] = exc.info.get('changes', {})
            ret['comment'] = exc.strerror_without_changes
        else:
            ret['changes'] = {}
            ret['comment'] = 'An error was encountered while downloading ' \
                             'package(s): {0}'.format(exc)
        return ret

    new_pkgs = __salt__['pkg.list_downloaded'](**kwargs)
    ok, failed = _verify_install(targets, new_pkgs, ignore_epoch=ignore_epoch)

    if failed:
        summary = ', '.join([_get_desired_pkg(x, targets)
                             for x in failed])
        ret['result'] = False
        ret['comment'] = 'The following packages failed to ' \
                         'download: {0}'.format(summary)

    if not ret['changes'] and not ret['comment']:
        ret['result'] = True
        ret['comment'] = 'Packages are already downloaded: ' \
                         '{0}'.format(', '.join(targets))

    return ret

Response: Download a specific version of a package from a software repository.


Instruction:
Here you have a function in Python 3, explain what it does
def patch_installed(name, advisory_ids=None, downloadonly=None, **kwargs):
    '''
    .. versionadded:: 2017.7.0

    Ensure that packages related to certain advisory ids are installed.

    Currently supported for the following pkg providers:
    :mod:`yumpkg <salt.modules.yumpkg>` and :mod:`zypper <salt.modules.zypper>`

    CLI Example:

    .. code-block:: yaml

        issue-foo-fixed:
          pkg.patch_installed:
            - advisory_ids:
              - SUSE-SLE-SERVER-12-SP2-2017-185
              - SUSE-SLE-SERVER-12-SP2-2017-150
              - SUSE-SLE-SERVER-12-SP2-2017-120
    '''
    ret = {'name': name,
           'changes': {},
           'result': None,
           'comment': ''}

    if 'pkg.list_patches' not in __salt__:
        ret['result'] = False
        ret['comment'] = 'The pkg.patch_installed state is not available on ' \
                         'this platform'
        return ret

    if not advisory_ids and isinstance(advisory_ids, list):
        ret['result'] = True
        ret['comment'] = 'No advisory ids provided'
        return ret

    # Only downloading not yet downloaded packages
    targets = _find_advisory_targets(name, advisory_ids, **kwargs)
    if isinstance(targets, dict) and 'result' in targets:
        return targets
    elif not isinstance(targets, list):
        ret['result'] = False
        ret['comment'] = 'An error was encountered while checking targets: ' \
                         '{0}'.format(targets)
        return ret

    if __opts__['test']:
        summary = ', '.join(targets)
        ret['comment'] = 'The following advisory patches would be ' \
                         'downloaded: {0}'.format(summary)
        return ret

    try:
        pkg_ret = __salt__['pkg.install'](name=name,
                                          advisory_ids=advisory_ids,
                                          downloadonly=downloadonly,
                                          **kwargs)
        ret['result'] = True
        ret['changes'].update(pkg_ret)
    except CommandExecutionError as exc:
        ret = {'name': name, 'result': False}
        if exc.info:
            # Get information for state return from the exception.
            ret['changes'] = exc.info.get('changes', {})
            ret['comment'] = exc.strerror_without_changes
        else:
            ret['changes'] = {}
            ret['comment'] = ('An error was encountered while downloading '
                              'package(s): {0}'.format(exc))
        return ret

    if not ret['changes'] and not ret['comment']:
        status = 'downloaded' if downloadonly else 'installed'
        ret['result'] = True
        ret['comment'] = ('Advisory patch is not needed or related packages '
                          'are already {0}'.format(status))

    return ret

Response: Ensure that the named advisory patch is installed on the specified packages.


Instruction:
How would you implement a function in Python 3 that
patches the installed packages with the given advisory ids.

Response:
def patch_downloaded(name, advisory_ids=None, **kwargs):
    '''
    .. versionadded:: 2017.7.0

    Ensure that packages related to certain advisory ids are downloaded.

    Currently supported for the following pkg providers:
    :mod:`yumpkg <salt.modules.yumpkg>` and :mod:`zypper <salt.modules.zypper>`

    CLI Example:

    .. code-block:: yaml

        preparing-to-fix-issues:
          pkg.patch_downloaded:
            - advisory_ids:
              - SUSE-SLE-SERVER-12-SP2-2017-185
              - SUSE-SLE-SERVER-12-SP2-2017-150
              - SUSE-SLE-SERVER-12-SP2-2017-120
    '''
    if 'pkg.list_patches' not in __salt__:
        return {'name': name,
                'result': False,
                'changes': {},
                'comment': 'The pkg.patch_downloaded state is not available on '
                           'this platform'}

    # It doesn't make sense here to received 'downloadonly' as kwargs
    # as we're explicitly passing 'downloadonly=True' to execution module.
    if 'downloadonly' in kwargs:
        del kwargs['downloadonly']
    return patch_installed(name=name, advisory_ids=advisory_ids, downloadonly=True, **kwargs)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def purged(name,
           version=None,
           pkgs=None,
           normalize=True,
           ignore_epoch=False,
           **kwargs):
    '''
    Verify that a package is not installed, calling ``pkg.purge`` if necessary
    to purge the package. All configuration files are also removed.

    name
        The name of the package to be purged.

    version
        The version of the package that should be removed. Don't do anything if
        the package is installed with an unmatching version.

        .. important::
            As of version 2015.8.7, for distros which use yum/dnf, packages
            which have a version with a nonzero epoch (that is, versions which
            start with a number followed by a colon like in the example above)
            must have the epoch included when specifying the version number.
            For example:

            .. code-block:: yaml

                vim-enhanced:
                  pkg.purged:
                    - version: 2:7.4.160-1.el7

            In version 2015.8.9, an **ignore_epoch** argument has been added to
            :py:mod:`pkg.installed <salt.states.pkg.installed>`,
            :py:mod:`pkg.removed <salt.states.pkg.removed>`, and
            :py:mod:`pkg.purged <salt.states.pkg.purged>` states, which
            causes the epoch to be disregarded when the state checks to see if
            the desired version was installed. If **ignore_epoch** was not set
            to ``True``, and instead of ``2:7.4.160-1.el7`` a version of
            ``7.4.160-1.el7`` were used, this state would report success since
            the actual installed version includes the epoch, and the specified
            version would not match.

    normalize : True
        Normalize the package name by removing the architecture, if the
        architecture of the package is different from the architecture of the
        operating system. The ability to disable this behavior is useful for
        poorly-created packages which include the architecture as an actual
        part of the name, such as kernel modules which match a specific kernel
        version.

        .. versionadded:: 2015.8.0

    ignore_epoch : False
        When a package version contains an non-zero epoch (e.g.
        ``1:3.14.159-2.el7``, and a specific version of a package is desired,
        set this option to ``True`` to ignore the epoch when comparing
        versions. This allows for the following SLS to be used:

        .. code-block:: yaml

            # Actual vim-enhanced version: 2:7.4.160-1.el7
            vim-enhanced:
              pkg.purged:
                - version: 7.4.160-1.el7
                - ignore_epoch: True

        Without this option set to ``True`` in the above example, the state
        would falsely report success since the actual installed version is
        ``2:7.4.160-1.el7``. Alternatively, this option can be left as
        ``False`` and the full version string (with epoch) can be specified in
        the SLS file:

        .. code-block:: yaml

            vim-enhanced:
              pkg.purged:
                - version: 2:7.4.160-1.el7

        .. versionadded:: 2015.8.9

    Multiple Package Options:

    pkgs
        A list of packages to purge. Must be passed as a python list. The
        ``name`` parameter will be ignored if this option is passed. It accepts
        version numbers as well.

    .. versionadded:: 0.16.0
    '''
    kwargs['saltenv'] = __env__
    try:
        return _uninstall(action='purge', name=name, version=version,
                          pkgs=pkgs, normalize=normalize,
                          ignore_epoch=ignore_epoch, **kwargs)
    except CommandExecutionError as exc:
        ret = {'name': name, 'result': False}
        if exc.info:
            # Get information for state return from the exception.
            ret['changes'] = exc.info.get('changes', {})
            ret['comment'] = exc.strerror_without_changes
        else:
            ret['changes'] = {}
            ret['comment'] = ('An error was encountered while purging '
                              'package(s): {0}'.format(exc))
        return ret

Response: Purge the specified package and version.


Instruction:
Can you generate the documentation for the following Python 3 function
def uptodate(name, refresh=False, pkgs=None, **kwargs):
    '''
    .. versionadded:: 2014.7.0
    .. versionchanged:: 2018.3.0

        Added support for the ``pkgin`` provider.

    Verify that the system is completely up to date.

    name
        The name has no functional value and is only used as a tracking
        reference

    refresh
        refresh the package database before checking for new upgrades

    pkgs
        list of packages to upgrade

    :param str cache_valid_time:
        This parameter sets the value in seconds after which cache marked as invalid,
        and cache update is necessary. This overwrite ``refresh`` parameter
        default behavior.

        In this case cache_valid_time is set, refresh will not take place for
        amount in seconds since last ``apt-get update`` executed on the system.

        .. note::

            This parameter available only on Debian based distributions, and
            have no effect on the rest.

    :param bool resolve_capabilities:
        Turn on resolving capabilities. This allow one to name "provides" or alias names for packages.

        .. versionadded:: 2018.3.0

    kwargs
        Any keyword arguments to pass through to ``pkg.upgrade``.

        .. versionadded:: 2015.5.0
    '''
    ret = {'name': name,
           'changes': {},
           'result': False,
           'comment': 'Failed to update'}

    if 'pkg.list_upgrades' not in __salt__:
        ret['comment'] = 'State pkg.uptodate is not available'
        return ret

    # emerge --update doesn't appear to support repo notation
    if 'fromrepo' in kwargs and __grains__['os_family'] == 'Gentoo':
        ret['comment'] = '\'fromrepo\' argument not supported on this platform'
        return ret

    if isinstance(refresh, bool):
        pkgs, refresh = _resolve_capabilities(pkgs, refresh=refresh, **kwargs)
        try:
            packages = __salt__['pkg.list_upgrades'](refresh=refresh, **kwargs)
            expected = {pkgname: {'new': pkgver, 'old': __salt__['pkg.version'](pkgname, **kwargs)}
                        for pkgname, pkgver in six.iteritems(packages)}
            if isinstance(pkgs, list):
                packages = [pkg for pkg in packages if pkg in pkgs]
                expected = {pkgname: pkgver for pkgname, pkgver in six.iteritems(expected) if pkgname in pkgs}
        except Exception as exc:
            ret['comment'] = six.text_type(exc)
            return ret
    else:
        ret['comment'] = 'refresh must be either True or False'
        return ret

    if not packages:
        ret['comment'] = 'System is already up-to-date'
        ret['result'] = True
        return ret
    elif __opts__['test']:
        ret['comment'] = 'System update will be performed'
        ret['changes'] = expected
        ret['result'] = None
        return ret

    try:
        ret['changes'] = __salt__['pkg.upgrade'](refresh=refresh, pkgs=pkgs, **kwargs)
    except CommandExecutionError as exc:
        if exc.info:
            # Get information for state return from the exception.
            ret['changes'] = exc.info.get('changes', {})
            ret['comment'] = exc.strerror_without_changes
        else:
            ret['changes'] = {}
            ret['comment'] = ('An error was encountered while updating '
                              'packages: {0}'.format(exc))
        return ret

    # If a package list was provided, ensure those packages were updated
    missing = []
    if isinstance(pkgs, list):
        missing = [pkg for pkg in six.iterkeys(expected) if pkg not in ret['changes']]

    if missing:
        ret['comment'] = 'The following package(s) failed to update: {0}'.format(', '.join(missing))
        ret['result'] = False
    else:
        ret['comment'] = 'Upgrade ran successfully'
        ret['result'] = True

    return ret

Response: Return a new version of the named package in a new version of the system.


Instruction:
Create a Python 3 function for
ensuring that a group is installed for a specific item.

Response:
def group_installed(name, skip=None, include=None, **kwargs):
    '''
    .. versionadded:: 2015.8.0

    .. versionchanged:: 2016.11.0
        Added support in :mod:`pacman <salt.modules.pacman>`

    Ensure that an entire package group is installed. This state is currently
    only supported for the :mod:`yum <salt.modules.yumpkg>` and :mod:`pacman <salt.modules.pacman>`
    package managers.

    skip
        Packages that would normally be installed by the package group
        ("default" packages), which should not be installed.

        .. code-block:: yaml

            Load Balancer:
              pkg.group_installed:
                - skip:
                  - piranha

    include
        Packages which are included in a group, which would not normally be
        installed by a ``yum groupinstall`` ("optional" packages). Note that
        this will not enforce group membership; if you include packages which
        are not members of the specified groups, they will still be installed.

        .. code-block:: yaml

            Load Balancer:
              pkg.group_installed:
                - include:
                  - haproxy

        .. versionchanged:: 2016.3.0
            This option can no longer be passed as a comma-separated list, it
            must now be passed as a list (as shown in the above example).

    .. note::
        Because this is essentially a wrapper around :py:func:`pkg.install
        <salt.modules.yumpkg.install>`, any argument which can be passed to
        pkg.install may also be included here, and it will be passed on to the
        call to :py:func:`pkg.install <salt.modules.yumpkg.install>`.
    '''
    ret = {'name': name,
           'changes': {},
           'result': False,
           'comment': ''}

    if 'pkg.group_diff' not in __salt__:
        ret['comment'] = 'pkg.group_install not available for this platform'
        return ret

    if skip is None:
        skip = []
    else:
        if not isinstance(skip, list):
            ret['comment'] = 'skip must be formatted as a list'
            return ret
        for idx, item in enumerate(skip):
            if not isinstance(item, six.string_types):
                skip[idx] = six.text_type(item)

    if include is None:
        include = []
    else:
        if not isinstance(include, list):
            ret['comment'] = 'include must be formatted as a list'
            return ret
        for idx, item in enumerate(include):
            if not isinstance(item, six.string_types):
                include[idx] = six.text_type(item)

    try:
        diff = __salt__['pkg.group_diff'](name)
    except CommandExecutionError as err:
        ret['comment'] = ('An error was encountered while installing/updating '
                          'group \'{0}\': {1}.'.format(name, err))
        return ret

    mandatory = diff['mandatory']['installed'] + \
        diff['mandatory']['not installed']

    invalid_skip = [x for x in mandatory if x in skip]
    if invalid_skip:
        ret['comment'] = (
            'The following mandatory packages cannot be skipped: {0}'
            .format(', '.join(invalid_skip))
        )
        return ret

    targets = diff['mandatory']['not installed']
    targets.extend([x for x in diff['default']['not installed']
                    if x not in skip])
    targets.extend(include)

    if not targets:
        ret['result'] = True
        ret['comment'] = 'Group \'{0}\' is already installed'.format(name)
        return ret

    partially_installed = diff['mandatory']['installed'] \
        or diff['default']['installed'] \
        or diff['optional']['installed']

    if __opts__['test']:
        ret['result'] = None
        if partially_installed:
            ret['comment'] = (
                'Group \'{0}\' is partially installed and will be updated'
                .format(name)
            )
        else:
            ret['comment'] = 'Group \'{0}\' will be installed'.format(name)
        return ret

    try:
        ret['changes'] = __salt__['pkg.install'](pkgs=targets, **kwargs)
    except CommandExecutionError as exc:
        ret = {'name': name, 'result': False}
        if exc.info:
            # Get information for state return from the exception.
            ret['changes'] = exc.info.get('changes', {})
            ret['comment'] = exc.strerror_without_changes
        else:
            ret['changes'] = {}
            ret['comment'] = ('An error was encountered while '
                              'installing/updating group \'{0}\': {1}'
                              .format(name, exc))
        return ret

    failed = [x for x in targets if x not in __salt__['pkg.list_pkgs'](**kwargs)]
    if failed:
        ret['comment'] = (
            'Failed to install the following packages: {0}'
            .format(', '.join(failed))
        )
        return ret

    ret['result'] = True
    ret['comment'] = 'Group \'{0}\' was {1}'.format(
        name,
        'updated' if partially_installed else 'installed'
    )
    return ret


Instruction:
Given the following Python 3 function, write the documentation
def mod_init(low):
    '''
    Set a flag to tell the install functions to refresh the package database.
    This ensures that the package database is refreshed only once during
    a state run significantly improving the speed of package management
    during a state run.

    It sets a flag for a number of reasons, primarily due to timeline logic.
    When originally setting up the mod_init for pkg a number of corner cases
    arose with different package managers and how they refresh package data.

    It also runs the "ex_mod_init" from the package manager module that is
    currently loaded. The "ex_mod_init" is expected to work as a normal
    "mod_init" function.

    .. seealso::
       :py:func:`salt.modules.ebuild.ex_mod_init`

    '''
    ret = True
    if 'pkg.ex_mod_init' in __salt__:
        ret = __salt__['pkg.ex_mod_init'](low)

    if low['fun'] == 'installed' or low['fun'] == 'latest':
        salt.utils.pkg.write_rtag(__opts__)
        return ret
    return False

Response: Initializes the package database.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def mod_watch(name, **kwargs):
    '''
    Install/reinstall a package based on a watch requisite

    .. note::
        This state exists to support special handling of the ``watch``
        :ref:`requisite <requisites>`. It should not be called directly.

        Parameters for this function should be set by the state being triggered.
    '''
    sfun = kwargs.pop('sfun', None)
    mapfun = {'purged': purged,
              'latest': latest,
              'removed': removed,
              'installed': installed}
    if sfun in mapfun:
        return mapfun[sfun](name, **kwargs)
    return {'name': name,
            'changes': {},
            'comment': 'pkg.{0} does not work with the watch requisite'.format(sfun),
            'result': False}

Response: This function is used to install or reinstall a package based on a watch requisite.


Instruction:
Implement a Python 3 function for
ensuring that the named port exists on the bridge.

Response:
def present(name, bridge, tunnel_type=None, id=None, remote=None, dst_port=None, internal=False):
    '''
    Ensures that the named port exists on bridge, eventually creates it.

    Args:
        name: The name of the port.
        bridge: The name of the bridge.
        tunnel_type: Optional type of interface to create, currently supports: vlan, vxlan and gre.
        id: Optional tunnel's key.
        remote: Remote endpoint's IP address.
        dst_port: Port to use when creating tunnelport in the switch.
        internal: Create an internal port if one does not exist

    '''
    ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
    tunnel_types = ('vlan', 'vxlan', 'gre')

    if tunnel_type and tunnel_type not in tunnel_types:
        raise TypeError('The optional type argument must be one of these values: {0}.'.format(
            six.text_type(tunnel_types))
        )

    bridge_exists = __salt__['openvswitch.bridge_exists'](bridge)
    port_list = []
    if bridge_exists:
        port_list = __salt__['openvswitch.port_list'](bridge)

    # Comment and change messages

    comments = {}

    comments['comment_bridge_notexists'] = 'Bridge {0} does not exist.'.format(bridge)
    comments['comment_port_exists'] = 'Port {0} already exists.'.format(name)
    comments['comment_port_created'] = 'Port {0} created on bridge {1}.'.format(name, bridge)
    comments['comment_port_notcreated'] = 'Unable to create port {0} on bridge {1}.'.format(name, bridge)
    comments['changes_port_created'] = {name: {'old': 'No port named {0} present.'.format(name),
                                   'new': 'Created port {1} on bridge {0}.'.format(bridge, name),
                                   }
                            }
    comments['comment_port_internal'] = 'Port {0} already exists, but interface type has been changed to internal.'.format(name)
    comments['changes_port_internal'] = {'internal': {'old': False, 'new': True}}
    comments['comment_port_internal_not_changed'] = 'Port {0} already exists, but the interface type could not be changed to internal.'.format(name)

    if tunnel_type:
        comments['comment_invalid_ip'] = 'Remote is not valid ip address.'
        if tunnel_type == "vlan":
            comments['comment_vlan_invalid_id'] = 'VLANs id must be between 0 and 4095.'
            comments['comment_vlan_invalid_name'] = 'Could not find network interface {0}.'.format(name)
            comments['comment_vlan_port_exists'] = 'Port {0} with access to VLAN {1} already exists on bridge {2}.'.format(name, id, bridge)
            comments['comment_vlan_created'] = 'Created port {0} with access to VLAN {1} on bridge {2}.'.format(name, id, bridge)
            comments['comment_vlan_notcreated'] = 'Unable to create port {0} with access to VLAN {1} on ' \
                                      'bridge {2}.'.format(name, id, bridge)
            comments['changes_vlan_created'] = {name: {'old': 'No port named {0} with access to VLAN {1} present on '
                                                  'bridge {2} present.'.format(name, id, bridge),
                                           'new': 'Created port {1} with access to VLAN {2} on '
                                                  'bridge {0}.'.format(bridge, name, id),
                                           }
                                    }

        elif tunnel_type == "gre":
            comments['comment_gre_invalid_id'] = 'Id of GRE tunnel must be an unsigned 32-bit integer.'
            comments['comment_gre_interface_exists'] = 'GRE tunnel interface {0} with rempte ip {1} and key {2} ' \
                                           'already exists on bridge {3}.'.format(name, remote, id, bridge)
            comments['comment_gre_created'] = 'Created GRE tunnel interface {0} with remote ip {1}  and key {2} ' \
                                  'on bridge {3}.'.format(name, remote, id, bridge)
            comments['comment_gre_notcreated'] = 'Unable to create GRE tunnel interface {0} with remote ip {1} and key {2} ' \
                                     'on bridge {3}.'.format(name, remote, id, bridge)
            comments['changes_gre_created'] = {name: {'old': 'No GRE tunnel interface {0} with remote ip {1} and key {2} '
                                                 'on bridge {3} present.'.format(name, remote, id, bridge),
                                           'new': 'Created GRE tunnel interface {0} with remote ip {1} and key {2} '
                                                  'on bridge {3}.'.format(name, remote, id, bridge),
                                           }
                                    }
        elif tunnel_type == "vxlan":
            comments['comment_dstport'] = ' (dst_port' + six.text_type(dst_port) + ')' if 0 < dst_port <= 65535 else ''
            comments['comment_vxlan_invalid_id'] = 'Id of VXLAN tunnel must be an unsigned 64-bit integer.'
            comments['comment_vxlan_interface_exists'] = 'VXLAN tunnel interface {0} with rempte ip {1} and key {2} ' \
                                           'already exists on bridge {3}{4}.'.format(name, remote, id, bridge, comments['comment_dstport'])
            comments['comment_vxlan_created'] = 'Created VXLAN tunnel interface {0} with remote ip {1}  and key {2} ' \
                                  'on bridge {3}{4}.'.format(name, remote, id, bridge, comments['comment_dstport'])
            comments['comment_vxlan_notcreated'] = 'Unable to create VXLAN tunnel interface {0} with remote ip {1} and key {2} ' \
                                     'on bridge {3}{4}.'.format(name, remote, id, bridge, comments['comment_dstport'])
            comments['changes_vxlan_created'] = {name: {'old': 'No VXLAN tunnel interface {0} with remote ip {1} and key {2} '
                                                 'on bridge {3}{4} present.'.format(name, remote, id, bridge, comments['comment_dstport']),
                                           'new': 'Created VXLAN tunnel interface {0} with remote ip {1} and key {2} '
                                                  'on bridge {3}{4}.'.format(name, remote, id, bridge, comments['comment_dstport']),
                                           }
                                    }

    # Check VLANs attributes
    def _check_vlan():
        tag = __salt__['openvswitch.port_get_tag'](name)
        interfaces = __salt__['network.interfaces']()
        if not 0 <= id <= 4095:
            ret['result'] = False
            ret['comment'] = comments['comment_vlan_invalid_id']
        elif not internal and name not in interfaces:
            ret['result'] = False
            ret['comment'] = comments['comment_vlan_invalid_name']
        elif tag and name in port_list:
            try:
                if int(tag[0]) == id:
                    ret['result'] = True
                    ret['comment'] = comments['comment_vlan_port_exists']
            except (ValueError, KeyError):
                pass

    # Check GRE tunnels attributes
    def _check_gre():
        interface_options = __salt__['openvswitch.interface_get_options'](name)
        interface_type = __salt__['openvswitch.interface_get_type'](name)
        if not 0 <= id <= 2**32:
            ret['result'] = False
            ret['comment'] = comments['comment_gre_invalid_id']
        elif not __salt__['dig.check_ip'](remote):
            ret['result'] = False
            ret['comment'] = comments['comment_invalid_ip']
        elif interface_options and interface_type and name in port_list:
            interface_attroptions = '{key=\"' + six.text_type(id) + '\", remote_ip=\"' + six.text_type(remote) + '\"}'
            try:
                if interface_type[0] == 'gre' and interface_options[0] == interface_attroptions:
                    ret['result'] = True
                    ret['comment'] = comments['comment_gre_interface_exists']
            except KeyError:
                pass

    # Check VXLAN tunnels attributes
    def _check_vxlan():
        interface_options = __salt__['openvswitch.interface_get_options'](name)
        interface_type = __salt__['openvswitch.interface_get_type'](name)
        if not 0 <= id <= 2**64:
            ret['result'] = False
            ret['comment'] = comments['comment_vxlan_invalid_id']
        elif not __salt__['dig.check_ip'](remote):
            ret['result'] = False
            ret['comment'] = comments['comment_invalid_ip']
        elif interface_options and interface_type and name in port_list:
            opt_port = 'dst_port=\"' + six.text_type(dst_port) + '\", ' if 0 < dst_port <= 65535 else ''
            interface_attroptions = '{{{0}key=\"'.format(opt_port) + six.text_type(id) + '\", remote_ip=\"' + six.text_type(remote) + '\"}'
            try:
                if interface_type[0] == 'vxlan' and interface_options[0] == interface_attroptions:
                    ret['result'] = True
                    ret['comment'] = comments['comment_vxlan_interface_exists']
            except KeyError:
                pass

    # Dry run, test=true mode
    if __opts__['test']:
        if bridge_exists:
            if tunnel_type == 'vlan':
                _check_vlan()
                if not ret['comment']:
                    ret['result'] = None
                    ret['comment'] = comments['comment_vlan_created']
            elif tunnel_type == 'vxlan':
                _check_vxlan()
                if not ret['comment']:
                    ret['result'] = None
                    ret['comment'] = comments['comment_vxlan_created']
            elif tunnel_type == 'gre':
                _check_gre()
                if not ret['comment']:
                    ret['result'] = None
                    ret['comment'] = comments['comment_gre_created']
            else:
                if name in port_list:
                    ret['result'] = True
                    current_type = __salt__['openvswitch.interface_get_type'](
                        name)
                    # The interface type is returned as a single-element list.
                    if internal and (current_type != ['internal']):
                        ret['comment'] = comments['comment_port_internal']
                    else:
                        ret['comment'] = comments['comment_port_exists']
                else:
                    ret['result'] = None
                    ret['comment'] = comments['comment_port_created']
        else:
            ret['result'] = None
            ret['comment'] = comments['comment_bridge_notexists']

        return ret

    if bridge_exists:
        if tunnel_type == 'vlan':
            _check_vlan()
            if not ret['comment']:
                port_create_vlan = __salt__['openvswitch.port_create_vlan'](bridge, name, id, internal)
                if port_create_vlan:
                    ret['result'] = True
                    ret['comment'] = comments['comment_vlan_created']
                    ret['changes'] = comments['changes_vlan_created']
                else:
                    ret['result'] = False
                    ret['comment'] = comments['comment_vlan_notcreated']
        elif tunnel_type == 'vxlan':
            _check_vxlan()
            if not ret['comment']:
                port_create_vxlan = __salt__['openvswitch.port_create_vxlan'](bridge, name, id, remote, dst_port)
                if port_create_vxlan:
                    ret['result'] = True
                    ret['comment'] = comments['comment_vxlan_created']
                    ret['changes'] = comments['changes_vxlan_created']
                else:
                    ret['result'] = False
                    ret['comment'] = comments['comment_vxlan_notcreated']
        elif tunnel_type == 'gre':
            _check_gre()
            if not ret['comment']:
                port_create_gre = __salt__['openvswitch.port_create_gre'](bridge, name, id, remote)
                if port_create_gre:
                    ret['result'] = True
                    ret['comment'] = comments['comment_gre_created']
                    ret['changes'] = comments['changes_gre_created']
                else:
                    ret['result'] = False
                    ret['comment'] = comments['comment_gre_notcreated']
        else:
            if name in port_list:
                current_type = __salt__['openvswitch.interface_get_type'](name)
                # The interface type is returned as a single-element list.
                if internal and (current_type != ['internal']):
                    # We do not have a direct way of only setting the interface
                    # type to internal, so we add the port with the --may-exist
                    # option.
                    port_add = __salt__['openvswitch.port_add'](
                        bridge, name, may_exist=True, internal=internal)
                    if port_add:
                        ret['result'] = True
                        ret['comment'] = comments['comment_port_internal']
                        ret['changes'] = comments['changes_port_internal']
                    else:
                        ret['result'] = False
                        ret['comment'] = comments[
                            'comment_port_internal_not_changed']
                else:
                    ret['result'] = True
                    ret['comment'] = comments['comment_port_exists']
            else:
                port_add = __salt__['openvswitch.port_add'](bridge, name, internal=internal)
                if port_add:
                    ret['result'] = True
                    ret['comment'] = comments['comment_port_created']
                    ret['changes'] = comments['changes_port_created']
                else:
                    ret['result'] = False
                    ret['comment'] = comments['comment_port_notcreated']
    else:
        ret['result'] = False
        ret['comment'] = comments['comment_bridge_notexists']

    return ret


Instruction:
Write a Python 3 function that can
ensure that the named port does not exist on the named bridge.

Response:
def absent(name, bridge=None):
    '''
    Ensures that the named port exists on bridge, eventually deletes it.
    If bridge is not set, port is removed from  whatever bridge contains it.

    Args:
        name: The name of the port.
        bridge: The name of the bridge.

    '''
    ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
    bridge_exists = False
    if bridge:
        bridge_exists = __salt__['openvswitch.bridge_exists'](bridge)
        if bridge_exists:
            port_list = __salt__['openvswitch.port_list'](bridge)
        else:
            port_list = ()
    else:
        port_list = [name]

    # Comment and change messages
    comments = {}
    comments['comment_bridge_notexists'] = 'Bridge {0} does not exist.'.format(bridge)
    comments['comment_port_notexists'] = 'Port {0} does not exist on bridge {1}.'.format(name, bridge)
    comments['comment_port_deleted'] = 'Port {0} deleted.'.format(name)
    comments['comment_port_notdeleted'] = 'Unable to delete port {0}.'.format(name)
    comments['changes_port_deleted'] = {name: {'old': 'Port named {0} may exist.'.format(name),
                                   'new': 'Deleted port {0}.'.format(name),
                                   }
                            }

    # Dry run, test=true mode
    if __opts__['test']:
        if bridge and not bridge_exists:
            ret['result'] = None
            ret['comment'] = comments['comment_bridge_notexists']
        elif name not in port_list:
            ret['result'] = True
            ret['comment'] = comments['comment_port_notexists']
        else:
            ret['result'] = None
            ret['comment'] = comments['comment_port_deleted']
        return ret

    if bridge and not bridge_exists:
        ret['result'] = False
        ret['comment'] = comments['comment_bridge_notexists']
    elif name not in port_list:
        ret['result'] = True
        ret['comment'] = comments['comment_port_notexists']
    else:
        if bridge:
            port_remove = __salt__['openvswitch.port_remove'](br=bridge, port=name)
        else:
            port_remove = __salt__['openvswitch.port_remove'](br=None, port=name)

        if port_remove:
            ret['result'] = True
            ret['comment'] = comments['comment_port_deleted']
            ret['changes'] = comments['changes_port_deleted']
        else:
            ret['result'] = False
            ret['comment'] = comments['comment_port_notdeleted']

    return ret


Instruction:
How would you code a function in Python 3 to
call out to system_profiler. Return a dictionary of the stuff we are interested in.

Response:
def _call_system_profiler(datatype):
    '''
    Call out to system_profiler.  Return a dictionary
    of the stuff we are interested in.
    '''

    p = subprocess.Popen(
        [PROFILER_BINARY, '-detailLevel', 'full',
         '-xml', datatype], stdout=subprocess.PIPE)
    (sysprofresults, sysprof_stderr) = p.communicate(input=None)

    if six.PY2:
        plist = plistlib.readPlistFromString(sysprofresults)
    else:
        plist = plistlib.readPlistFromBytes(sysprofresults)

    try:
        apps = plist[0]['_items']
    except (IndexError, KeyError):
        apps = []

    return apps


Instruction:
Can you generate the documentation for the following Python 3 function
def receipts():
    '''
    Return the results of a call to
    ``system_profiler -xml -detail full SPInstallHistoryDataType``
    as a dictionary.  Top-level keys of the dictionary
    are the names of each set of install receipts, since
    there can be multiple receipts with the same name.
    Contents of each key are a list of dictionaries.

    CLI Example:

    .. code-block:: bash

        salt '*' systemprofiler.receipts
    '''

    apps = _call_system_profiler('SPInstallHistoryDataType')

    appdict = {}

    for a in apps:
        details = dict(a)
        details.pop('_name')
        if 'install_date' in details:
            details['install_date'] = details['install_date'].strftime('%Y-%m-%d %H:%M:%S')
        if 'info' in details:
            try:
                details['info'] = '{0}: {1}'.format(details['info'][0],
                                                    details['info'][1].strftime('%Y-%m-%d %H:%M:%S'))
            except (IndexError, AttributeError):
                pass

        if a['_name'] not in appdict:
            appdict[a['_name']] = []

        appdict[a['_name']].append(details)

    return appdict

Response: Return the results of a call to system_profiler - xml - detail full SPInstallHistoryDataType


Instruction:
Explain what the following Python 3 code does
def alias(name, collections, **kwargs):
    '''
    Create alias and enforce collection list.

    Use the solrcloud module to get alias members and set them.

    You can pass additional arguments that will be forwarded to http.query

    name
        The collection name
    collections
        list of collections to include in the alias
    '''
    ret = {
        'name': name,
        'changes': {},
        'result': False,
        'comment': '',
    }

    if __salt__['solrcloud.alias_exists'](name, **kwargs):
        alias_content = __salt__['solrcloud.alias_get_collections'](name, **kwargs)
        diff = set(alias_content).difference(set(collections))

        if not diff:
            ret['result'] = True
            ret['comment'] = 'Alias is in desired state'
            return ret

        if __opts__['test']:
            ret['comment'] = 'The alias "{0}" will be updated.'.format(name)
            ret['result'] = None
        else:
            __salt__['solrcloud.alias_set_collections'](name, collections, **kwargs)
            ret['comment'] = 'The alias "{0}" has been updated.'.format(name)
            ret['result'] = True

        ret['changes'] = {
            'old': ','.join(alias_content),
            'new': ','.join(collections),
        }

    else:
        if __opts__['test']:
            ret['comment'] = 'The alias "{0}" will be created.'.format(name)
            ret['result'] = None
        else:
            __salt__['solrcloud.alias_set_collections'](name, collections, **kwargs)
            ret['comment'] = 'The alias "{0}" has been created.'.format(name)
            ret['result'] = True

        ret['changes'] = {
            'old': None,
            'new': ','.join(collections),
        }

    return ret

Response: Create alias and enforce collection list.


Instruction:
Write a Python 3 script for
creating a new collection and enforce options.

Response:
def collection(name, options=None, **kwargs):
    '''
    Create collection and enforce options.

    Use the solrcloud module to get collection parameters.

    You can pass additional arguments that will be forwarded to http.query

    name
        The collection name
    options : {}
        options to ensure
    '''
    ret = {
        'name': name,
        'changes': {},
        'result': False,
        'comment': '',
    }

    if options is None:
        options = {}

    if __salt__["solrcloud.collection_exists"](name, **kwargs):

        diff = {}

        current_options = __salt__["solrcloud.collection_get_options"](name, **kwargs)

        # Filter options that can be updated
        updatable_options = [
            "maxShardsPerNode",
            "replicationFactor",
            "autoAddReplicas",
            "collection.configName",
            "rule",
            "snitch"]

        options = [k for k in six.iteritems(options) if k in updatable_options]

        for key, value in options:
            if key not in current_options or current_options[key] != value:
                diff[key] = value

        if not diff:
            ret['result'] = True
            ret['comment'] = 'Collection options are in desired state'
            return ret

        else:

            if __opts__['test']:
                ret['comment'] = 'Collection options "{0}" will be changed.'.format(name)
                ret['result'] = None
            else:
                __salt__['solrcloud.collection_set_options'](name, diff, **kwargs)
                ret['comment'] = 'Parameters were updated for collection "{0}".'.format(name)
                ret['result'] = True

            ret['changes'] = {
                'old': salt.utils.json.dumps(current_options, sort_keys=True, indent=4, separators=(',', ': ')),
                'new': salt.utils.json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
            }
            return ret

    else:

        new_changes = salt.utils.json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
        if __opts__['test']:
            ret['comment'] = 'The collection "{0}" will be created.'.format(name)
            ret['result'] = None
        else:
            __salt__["solrcloud.collection_create"](name, options, **kwargs)
            ret['comment'] = 'The collection "{0}" has been created.'.format(name)
            ret['result'] = True

        ret['changes'] = {
            'old': None,
            'new': str('options=') + new_changes  # future lint: disable=blacklisted-function
        }

    return ret


Instruction:
Write a Python 3 script for
querying the object on the Consul API URL.

Response:
def _query(function,
           consul_url,
           token=None,
           method='GET',
           api_version='v1',
           data=None,
           query_params=None):
    '''
    Consul object method function to construct and execute on the API URL.

    :param api_url:     The Consul api url.
    :param api_version  The Consul api version
    :param function:    The Consul api function to perform.
    :param method:      The HTTP method, e.g. GET or POST.
    :param data:        The data to be sent for POST method. This param is ignored for GET requests.
    :return:            The json response from the API call or False.
    '''

    if not query_params:
        query_params = {}

    ret = {'data': '',
           'res': True}

    if not token:
        token = _get_token()

    headers = {"X-Consul-Token": token, "Content-Type": "application/json"}
    base_url = urllib.parse.urljoin(consul_url, '{0}/'.format(api_version))
    url = urllib.parse.urljoin(base_url, function, False)

    if method == 'GET':
        data = None
    else:
        if data is None:
            data = {}
        data = salt.utils.json.dumps(data)

    result = salt.utils.http.query(
        url,
        method=method,
        params=query_params,
        data=data,
        decode=True,
        status=True,
        header_dict=headers,
        opts=__opts__,
    )

    if result.get('status', None) == http_client.OK:
        ret['data'] = result.get('dict', result)
        ret['res'] = True
    elif result.get('status', None) == http_client.NO_CONTENT:
        ret['res'] = False
    elif result.get('status', None) == http_client.NOT_FOUND:
        ret['data'] = 'Key not found.'
        ret['res'] = False
    else:
        if result:
            ret['data'] = result
            ret['res'] = True
        else:
            ret['res'] = False
    return ret


Instruction:
How would you implement a function in Python 3 that
lists the keys in Consul

Response:
def list_(consul_url=None, token=None, key=None, **kwargs):
    '''
    List keys in Consul

    :param consul_url: The Consul server URL.
    :param key: The key to use as the starting point for the list.
    :return: The list of keys.

    CLI Example:

    .. code-block:: bash

        salt '*' consul.list
        salt '*' consul.list key='web'

    '''
    ret = {}

    if not consul_url:
        consul_url = _get_config()
        if not consul_url:
            log.error('No Consul URL found.')
            ret['message'] = 'No Consul URL found.'
            ret['res'] = False
            return ret

    query_params = {}

    if 'recurse' in kwargs:
        query_params['recurse'] = 'True'

    # No key so recurse and show all values
    if not key:
        query_params['recurse'] = 'True'
        function = 'kv/'
    else:
        function = 'kv/{0}'.format(key)

    query_params['keys'] = 'True'
    query_params['separator'] = '/'
    ret = _query(consul_url=consul_url,
                 function=function,
                 token=token,
                 query_params=query_params)
    return ret


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get(consul_url=None, key=None, token=None, recurse=False, decode=False, raw=False):
    '''
    Get key from Consul

    :param consul_url: The Consul server URL.
    :param key: The key to use as the starting point for the list.
    :param recurse: Return values recursively beginning at the value of key.
    :param decode: By default values are stored as Base64 encoded values,
                   decode will return the whole key with the value decoded.
    :param raw: Simply return the decoded value of the key.
    :return: The keys in Consul.

    CLI Example:

    .. code-block:: bash

        salt '*' consul.get key='web/key1'
        salt '*' consul.get key='web' recurse=True
        salt '*' consul.get key='web' recurse=True decode=True

    By default values stored in Consul are base64 encoded, passing the
    decode option will show them as the decoded values.

    .. code-block:: bash

        salt '*' consul.get key='web' recurse=True decode=True raw=True

    By default Consult will return other information about the key, the raw
    option will return only the raw value.

    '''
    ret = {}
    if not consul_url:
        consul_url = _get_config()
        if not consul_url:
            log.error('No Consul URL found.')
            ret['message'] = 'No Consul URL found.'
            ret['res'] = False
            return ret

    if not key:
        raise SaltInvocationError('Required argument "key" is missing.')

    query_params = {}
    function = 'kv/{0}'.format(key)
    if recurse:
        query_params['recurse'] = 'True'
    if raw:
        query_params['raw'] = True
    ret = _query(consul_url=consul_url,
                 function=function,
                 token=token,
                 query_params=query_params)

    if ret['res']:
        if decode:
            for item in ret['data']:
                if item['Value'] is None:
                    item['Value'] = ""
                else:
                    item['Value'] = base64.b64decode(item['Value'])
    return ret

Response: Get the key from Consul.