Пример #1
0
def delete_key_recursive(hive, key, use_32bit_registry=False):
    """
    .. versionadded:: 2015.5.4

    Delete a registry key to include all subkeys and value/data pairs.

    Args:

        hive (str):
            The name of the hive. Can be one of the following

                - HKEY_LOCAL_MACHINE or HKLM
                - HKEY_CURRENT_USER or HKCU
                - HKEY_USER or HKU
                - HKEY_CLASSES_ROOT or HKCR
                - HKEY_CURRENT_CONFIG or HKCC

            key (str):
                The key to remove (looks like a path)

            use_32bit_registry (bool):
                Deletes the 32bit portion of the registry on 64bit
                installations. On 32bit machines this is ignored.

    Returns:
        dict: A dictionary listing the keys that deleted successfully as well as
            those that failed to delete.

    Usage:

        The following example will remove ``salt`` and all its subkeys from the
        ``SOFTWARE`` key in ``HKEY_LOCAL_MACHINE``:

        .. code-block:: python

            import salt.utils.win_reg
            winreg.delete_key_recursive(hive='HKLM', key='SOFTWARE\\DeleteMe')
    """

    local_hive = _to_unicode(hive)
    local_key = _to_unicode(key)

    # Instantiate the registry object
    registry = Registry()
    try:
        hkey = registry.hkeys[local_hive]
    except KeyError:
        raise CommandExecutionError("Invalid Hive: {0}".format(local_hive))
    key_path = local_key
    access_mask = registry.registry_32[
        use_32bit_registry] | win32con.KEY_ALL_ACCESS

    if not key_exists(local_hive, local_key, use_32bit_registry):
        log.debug('"%s\\%s" not found', hive, key)
        return False

    if (len(key) > 1) and (key.count("\\", 1) <
                           registry.subkey_slash_check[hkey]):
        log.error('"%s\\%s" is too close to root, not safe to remove', hive,
                  key)
        return False

    # Functions for traversing the registry tree
    def _subkeys(_key):
        """
        Enumerate keys
        """
        i = 0
        while True:
            try:
                subkey = win32api.RegEnumKey(_key, i)
                yield _to_mbcs(subkey)
                i += 1
            except win32api.error:
                break

    def _traverse_registry_tree(_hkey, _keypath, _ret, _access_mask):
        """
        Traverse the registry tree i.e. dive into the tree
        """
        _key = win32api.RegOpenKeyEx(_hkey, _keypath, 0, _access_mask)
        for subkeyname in _subkeys(_key):
            subkeypath = "{0}\\{1}".format(_keypath, subkeyname)
            _ret = _traverse_registry_tree(_hkey, subkeypath, _ret,
                                           access_mask)
            _ret.append(subkeypath)
        return _ret

    # Get a reverse list of registry keys to be deleted
    key_list = []
    key_list = _traverse_registry_tree(hkey, key_path, key_list, access_mask)
    # Add the top level key last, all subkeys must be deleted first
    key_list.append(key_path)

    ret = {"Deleted": [], "Failed": []}

    # Delete all sub_keys
    for sub_key_path in key_list:
        key_handle = None
        try:
            key_handle = win32api.RegOpenKeyEx(hkey, sub_key_path, 0,
                                               access_mask)
            try:
                win32api.RegDeleteKey(key_handle, "")
                ret["Deleted"].append(r"{0}\{1}".format(hive, sub_key_path))
            except WindowsError as exc:  # pylint: disable=undefined-variable
                log.error(exc, exc_info=True)
                ret["Failed"].append(r"{0}\{1} {2}".format(
                    hive, sub_key_path, exc))
        except win32api.error as exc:
            log.error(exc, exc_info=True)
            ret["Failed"].append(r"{0}\{1} {2}".format(hive, sub_key_path,
                                                       exc.strerror))
        finally:
            if key_handle:
                win32api.CloseHandle(key_handle)

    broadcast_change()

    return ret
Пример #2
0
def mod_repo(repo, **kwargs):
    '''
    Modify one or more values for a repo.  If the repo does not exist, it will
    be created, so long as uri is defined.

    The following options are available to modify a repo definition:

    repo
        alias by which opkg refers to the repo.
    uri
        the URI to the repo.
    compressed
        defines (True or False) if the index file is compressed
    enabled
        enable or disable (True or False) repository
        but do not remove if disabled.
    refresh
        enable or disable (True or False) auto-refresh of the repositories

    CLI Examples:

    .. code-block:: bash

        salt '*' pkg.mod_repo repo uri=http://new/uri
        salt '*' pkg.mod_repo repo enabled=False
    '''
    repos = list_repos()
    found = False
    uri = ''
    if 'uri' in kwargs:
        uri = kwargs['uri']

    for repository in repos:
        source = repos[repository][0]
        if source['name'] == repo:
            found = True
            repostr = ''
            if 'enabled' in kwargs and not kwargs['enabled']:
                repostr += '# '
            if 'compressed' in kwargs:
                repostr += 'src/gz ' if kwargs['compressed'] else 'src'
            else:
                repostr += 'src/gz' if source['compressed'] else 'src'
            repo_alias = kwargs['alias'] if 'alias' in kwargs else repo
            if ' ' in repo_alias:
                repostr += ' "{0}"'.format(repo_alias)
            else:
                repostr += ' {0}'.format(repo_alias)
            repostr += ' {0}'.format(kwargs['uri'] if 'uri' in kwargs else source['uri'])
            _mod_repo_in_file(repo, repostr, source['file'])
        elif uri and source['uri'] == uri:
            raise CommandExecutionError(
                'Repository \'{0}\' already exists as \'{1}\'.'.format(uri, source['name']))

    if not found:
        # Need to add a new repo
        if 'uri' not in kwargs:
            raise CommandExecutionError(
                'Repository \'{0}\' not found and no URI passed to create one.'.format(repo))
        # If compressed is not defined, assume True
        compressed = kwargs['compressed'] if 'compressed' in kwargs else True
        # If enabled is not defined, assume True
        enabled = kwargs['enabled'] if 'enabled' in kwargs else True
        _add_new_repo(repo, kwargs['uri'], compressed, enabled)

    if 'refresh' in kwargs:
        refresh_db()
Пример #3
0
def install(name=None,
            refresh=False,
            pkgs=None,
            sources=None,
            reinstall=False,
            **kwargs):
    '''
    Install the passed package, add refresh=True to update the opkg database.

    name
        The name of the package to be installed. Note that this parameter is
        ignored if either "pkgs" or "sources" is passed. 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.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install <package name>

    refresh
        Whether or not to refresh the package database before installing.

    version
        Install a specific version of the package, e.g. 1.2.3~0ubuntu0. Ignored
        if "pkgs" or "sources" is passed.

        .. versionadded:: 2017.7.0

    reinstall : False
        Specifying reinstall=True will use ``opkg install --force-reinstall``
        rather than simply ``opkg install`` for requested packages that are
        already installed.

        If a version is specified with the requested package, then ``opkg
        install --force-reinstall`` will only be used if the installed version
        matches the requested version.

        .. versionadded:: 2017.7.0


    Multiple Package Installation Options:

    pkgs
        A list of packages to install from a software repository. Must be
        passed as a python list.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install pkgs='["foo", "bar"]'
            salt '*' pkg.install pkgs='["foo", {"bar": "1.2.3-0ubuntu0"}]'

    sources
        A list of IPK packages to install. Must be passed as a list of dicts,
        with the keys being package names, and the values being the source URI
        or local path to the package.  Dependencies are automatically resolved
        and marked as auto-installed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sources='[{"foo": "salt://foo.deb"},{"bar": "salt://bar.deb"}]'

    install_recommends
        Whether to install the packages marked as recommended. Default is True.

    only_upgrade
        Only upgrade the packages (disallow downgrades), if they are already
        installed. Default is False.

        .. versionadded:: 2017.7.0

    always_restart_services
        Whether to restart services even if a reboot is required. Default is True.

    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}
    '''
    refreshdb = salt.utils.data.is_true(refresh)

    try:
        pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](
            name, pkgs, sources, **kwargs
        )
    except MinionError as exc:
        raise CommandExecutionError(exc)

    old = list_pkgs()
    cmd_prefix = ['opkg', 'install']
    to_install = []
    to_reinstall = []
    to_downgrade = []

    _append_noaction_if_testmode(cmd_prefix, **kwargs)
    if not pkg_params:
        return {}
    elif pkg_type == 'file':
        if reinstall:
            cmd_prefix.append('--force-reinstall')
        if not kwargs.get('only_upgrade', False):
            cmd_prefix.append('--force-downgrade')
        to_install.extend(pkg_params)
    elif pkg_type == 'repository':
        if not kwargs.get('install_recommends', True):
            cmd_prefix.append('--no-install-recommends')
        for pkgname, pkgversion in six.iteritems(pkg_params):
            if (name and pkgs is None and kwargs.get('version') and
                    len(pkg_params) == 1):
                # Only use the 'version' param if 'name' was not specified as a
                # comma-separated list
                version_num = kwargs['version']
            else:
                version_num = pkgversion

            if version_num is None:
                # Don't allow downgrades if the version
                # number is not specified.
                if reinstall and pkgname in old:
                    to_reinstall.append(pkgname)
                else:
                    to_install.append(pkgname)
            else:
                pkgstr = '{0}={1}'.format(pkgname, version_num)
                cver = old.get(pkgname, '')
                if reinstall and cver and salt.utils.versions.compare(
                        ver1=version_num,
                        oper='==',
                        ver2=cver,
                        cmp_func=version_cmp):
                    to_reinstall.append(pkgstr)
                elif not cver or salt.utils.versions.compare(
                        ver1=version_num,
                        oper='>=',
                        ver2=cver,
                        cmp_func=version_cmp):
                    to_install.append(pkgstr)
                else:
                    if not kwargs.get('only_upgrade', False):
                        to_downgrade.append(pkgstr)
                    else:
                        # This should cause the command to fail.
                        to_install.append(pkgstr)

    cmds = _build_install_command_list(cmd_prefix, to_install, to_downgrade, to_reinstall)

    if not cmds:
        return {}

    if refreshdb:
        refresh_db()

    errors = []
    is_testmode = _is_testmode(**kwargs)
    test_packages = {}
    for cmd in cmds:
        _execute_install_command(cmd, is_testmode, errors, test_packages)

    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()
    if is_testmode:
        new = copy.deepcopy(new)
        new.update(test_packages)

    ret = salt.utils.data.compare_dicts(old, new)

    if pkg_type == 'file' and reinstall:
        # For file-based packages, prepare 'to_reinstall' to have a list
        # of all the package names that may have been reinstalled.
        # This way, we could include reinstalled packages in 'ret'.
        for pkgfile in to_install:
            # Convert from file name to package name.
            cmd = ['opkg', 'info', pkgfile]
            out = __salt__['cmd.run_all'](
                cmd,
                output_loglevel='trace',
                python_shell=False
            )
            if out['retcode'] == 0:
                # Just need the package name.
                pkginfo_dict = _process_info_installed_output(
                    out['stdout'], []
                )
                if pkginfo_dict:
                    to_reinstall.append(list(pkginfo_dict.keys())[0])

    for pkgname in to_reinstall:
        if pkgname not in ret or pkgname in old:
            ret.update({pkgname: {'old': old.get(pkgname, ''),
                                  'new': new.get(pkgname, '')}})

    rs_result = _get_restartcheck_result(errors)

    if errors:
        raise CommandExecutionError(
            'Problem encountered installing package(s)',
            info={'errors': errors, 'changes': ret}
        )

    _process_restartcheck_result(rs_result, **kwargs)

    return ret
Пример #4
0
def persist(name, value, config=None):
    """
    Assign and persist a simple sysctl parameter for this minion. If ``config``
    is not specified, a sensible default will be chosen using
    :mod:`sysctl.default_config <salt.modules.linux_sysctl.default_config>`.

    CLI Example:

    .. code-block:: bash

        salt '*' sysctl.persist net.ipv4.ip_forward 1
    """
    if config is None:
        config = default_config()
    edited = False
    # If the sysctl.conf is not present, add it
    if not os.path.isfile(config):
        sysctl_dir = os.path.dirname(config)
        if not os.path.exists(sysctl_dir):
            os.makedirs(sysctl_dir)
        try:
            with salt.utils.files.fopen(config, "w+") as _fh:
                _fh.write("#\n# Kernel sysctl configuration\n#\n")
        except (IOError, OSError):
            msg = "Could not write to file: {0}"
            raise CommandExecutionError(msg.format(config))

    # Read the existing sysctl.conf
    nlines = []
    try:
        with salt.utils.files.fopen(config, "r") as _fh:
            # Use readlines because this should be a small file
            # and it seems unnecessary to indent the below for
            # loop since it is a fairly large block of code.
            config_data = salt.utils.data.decode(_fh.readlines())
    except (IOError, OSError):
        msg = "Could not read from file: {0}"
        raise CommandExecutionError(msg.format(config))

    for line in config_data:
        if line.startswith("#"):
            nlines.append(line)
            continue
        if "=" not in line:
            nlines.append(line)
            continue

        # Strip trailing whitespace and split the k,v
        comps = [i.strip() for i in line.split("=", 1)]

        # On Linux procfs, files such as /proc/sys/net/ipv4/tcp_rmem or any
        # other sysctl with whitespace in it consistently uses 1 tab.  Lets
        # allow our users to put a space or tab between multi-value sysctls
        # and have salt not try to set it every single time.
        if isinstance(comps[1], string_types) and " " in comps[1]:
            comps[1] = re.sub(r"\s+", "\t", comps[1])

        # Do the same thing for the value 'just in case'
        if isinstance(value, string_types) and " " in value:
            value = re.sub(r"\s+", "\t", value)

        if len(comps) < 2:
            nlines.append(line)
            continue
        if name == comps[0]:
            # This is the line to edit
            if six.text_type(comps[1]) == six.text_type(value):
                # It is correct in the config, check if it is correct in /proc
                if six.text_type(get(name)) != six.text_type(value):
                    assign(name, value)
                    return "Updated"
                else:
                    return "Already set"

            nlines.append("{0} = {1}\n".format(name, value))
            edited = True
            continue
        else:
            nlines.append(line)
    if not edited:
        nlines.append("{0} = {1}\n".format(name, value))
    try:
        with salt.utils.files.fopen(config, "wb") as _fh:
            _fh.writelines(salt.utils.data.encode(nlines))
    except (IOError, OSError):
        msg = "Could not write to file: {0}"
        raise CommandExecutionError(msg.format(config))

    assign(name, value)
    return "Updated"
Пример #5
0
def gen_locale(locale, **kwargs):
    '''
    Generate a locale. Options:

    .. versionadded:: 2014.7.0

    :param locale: Any locale listed in /usr/share/i18n/locales or
        /usr/share/i18n/SUPPORTED for Debian and Gentoo based distributions,
        which require the charmap to be specified as part of the locale
        when generating it.

    verbose
        Show extra warnings about errors that are normally ignored.

    CLI Example:

    .. code-block:: bash

        salt '*' locale.gen_locale en_US.UTF-8
        salt '*' locale.gen_locale 'en_IE.UTF-8 UTF-8'    # Debian/Gentoo only
    '''
    on_debian = __grains__.get('os') == 'Debian'
    on_ubuntu = __grains__.get('os') == 'Ubuntu'
    on_gentoo = __grains__.get('os_family') == 'Gentoo'
    on_suse = __grains__.get('os_family') == 'Suse'
    on_solaris = __grains__.get('os_family') == 'Solaris'

    if on_solaris:  # all locales are pre-generated
        return locale in __salt__['locale.list_avail']()

    locale_info = salt.utils.locales.split_locale(locale)

    # if the charmap has not been supplied, normalize by appening it
    if not locale_info['charmap'] and not on_ubuntu:
        locale_info['charmap'] = locale_info['codeset']
        locale = salt.utils.locales.join_locale(locale_info)

    if on_debian or on_gentoo:  # file-based search
        search = '/usr/share/i18n/SUPPORTED'
        valid = __salt__['file.search'](search,
                                        '^{0}$'.format(locale),
                                        flags=re.MULTILINE)
    else:  # directory-based search
        if on_suse:
            search = '/usr/share/locale'
        else:
            search = '/usr/share/i18n/locales'
        try:
            valid = "{0}_{1}".format(
                locale_info['language'],
                locale_info['territory']) in os.listdir(search)
        except OSError as ex:
            log.error(ex)
            raise CommandExecutionError(
                "Locale \"{0}\" is not available.".format(locale))

    if not valid:
        log.error('The provided locale "{0}" is not found in {1}'.format(
            locale, search))
        return False

    if os.path.exists('/etc/locale.gen'):
        __salt__['file.replace']('/etc/locale.gen',
                                 r'^\s*#\s*{0}\s*$'.format(locale),
                                 '{0}\n'.format(locale),
                                 append_if_not_found=True)
    elif on_ubuntu:
        __salt__['file.touch']('/var/lib/locales/supported.d/{0}'.format(
            locale_info['language']))
        __salt__['file.replace']('/var/lib/locales/supported.d/{0}'.format(
            locale_info['language']),
                                 locale,
                                 locale,
                                 append_if_not_found=True)

    if salt.utils.which("locale-gen") is not None:
        cmd = ['locale-gen']
        if on_gentoo:
            cmd.append('--generate')
        if on_ubuntu:
            cmd.append(salt.utils.locales.normalize_locale(locale))
        else:
            cmd.append(locale)
    elif salt.utils.which("localedef") is not None:
        cmd = [
            'localedef', '--force', '-i',
            "{0}_{1}".format(locale_info['language'],
                             locale_info['territory']), '-f',
            locale_info['codeset'],
            '{0}_{1}.{2}'.format(locale_info['language'],
                                 locale_info['territory'],
                                 locale_info['codeset'])
        ]
        cmd.append(kwargs.get('verbose', False) and '--verbose' or '--quiet')
    else:
        raise CommandExecutionError(
            'Command "locale-gen" or "localedef" was not found on this system.'
        )

    res = __salt__['cmd.run_all'](cmd)
    if res['retcode']:
        log.error(res['stderr'])

    if kwargs.get('verbose'):
        return res
    else:
        return res['retcode'] == 0
Пример #6
0
def upgrade(refresh=True, binhost=None, backtrack=3):
    """
    .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
        On minions running systemd>=205, `systemd-run(1)`_ is now used to
        isolate commands which modify installed packages from the
        ``salt-minion`` daemon's control group. This is done to keep systemd
        from killing any emerge commands spawned by Salt when the
        ``salt-minion`` service is restarted. (see ``KillMode`` in the
        `systemd.kill(5)`_ manpage for more information). If desired, usage of
        `systemd-run(1)`_ can be suppressed by setting a :mod:`config option
        <salt.modules.config.get>` called ``systemd.scope``, with a value of
        ``False`` (no quotes).

    .. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
    .. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html

    Run a full system upgrade (emerge -uDN @world)

    binhost
        has two options try and force.
        try - tells emerge to try and install the package from a configured binhost.
        force - forces emerge to install the package from a binhost otherwise it fails out.

    backtrack
        Specifies an integer number of times to backtrack if dependency
        calculation fails due to a conflict or an unsatisfied dependency
        (default: ´3´).

        .. versionadded: 2015.8.0

    Returns a dictionary containing the changes:

    .. code-block:: python

        {'<package>':  {'old': '<old-version>',
                        'new': '<new-version>'}}


    CLI Example:

    .. code-block:: bash

        salt '*' pkg.upgrade
    """
    ret = {"changes": {}, "result": True, "comment": ""}

    if salt.utils.data.is_true(refresh):
        refresh_db()

    if binhost == "try":
        bin_opts = ["--getbinpkg"]
    elif binhost == "force":
        bin_opts = ["--getbinpkgonly"]
    else:
        bin_opts = []

    old = list_pkgs()
    cmd = []
    if salt.utils.systemd.has_scope(__context__) and __salt__["config.get"](
            "systemd.scope", True):
        cmd.extend(["systemd-run", "--scope"])
    cmd.extend([
        "emerge",
        "--ask",
        "n",
        "--quiet",
        "--backtrack",
        "{0}".format(backtrack),
        "--update",
        "--newuse",
        "--deep",
    ])
    if bin_opts:
        cmd.extend(bin_opts)
    cmd.append("@world")

    result = __salt__["cmd.run_all"](cmd,
                                     output_loglevel="trace",
                                     python_shell=False)
    __context__.pop("pkg.list_pkgs", None)
    new = list_pkgs()
    ret = salt.utils.data.compare_dicts(old, new)

    if result["retcode"] != 0:
        raise CommandExecutionError(
            "Problem encountered upgrading packages",
            info={
                "changes": ret,
                "result": result
            },
        )

    return ret
Пример #7
0
def install(name=None,
            refresh=False,
            sysupgrade=False,
            pkgs=None,
            sources=None,
            **kwargs):
    '''
    .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
        On minions running systemd>=205, `systemd-run(1)`_ is now used to
        isolate commands which modify installed packages from the
        ``salt-minion`` daemon's control group. This is done to keep systemd
        from killing any pacman commands spawned by Salt when the
        ``salt-minion`` service is restarted. (see ``KillMode`` in the
        `systemd.kill(5)`_ manpage for more information). If desired, usage of
        `systemd-run(1)`_ can be suppressed by setting a :mod:`config option
        <salt.modules.config.get>` called ``systemd.scope``, with a value of
        ``False`` (no quotes).

    .. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
    .. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html

    Install (``pacman -S``) the specified packag(s). Add ``refresh=True`` to
    install with ``-y``, add ``sysupgrade=True`` to install with ``-u``.

    name
        The name of the package to be installed. Note that this parameter is
        ignored if either ``pkgs`` or ``sources`` is passed. 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.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install <package name>

    refresh
        Whether or not to refresh the package database before installing.

    sysupgrade
        Whether or not to upgrade the system packages before installing.


    Multiple Package Installation Options:

    pkgs
        A list of packages to install from a software repository. Must be
        passed as a python list. A specific version number can be specified
        by using a single-element dict representing the package and its
        version. As with the ``version`` parameter above, comparison operators
        can be used to target a specific version of a package.

        CLI Examples:

        .. code-block:: bash

            salt '*' pkg.install pkgs='["foo", "bar"]'
            salt '*' pkg.install pkgs='["foo", {"bar": "1.2.3-4"}]'
            salt '*' pkg.install pkgs='["foo", {"bar": "<1.2.3-4"}]'

    sources
        A list of packages to install. Must be passed as a list of dicts,
        with the keys being package names, and the values being the source URI
        or local path to the package.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install \
                sources='[{"foo": "salt://foo.pkg.tar.xz"}, \
                {"bar": "salt://bar.pkg.tar.xz"}]'


    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}
    '''
    try:
        pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](
            name, pkgs, sources, **kwargs
        )
    except MinionError as exc:
        raise CommandExecutionError(exc)

    if pkg_params is None or len(pkg_params) == 0:
        return {}

    version_num = kwargs.get('version')
    if version_num:
        if pkgs is None and sources is None:
            # Allow "version" to work for single package target
            pkg_params = {name: version_num}
        else:
            log.warning('\'version\' parameter will be ignored for multiple '
                        'package targets')

    cmd = []
    if salt.utils.systemd.has_scope(__context__) \
            and __salt__['config.get']('systemd.scope', True):
        cmd.extend(['systemd-run', '--scope'])
    cmd.append('pacman')

    if pkg_type == 'file':
        cmd.extend(['-U', '--noprogressbar', '--noconfirm'])
        cmd.extend(pkg_params)
    elif pkg_type == 'repository':
        cmd.append('-S')
        if salt.utils.is_true(refresh):
            cmd.append('-y')
        if salt.utils.is_true(sysupgrade):
            cmd.append('-u')
        cmd.extend(['--noprogressbar', '--noconfirm', '--needed'])
        targets = []
        problems = []
        for param, version_num in six.iteritems(pkg_params):
            if version_num is None:
                targets.append(param)
            else:
                match = re.match('^([<>])?(=)?([^<>=]+)$', version_num)
                if match:
                    gt_lt, eq, verstr = match.groups()
                    prefix = gt_lt or ''
                    prefix += eq or ''
                    # If no prefix characters were supplied, use '='
                    prefix = prefix or '='
                    targets.append('{0}{1}{2}'.format(param, prefix, verstr))
                else:
                    msg = ('Invalid version string \'{0}\' for package '
                           '\'{1}\''.format(version_num, name))
                    problems.append(msg)
        if problems:
            for problem in problems:
                log.error(problem)
            return {}

        cmd.extend(targets)

    old = list_pkgs()
    __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False)
    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()
    return salt.utils.compare_dicts(old, new)
Пример #8
0
def bootstrap(force=False):
    '''
    Download and install the latest version of the Chocolatey package manager
    via the official bootstrap.

    Chocolatey requires Windows PowerShell and the .NET v4.0 runtime. Depending
    on the host's version of Windows, chocolatey.bootstrap will attempt to
    ensure these prerequisites are met by downloading and executing the
    appropriate installers from Microsoft.

    Note that if PowerShell is installed, you may have to restart the host
    machine for Chocolatey to work.

    force
        Run the bootstrap process even if Chocolatey is found in the path.

    CLI Example:

    .. code-block:: bash

        salt '*' chocolatey.bootstrap
        salt '*' chocolatey.bootstrap force=True
    '''
    # Check if Chocolatey is already present in the path
    try:
        choc_path = _find_chocolatey(__context__, __salt__)
    except CommandExecutionError:
        choc_path = None
    if choc_path and not force:
        return 'Chocolatey found at {0}'.format(choc_path)

    # The following lookup tables are required to determine the correct
    # download required to install PowerShell. That's right, there's more
    # than one! You're welcome.
    ps_downloads = {
        ('Vista', 'x86'):
        'http://download.microsoft.com/download/A/7/5/A75BC017-63CE-47D6-8FA4-AFB5C21BAC54/Windows6.0-KB968930-x86.msu',
        ('Vista', 'AMD64'):
        'http://download.microsoft.com/download/3/C/8/3C8CF51E-1D9D-4DAA-AAEA-5C48D1CD055C/Windows6.0-KB968930-x64.msu',
        ('2008Server', 'x86'):
        'http://download.microsoft.com/download/F/9/E/F9EF6ACB-2BA8-4845-9C10-85FC4A69B207/Windows6.0-KB968930-x86.msu',
        ('2008Server', 'AMD64'):
        'http://download.microsoft.com/download/2/8/6/28686477-3242-4E96-9009-30B16BED89AF/Windows6.0-KB968930-x64.msu'
    }

    # It took until .NET v4.0 for Microsoft got the hang of making installers,
    # this should work under any version of Windows
    net4_url = 'http://download.microsoft.com/download/1/B/E/1BE39E79-7E39-46A3-96FF-047F95396215/dotNetFx40_Full_setup.exe'

    temp_dir = tempfile.gettempdir()

    # Check if PowerShell is installed. This should be the case for every
    # Windows release following Server 2008.
    ps_path = 'C:\\Windows\\SYSTEM32\\WindowsPowerShell\\v1.0\\powershell.exe'

    if not __salt__['cmd.has_exec'](ps_path):
        if (__grains__['osrelease'], __grains__['cpuarch']) in ps_downloads:
            # Install the appropriate release of PowerShell v2.0
            url = ps_downloads[(__grains__['osrelease'],
                                __grains__['cpuarch'])]
            dest = os.path.join(temp_dir, 'powershell.exe')
            __salt__['cp.get_url'](url, dest)
            cmd = [dest, '/quiet', '/norestart']
            result = __salt__['cmd.run_all'](cmd, python_shell=False)
            if result['retcode'] != 0:
                err = ('Installing Windows PowerShell failed. Please run the '
                       'installer GUI on the host to get a more specific '
                       'reason.')
                log.error(err)
                raise CommandExecutionError(err)
        else:
            err = 'Windows PowerShell not found'
            log.error(err)
            raise CommandNotFoundError(err)

    # Run the .NET Framework 4 web installer
    dest = os.path.join(temp_dir, 'dotnet4.exe')
    __salt__['cp.get_url'](net4_url, dest)
    cmd = [dest, '/q', '/norestart']
    result = __salt__['cmd.run_all'](cmd, python_shell=False)
    if result['retcode'] != 0:
        err = ('Installing .NET v4.0 failed. Please run the installer GUI on '
               'the host to get a more specific reason.')
        log.error(err)
        raise CommandExecutionError(err)

    # Run the Chocolatey bootstrap.
    cmd = ('{0} -NoProfile -ExecutionPolicy unrestricted '
           '-Command "iex ((new-object net.webclient).'
           'DownloadString(\'https://chocolatey.org/install.ps1\'))" '
           '&& SET PATH=%PATH%;%systemdrive%\\chocolatey\\bin'.format(ps_path))
    result = __salt__['cmd.run_all'](cmd, python_shell=True)

    if result['retcode'] != 0:
        err = 'Bootstrapping Chocolatey failed: {0}'.format(result['stderr'])
        log.error(err)
        raise CommandExecutionError(err)

    return result['stdout']
Пример #9
0
def list_(narrow=None,
          all_versions=False,
          pre_versions=False,
          source=None,
          local_only=False):
    '''
    Instructs Chocolatey to pull a vague package list from the repository.

    narrow
        Term used to narrow down results. Searches against name/description/tag.

    all_versions
        Display all available package versions in results. Defaults to False.

    pre_versions
        Display pre-release packages in results. Defaults to False.

    source
        Chocolatey repository (directory, share or remote URL feed) the package
        comes from. Defaults to the official Chocolatey feed.

    local_only
        Display packages only installed locally

    CLI Example:

    .. code-block:: bash

        salt '*' chocolatey.list <narrow>
        salt '*' chocolatey.list <narrow> all_versions=True
    '''
    choc_path = _find_chocolatey(__context__, __salt__)
    cmd = [choc_path, 'list']
    if narrow:
        cmd.append(narrow)
    if salt.utils.is_true(all_versions):
        cmd.append('-AllVersions')
    if salt.utils.is_true(pre_versions):
        cmd.append('-Prerelease')
    if source:
        cmd.extend(['-Source', source])
    if local_only:
        cmd.extend(['-localonly'])

    result = __salt__['cmd.run_all'](cmd, python_shell=False)

    if result['retcode'] != 0:
        err = 'Running chocolatey failed: {0}'.format(result['stderr'])
        log.error(err)
        raise CommandExecutionError(err)

    ret = {}
    pkg_re = re.compile(r'(\S+)\s+(\S+)')
    for line in result['stdout'].split('\n'):
        if line.startswith("No packages"):
            return ret
        for name, ver in pkg_re.findall(line):
            if name not in ret:
                ret[name] = []
            ret[name].append(ver)

    return ret
Пример #10
0
def install(name=None,
            refresh=False,
            fromrepo=None,
            pkgs=None,
            sources=None,
            **kwargs):
    '''
    Install the passed package(s), add refresh=True to run 'zypper refresh'
    before package is installed.

    name
        The name of the package to be installed. Note that this parameter is
        ignored if either "pkgs" or "sources" is passed. 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.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install <package name>

    refresh
        Whether or not to refresh the package database before installing.

    fromrepo
        Specify a package repository to install from.

    version
        Can be either a version number, or the combination of a comparison
        operator (<, >, <=, >=, =) and a version number (ex. '>1.2.3-4').
        This parameter is ignored if "pkgs" or "sources" is passed.


    Multiple Package Installation Options:

    pkgs
        A list of packages to install from a software repository. Must be
        passed as a python list. A specific version number can be specified
        by using a single-element dict representing the package and its
        version. As with the ``version`` parameter above, comparison operators
        can be used to target a specific version of a package.

        CLI Examples:

        .. code-block:: bash

            salt '*' pkg.install pkgs='["foo", "bar"]'
            salt '*' pkg.install pkgs='["foo", {"bar": "1.2.3-4"}]'
            salt '*' pkg.install pkgs='["foo", {"bar": "<1.2.3-4"}]'

    sources
        A list of RPM packages to install. Must be passed as a list of dicts,
        with the keys being package names, and the values being the source URI
        or local path to the package.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sources='[{"foo": "salt://foo.rpm"},{"bar": "salt://bar.rpm"}]'


    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}
    '''
    if salt.utils.is_true(refresh):
        refresh_db()

    try:
        pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](name,
                                                                      pkgs,
                                                                      sources,
                                                                      **kwargs)
    except MinionError as exc:
        raise CommandExecutionError(exc)

    if pkg_params is None or len(pkg_params) == 0:
        return {}

    version_num = kwargs.get('version')
    if version_num:
        if pkgs is None and sources is None:
            # Allow "version" to work for single package target
            pkg_params = {name: version_num}
        else:
            log.warning('"version" parameter will be ignored for multiple '
                        'package targets')

    if pkg_type == 'repository':
        targets = []
        problems = []
        for param, version_num in pkg_params.iteritems():
            if version_num is None:
                targets.append(param)
            else:
                match = re.match('^([<>])?(=)?([^<>=]+)$', version_num)
                if match:
                    gt_lt, eq, verstr = match.groups()
                    prefix = gt_lt or ''
                    prefix += eq or ''
                    # If no prefix characters were supplied, use '='
                    prefix = prefix or '='
                    targets.append('{0}{1}{2}'.format(param, prefix, verstr))
                    log.debug(targets)
                else:
                    msg = ('Invalid version string {0!r} for package '
                           '{1!r}'.format(version_num, name))
                    problems.append(msg)
        if problems:
            for problem in problems:
                log.error(problem)
            return {}
    else:
        targets = pkg_params

    old = list_pkgs()
    downgrades = []
    if fromrepo:
        fromrepoopt = "--force --force-resolution --from {0} ".format(fromrepo)
        log.info('Targeting repo {0!r}'.format(fromrepo))
    else:
        fromrepoopt = ""
    # Split the targets into batches of 500 packages each, so that
    # the maximal length of the command line is not broken
    while targets:
        # Quotes needed around package targets because of the possibility of
        # output redirection characters "<" or ">" in zypper command.
        cmd = ('zypper --non-interactive install --name '
               '--auto-agree-with-licenses {0}"{1}"'.format(
                   fromrepoopt, '" "'.join(targets[:500])))
        targets = targets[500:]
        out = __salt__['cmd.run'](cmd, output_loglevel='trace')
        for line in out.splitlines():
            match = re.match(
                "^The selected package '([^']+)'.+has lower version", line)
            if match:
                downgrades.append(match.group(1))

    while downgrades:
        cmd = ('zypper --non-interactive install --name '
               '--auto-agree-with-licenses --force {0}{1}'.format(
                   fromrepoopt, ' '.join(downgrades[:500])))
        __salt__['cmd.run'](cmd, output_loglevel='trace')
        downgrades = downgrades[500:]
    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()
    return salt.utils.compare_dicts(old, new)
Пример #11
0
def add(name,
        uid=None,
        gid=None,
        groups=None,
        home=None,
        shell=None,
        fullname=None,
        createhome=True,
        **kwargs):
    '''
    Add a user to the minion

    CLI Example:

    .. code-block:: bash

        salt '*' user.add name <uid> <gid> <groups> <home> <shell>
    '''
    if info(name):
        raise CommandExecutionError('User {0!r} already exists'.format(name))

    if salt.utils.contains_whitespace(name):
        raise SaltInvocationError('Username cannot contain whitespace')

    if uid is None:
        uid = _first_avail_uid()
    if gid is None:
        gid = 20  # gid 20 == 'staff', the default group
    if home is None:
        home = '/Users/{0}'.format(name)
    if shell is None:
        shell = '/bin/bash'
    if fullname is None:
        fullname = ''
    # TODO: do createhome as well

    if not isinstance(uid, int):
        raise SaltInvocationError('uid must be an integer')
    if not isinstance(gid, int):
        raise SaltInvocationError('gid must be an integer')

    _dscl('/Users/{0} UniqueID {1!r}'.format(_cmd_quote(name), uid))
    _dscl('/Users/{0} PrimaryGroupID {1!r}'.format(_cmd_quote(name), gid))
    _dscl('/Users/{0} UserShell {1!r}'.format(_cmd_quote(name),
                                              _cmd_quote(shell)))
    _dscl('/Users/{0} NFSHomeDirectory {1!r}'.format(_cmd_quote(name),
                                                     _cmd_quote(home)))
    _dscl('/Users/{0} RealName {1!r}'.format(_cmd_quote(name),
                                             _cmd_quote(fullname)))

    # Set random password, since without a password the account will not be
    # available. TODO: add shadow module
    randpass = ''.join(random.SystemRandom().choice(string.letters +
                                                    string.digits)
                       for x in range(20))
    _dscl('/Users/{0} {1!r}'.format(_cmd_quote(name), _cmd_quote(randpass)),
          ctype='passwd')

    # dscl buffers changes, sleep before setting group membership
    time.sleep(1)
    if groups:
        chgroups(name, groups)
    return True
Пример #12
0
def query(key, keyid, method='GET', params=None, headers=None,
          requesturl=None, return_url=False, bucket=None, service_url=None,
          path='', return_bin=False, action=None, local_file=None,
          verify_ssl=True, full_headers=False, kms_keyid=None,
          location=None, role_arn=None, chunk_size=16384, path_style=False,
          https_enable=True):
    '''
    Perform a query against an S3-like API. This function requires that a
    secret key and the id for that key are passed in. For instance:

        s3.keyid: GKTADJGHEIQSXMKKRBJ08H
        s3.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs

    If keyid or key is not specified, an attempt to fetch them from EC2 IAM
    metadata service will be made.

    A service_url may also be specified in the configuration:

        s3.service_url: s3.amazonaws.com

    If a service_url is not specified, the default is s3.amazonaws.com. This
    may appear in various documentation as an "endpoint". A comprehensive list
    for Amazon S3 may be found at::

        http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region

    The service_url will form the basis for the final endpoint that is used to
    query the service.

    Path style can be enabled:

        s3.path_style: True

    This can be useful if you need to use salt with a proxy for an s3 compatible storage

    You can use either https protocol or http protocol:

        s3.https_enable: True

    SSL verification may also be turned off in the configuration:

        s3.verify_ssl: False

    This is required if using S3 bucket names that contain a period, as
    these will not match Amazon's S3 wildcard certificates. Certificate
    verification is enabled by default.

    A region may be specified:

        s3.location: eu-central-1

    If region is not specified, an attempt to fetch the region from EC2 IAM
    metadata service will be made. Failing that, default is us-east-1
    '''
    if not HAS_REQUESTS:
        log.error('There was an error: requests is required for s3 access')

    if not headers:
        headers = {}

    if not params:
        params = {}

    if not service_url:
        service_url = 's3.amazonaws.com'

    if not bucket or path_style:
        endpoint = service_url
    else:
        endpoint = '{0}.{1}'.format(bucket, service_url)

    if path_style and bucket:
        path = '{0}/{1}'.format(bucket, path)

    # Try grabbing the credentials from the EC2 instance IAM metadata if available
    if not key:
        key = salt.utils.aws.IROLE_CODE

    if not keyid:
        keyid = salt.utils.aws.IROLE_CODE

    if kms_keyid is not None and method in ('PUT', 'POST'):
        headers['x-amz-server-side-encryption'] = 'aws:kms'
        headers['x-amz-server-side-encryption-aws-kms-key-id'] = kms_keyid

    if not location:
        location = salt.utils.aws.get_location()

    data = ''
    fh = None
    payload_hash = None
    if method == 'PUT':
        if local_file:
            payload_hash = salt.utils.hashutils.get_hash(local_file, form='sha256')

    if path is None:
        path = ''
    path = _quote(path)

    if not requesturl:
        requesturl = (('https' if https_enable else 'http')+'://{0}/{1}').format(endpoint, path)
        headers, requesturl = salt.utils.aws.sig4(
            method,
            endpoint,
            params,
            data=data,
            uri='/{0}'.format(path),
            prov_dict={'id': keyid, 'key': key},
            role_arn=role_arn,
            location=location,
            product='s3',
            requesturl=requesturl,
            headers=headers,
            payload_hash=payload_hash,
        )

    log.debug('S3 Request: %s', requesturl)
    log.debug('S3 Headers::')
    log.debug('    Authorization: %s', headers['Authorization'])

    if not data:
        data = None

    try:
        if method == 'PUT':
            if local_file:
                fh = salt.utils.files.fopen(local_file, 'rb')  # pylint: disable=resource-leakage
                data = fh.read()  # pylint: disable=resource-leakage
            result = requests.request(method,
                                      requesturl,
                                      headers=headers,
                                      data=data,
                                      verify=verify_ssl,
                                      stream=True)
        elif method == 'GET' and local_file and not return_bin:
            result = requests.request(method,
                                      requesturl,
                                      headers=headers,
                                      data=data,
                                      verify=verify_ssl,
                                      stream=True)
        else:
            result = requests.request(method,
                                      requesturl,
                                      headers=headers,
                                      data=data,
                                      verify=verify_ssl)
    finally:
        if fh is not None:
            fh.close()

    err_code = None
    err_msg = None
    if result.status_code >= 400:
        # On error the S3 API response should contain error message
        err_text = result.content or 'Unknown error'
        log.debug('    Response content: %s', err_text)

        # Try to get err info from response xml
        try:
            err_data = xml.to_dict(ET.fromstring(err_text))
            err_code = err_data['Code']
            err_msg = err_data['Message']
        except (KeyError, ET.ParseError) as err:
            log.debug(
                'Failed to parse s3 err response. %s: %s',
                type(err).__name__, err
            )
            err_code = 'http-{0}'.format(result.status_code)
            err_msg = err_text

    log.debug('S3 Response Status Code: %s', result.status_code)

    if method == 'PUT':
        if result.status_code != 200:
            if local_file:
                raise CommandExecutionError(
                    'Failed to upload from {0} to {1}. {2}: {3}'.format(
                        local_file, path, err_code, err_msg))
            raise CommandExecutionError(
                'Failed to create bucket {0}. {1}: {2}'.format(
                    bucket, err_code, err_msg))

        if local_file:
            log.debug('Uploaded from %s to %s', local_file, path)
        else:
            log.debug('Created bucket %s', bucket)
        return

    if method == 'DELETE':
        if not six.text_type(result.status_code).startswith('2'):
            if path:
                raise CommandExecutionError(
                    'Failed to delete {0} from bucket {1}. {2}: {3}'.format(
                        path, bucket, err_code, err_msg))
            raise CommandExecutionError(
                'Failed to delete bucket {0}. {1}: {2}'.format(
                    bucket, err_code, err_msg))

        if path:
            log.debug('Deleted %s from bucket %s', path, bucket)
        else:
            log.debug('Deleted bucket %s', bucket)
        return

    # This can be used to save a binary object to disk
    if local_file and method == 'GET':
        if result.status_code < 200 or result.status_code >= 300:
            raise CommandExecutionError(
                'Failed to get file. {0}: {1}'.format(err_code, err_msg))

        log.debug('Saving to local file: %s', local_file)
        with salt.utils.files.fopen(local_file, 'wb') as out:
            for chunk in result.iter_content(chunk_size=chunk_size):
                out.write(chunk)
        return 'Saved to local file: {0}'.format(local_file)

    if result.status_code < 200 or result.status_code >= 300:
        raise CommandExecutionError(
            'Failed s3 operation. {0}: {1}'.format(err_code, err_msg))

    # This can be used to return a binary object wholesale
    if return_bin:
        return result.content

    if result.content:
        items = ET.fromstring(result.content)

        ret = []
        for item in items:
            ret.append(xml.to_dict(item))

        if return_url is True:
            return ret, requesturl
    else:
        if result.status_code != requests.codes.ok:
            return
        ret = {'headers': []}
        if full_headers:
            ret['headers'] = dict(result.headers)
        else:
            for header in result.headers:
                ret['headers'].append(header.strip())

    return ret
Пример #13
0
Файл: opkg.py Проект: vodik/salt
def install(name=None,
            refresh=False,
            pkgs=None,
            sources=None,
            **kwargs):
    '''
    Install the passed package, add refresh=True to update the opkg database.

    name
        The name of the package to be installed. Note that this parameter is
        ignored if either "pkgs" or "sources" is passed. 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.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install <package name>

    refresh
        Whether or not to refresh the package database before installing.


    Multiple Package Installation Options:

    pkgs
        A list of packages to install from a software repository. Must be
        passed as a python list.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install pkgs='["foo", "bar"]'

    sources
        A list of IPK packages to install. Must be passed as a list of dicts,
        with the keys being package names, and the values being the source URI
        or local path to the package.  Dependencies are automatically resolved
        and marked as auto-installed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sources='[{"foo": "salt://foo.deb"},{"bar": "salt://bar.deb"}]'

    install_recommends
        Whether to install the packages marked as recommended. Default is True.

    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}
    '''
    refreshdb = salt.utils.is_true(refresh)

    try:
        pkgs, pkg_type = __salt__['pkg_resource.parse_targets'](
            name, pkgs, sources, **kwargs
        )
    except MinionError as exc:
        raise CommandExecutionError(exc)

    old = list_pkgs()
    cmd = ['opkg', 'install']
    if pkgs is None or len(pkgs) == 0:
        return {}
    elif pkg_type == 'file':
        cmd.extend(pkgs)
    elif pkg_type == 'repository':
        targets = list(pkgs.keys())
        if 'install_recommends' in kwargs and not kwargs['install_recommends']:
            cmd.append('--no-install-recommends')
        cmd.extend(targets)

    if refreshdb:
        refresh_db()

    out = __salt__['cmd.run_all'](
        cmd,
        output_loglevel='trace',
        python_shell=False
    )

    if out['retcode'] != 0 and out['stderr']:
        errors = [out['stderr']]
    else:
        errors = []

    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()
    ret = salt.utils.compare_dicts(old, new)

    if errors:
        raise CommandExecutionError(
            'Problem encountered installing package(s)',
            info={'errors': errors, 'changes': ret}
        )

    return ret
Пример #14
0
def delete_value(hive, key, vname=None, use_32bit_registry=False):
    """
    Delete a registry value entry or the default value for a key.

    Args:

        hive (str):
            The name of the hive. Can be one of the following

                - HKEY_LOCAL_MACHINE or HKLM
                - HKEY_CURRENT_USER or HKCU
                - HKEY_USER or HKU
                - HKEY_CLASSES_ROOT or HKCR
                - HKEY_CURRENT_CONFIG or HKCC

        key (str):
            The key (looks like a path) to the value name.

        vname (str):
            The value name. These are the individual name/data pairs under the
            key. If not passed, the key (Default) value will be deleted.

        use_32bit_registry (bool):
            Deletes the 32bit portion of the registry on 64bit installations. On
            32bit machines this is ignored.

    Return:
        bool: True if successful, otherwise False

    Usage:

        .. code-block:: python

            import salt.utils.win_reg
            winreg.delete_value(hive='HKLM', key='SOFTWARE\\SaltTest', vname='version')
    """
    local_hive = _to_unicode(hive)
    local_key = _to_unicode(key)
    local_vname = _to_unicode(vname)

    registry = Registry()
    try:
        hkey = registry.hkeys[local_hive]
    except KeyError:
        raise CommandExecutionError("Invalid Hive: {0}".format(local_hive))
    access_mask = registry.registry_32[
        use_32bit_registry] | win32con.KEY_ALL_ACCESS

    handle = None
    try:
        handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
        win32api.RegDeleteValue(handle, local_vname)
        broadcast_change()
        return True
    except win32api.error as exc:
        if exc.winerror == 2:
            return None
        raise
    finally:
        if handle:
            win32api.RegCloseKey(handle)
Пример #15
0
def install(name=None,
            refresh=False,
            pkgs=None,
            sources=None,
            slot=None,
            fromrepo=None,
            uses=None,
            binhost=None,
            **kwargs):
    """
    .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
        On minions running systemd>=205, `systemd-run(1)`_ is now used to
        isolate commands which modify installed packages from the
        ``salt-minion`` daemon's control group. This is done to keep systemd
        from killing any emerge commands spawned by Salt when the
        ``salt-minion`` service is restarted. (see ``KillMode`` in the
        `systemd.kill(5)`_ manpage for more information). If desired, usage of
        `systemd-run(1)`_ can be suppressed by setting a :mod:`config option
        <salt.modules.config.get>` called ``systemd.scope``, with a value of
        ``False`` (no quotes).

    .. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
    .. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html

    Install the passed package(s), add refresh=True to sync the portage tree
    before package is installed.

    name
        The name of the package to be installed. Note that this parameter is
        ignored if either "pkgs" or "sources" is passed. Additionally, please
        note that this option can only be used to emerge a package from the
        portage tree. To install a tbz2 package manually, use the "sources"
        option described below.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install <package name>

    refresh
        Whether or not to sync the portage tree before installing.

    version
        Install a specific version of the package, e.g. 1.0.9-r1. Ignored
        if "pkgs" or "sources" is passed.

    slot
        Similar to version, but specifies a valid slot to be installed. It
        will install the latest available version in the specified slot.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sys-devel/gcc slot='4.4'

    fromrepo
        Similar to slot, but specifies the repository from the package will be
        installed. It will install the latest available version in the
        specified repository.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install salt fromrepo='gentoo'

    uses
        Similar to slot, but specifies a list of use flag.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sys-devel/gcc uses='["nptl","-nossp"]'


    Multiple Package Installation Options:

    pkgs
        A list of packages to install from the portage tree. Must be passed as
        a python list.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install pkgs='["foo","bar","~category/package:slot::repository[use]"]'

    sources
        A list of tbz2 packages to install. Must be passed as a list of dicts,
        with the keys being package names, and the values being the source URI
        or local path to the package.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sources='[{"foo": "salt://foo.tbz2"},{"bar": "salt://bar.tbz2"}]'
    binhost
        has two options try and force.
        try - tells emerge to try and install the package from a configured binhost.
        force - forces emerge to install the package from a binhost otherwise it fails out.

    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}
    """
    log.debug(
        "Called modules.pkg.install: %s",
        {
            "name": name,
            "refresh": refresh,
            "pkgs": pkgs,
            "sources": sources,
            "kwargs": kwargs,
            "binhost": binhost,
        },
    )
    if salt.utils.data.is_true(refresh):
        refresh_db()

    try:
        pkg_params, pkg_type = __salt__["pkg_resource.parse_targets"](name,
                                                                      pkgs,
                                                                      sources,
                                                                      **kwargs)
    except MinionError as exc:
        raise CommandExecutionError(exc)

    # Handle version kwarg for a single package target
    if pkgs is None and sources is None:
        version_num = kwargs.get("version")
        if not version_num:
            version_num = ""
            if slot is not None:
                version_num += ":{0}".format(slot)
            if fromrepo is not None:
                version_num += "::{0}".format(fromrepo)
            if uses is not None:
                version_num += "[{0}]".format(",".join(uses))
            pkg_params = {name: version_num}

    if not pkg_params:
        return {}
    elif pkg_type == "file":
        emerge_opts = ["tbz2file"]
    else:
        emerge_opts = []

    if binhost == "try":
        bin_opts = ["-g"]
    elif binhost == "force":
        bin_opts = ["-G"]
    else:
        bin_opts = []

    changes = {}

    if pkg_type == "repository":
        targets = list()
        for param, version_num in six.iteritems(pkg_params):
            original_param = param
            param = _p_to_cp(param)
            if param is None:
                raise portage.dep.InvalidAtom(original_param)

            if version_num is None:
                targets.append(param)
            else:
                keyword = None

                match = re.match("^(~)?([<>])?(=)?([^<>=]*)$", version_num)
                if match:
                    keyword, gt_lt, eq, verstr = match.groups()
                    prefix = gt_lt or ""
                    prefix += eq or ""
                    # If no prefix characters were supplied and verstr contains a version, use '='
                    if len(verstr
                           ) > 0 and verstr[0] != ":" and verstr[0] != "[":
                        prefix = prefix or "="
                        target = "{0}{1}-{2}".format(prefix, param, verstr)
                    else:
                        target = "{0}{1}".format(param, verstr)
                else:
                    target = "{0}".format(param)

                if "[" in target:
                    old = __salt__[
                        "portage_config.get_flags_from_package_conf"]("use",
                                                                      target)
                    __salt__["portage_config.append_use_flags"](target)
                    new = __salt__[
                        "portage_config.get_flags_from_package_conf"]("use",
                                                                      target)
                    if old != new:
                        changes[param + "-USE"] = {"old": old, "new": new}
                    target = target[:target.rfind("[")]

                if keyword is not None:
                    __salt__["portage_config.append_to_package_conf"](
                        "accept_keywords", target, ["~ARCH"])
                    changes[param + "-ACCEPT_KEYWORD"] = {
                        "old": "",
                        "new": "~ARCH"
                    }

                if not changes:
                    inst_v = version(param)

                    # Prevent latest_version from calling refresh_db. Either we
                    # just called it or we were asked not to.
                    if latest_version(param, refresh=False) == inst_v:
                        all_uses = __salt__[
                            "portage_config.get_cleared_flags"](param)
                        if _flags_changed(*all_uses):
                            changes[param] = {
                                "version": inst_v,
                                "old": {
                                    "use": all_uses[0]
                                },
                                "new": {
                                    "use": all_uses[1]
                                },
                            }
                targets.append(target)
    else:
        targets = pkg_params

    cmd = []
    if salt.utils.systemd.has_scope(__context__) and __salt__["config.get"](
            "systemd.scope", True):
        cmd.extend(["systemd-run", "--scope"])
    cmd.extend(["emerge", "--ask", "n", "--quiet"])
    cmd.extend(bin_opts)
    cmd.extend(emerge_opts)
    cmd.extend(targets)

    old = list_pkgs()
    call = __salt__["cmd.run_all"](cmd,
                                   output_loglevel="trace",
                                   python_shell=False)
    if call["retcode"] != 0:
        needed_changes = _process_emerge_err(call["stdout"], call["stderr"])
    else:
        needed_changes = []

    __context__.pop("pkg.list_pkgs", None)
    new = list_pkgs()
    changes.update(salt.utils.data.compare_dicts(old, new))

    if needed_changes:
        raise CommandExecutionError(
            "Error occurred installing package(s)",
            info={
                "needed changes": needed_changes,
                "changes": changes
            },
        )

    return changes
Пример #16
0
def install(name,
            version=None,
            source=None,
            force=False,
            install_args=None,
            override_args=False,
            force_x86=False,
            package_args=None):
    '''
    Instructs Chocolatey to install a package.

    name
        The name of the package to be installed. Only accepts a single argument.

    version
        Install a specific version of the package. Defaults to latest version.

    source
        Chocolatey repository (directory, share or remote URL feed) the package
        comes from. Defaults to the official Chocolatey feed.

    force
        Reinstall the current version of an existing package.

    install_args
        A list of install arguments you want to pass to the installation process
        i.e product key or feature list

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

    force_x86
        Force x86 (32bit) installation on 64 bit systems. Defaults to false.

    package_args
        A list of arguments you want to pass to the package

    CLI Example:

    .. code-block:: bash

        salt '*' chocolatey.install <package name>
        salt '*' chocolatey.install <package name> version=<package version>
        salt '*' chocolatey.install <package name> install_args=<args> override_args=True
    '''
    choc_path = _find_chocolatey(__context__, __salt__)
    # chocolatey helpfully only supports a single package argument
    cmd = [choc_path, 'install', name]
    if version:
        cmd.extend(['-Version', version])
    if source:
        cmd.extend(['-Source', source])
    if salt.utils.is_true(force):
        cmd.extend(['-Force'])
    if install_args:
        cmd.extend(['-InstallArguments', install_args])
    if override_args:
        cmd.extend(['-OverrideArguments'])
    if force_x86:
        cmd.extend(['-forcex86'])
    if package_args:
        cmd.extend(['-PackageParameters', package_args])
    cmd.extend(_yes(__context__))
    result = __salt__['cmd.run_all'](cmd, python_shell=False)

    if result['retcode'] != 0:
        err = 'Running chocolatey failed: {0}'.format(result['stderr'])
        log.error(err)
        raise CommandExecutionError(err)
    elif name == 'chocolatey':
        _clear_context(__context__)

    return result['stdout']
Пример #17
0
def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
    """
    .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
        On minions running systemd>=205, `systemd-run(1)`_ is now used to
        isolate commands which modify installed packages from the
        ``salt-minion`` daemon's control group. This is done to keep systemd
        from killing any emerge commands spawned by Salt when the
        ``salt-minion`` service is restarted. (see ``KillMode`` in the
        `systemd.kill(5)`_ manpage for more information). If desired, usage of
        `systemd-run(1)`_ can be suppressed by setting a :mod:`config option
        <salt.modules.config.get>` called ``systemd.scope``, with a value of
        ``False`` (no quotes).

    .. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
    .. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html

    Updates the passed package (emerge --update package)

    slot
        Restrict the update to a particular slot. It will update to the
        latest version within the slot.

    fromrepo
        Restrict the update to a particular repository. It will update to the
        latest version within the repository.
    binhost
        has two options try and force.
        try - tells emerge to try and install the package from a configured binhost.
        force - forces emerge to install the package from a binhost otherwise it fails out.

    Return a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}

    CLI Example:

    .. code-block:: bash

        salt '*' pkg.update <package name>
    """
    if salt.utils.data.is_true(refresh):
        refresh_db()

    full_atom = pkg

    if slot is not None:
        full_atom = "{0}:{1}".format(full_atom, slot)

    if fromrepo is not None:
        full_atom = "{0}::{1}".format(full_atom, fromrepo)

    if binhost == "try":
        bin_opts = ["-g"]
    elif binhost == "force":
        bin_opts = ["-G"]
    else:
        bin_opts = []

    old = list_pkgs()
    cmd = []
    if salt.utils.systemd.has_scope(__context__) and __salt__["config.get"](
            "systemd.scope", True):
        cmd.extend(["systemd-run", "--scope"])
    cmd.extend([
        "emerge", "--ask", "n", "--quiet", "--update", "--newuse", "--oneshot"
    ])
    cmd.extend(bin_opts)
    cmd.append(full_atom)
    call = __salt__["cmd.run_all"](cmd,
                                   output_loglevel="trace",
                                   python_shell=False)
    if call["retcode"] != 0:
        needed_changes = _process_emerge_err(call["stdout"], call["stderr"])
    else:
        needed_changes = []

    __context__.pop("pkg.list_pkgs", None)
    new = list_pkgs()
    ret = salt.utils.data.compare_dicts(old, new)

    if needed_changes:
        raise CommandExecutionError(
            "Problem encountered updating package(s)",
            info={
                "needed_changes": needed_changes,
                "changes": ret
            },
        )

    return ret
Пример #18
0
def version(name, check_remote=False, source=None, pre_versions=False):
    '''
    Instructs Chocolatey to check an installed package version, and optionally
    compare it to one available from a remote feed.

    name
        The name of the package to check.

    check_remote
        Get the version number of the latest package from the remote feed.
        Defaults to False.

    source
        Chocolatey repository (directory, share or remote URL feed) the package
        comes from. Defaults to the official Chocolatey feed.

    pre_versions
        Include pre-release packages in comparison. Defaults to False.

    CLI Example:

    .. code-block:: bash

        salt "*" chocolatey.version <package name>
        salt "*" chocolatey.version <package name> check_remote=True
    '''
    choc_path = _find_chocolatey(__context__, __salt__)
    if not choc_path:
        err = 'Chocolatey not installed. Use chocolatey.bootstrap to install the Chocolatey package manager.'
        log.error(err)
        raise CommandExecutionError(err)

    use_list = _LooseVersion(chocolatey_version()) >= _LooseVersion('0.9.9')
    if use_list:
        choco_cmd = "list"
    else:
        choco_cmd = "version"

    cmd = [choc_path, choco_cmd, name]
    if not salt.utils.is_true(check_remote):
        cmd.append('-LocalOnly')
    if salt.utils.is_true(pre_versions):
        cmd.append('-Prerelease')
    if source:
        cmd.extend(['-Source', source])

    result = __salt__['cmd.run_all'](cmd, python_shell=False)

    if result['retcode'] != 0:
        err = 'Running chocolatey failed: {0}'.format(result['stderr'])
        log.error(err)
        raise CommandExecutionError(err)

    ret = {}

    res = result['stdout'].split('\n')
    if use_list:
        res = res[:-1]

    # the next bit is to deal with the stupid default PowerShell formatting.
    # printing two value pairs is shown in columns, whereas printing six
    # pairs is shown in rows...
    if not salt.utils.is_true(check_remote):
        ver_re = re.compile(r'(\S+)\s+(.+)')
        for line in res:
            for name, ver in ver_re.findall(line):
                ret['name'] = name
                ret['found'] = ver
    else:
        ver_re = re.compile(r'(\S+)\s+:\s*(.*)')
        for line in res:
            for key, value in ver_re.findall(line):
                ret[key] = value

    return ret
Пример #19
0
def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
    """
    .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
        On minions running systemd>=205, `systemd-run(1)`_ is now used to
        isolate commands which modify installed packages from the
        ``salt-minion`` daemon's control group. This is done to keep systemd
        from killing any emerge commands spawned by Salt when the
        ``salt-minion`` service is restarted. (see ``KillMode`` in the
        `systemd.kill(5)`_ manpage for more information). If desired, usage of
        `systemd-run(1)`_ can be suppressed by setting a :mod:`config option
        <salt.modules.config.get>` called ``systemd.scope``, with a value of
        ``False`` (no quotes).

    .. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
    .. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html

    Remove packages via emerge --unmerge.

    name
        The name of the package to be deleted.

    slot
        Restrict the remove to a specific slot. Ignored if ``name`` is None.

    fromrepo
        Restrict the remove to a specific slot. Ignored if ``name`` is None.

    Multiple Package Options:

    pkgs
        Uninstall multiple packages. ``slot`` and ``fromrepo`` arguments are
        ignored if this argument is present. Must be passed as a python list.

    .. versionadded:: 0.16.0

    Returns a dict containing the changes.

    CLI Example:

    .. code-block:: bash

        salt '*' pkg.remove <package name>
        salt '*' pkg.remove <package name> slot=4.4 fromrepo=gentoo
        salt '*' pkg.remove <package1>,<package2>,<package3>
        salt '*' pkg.remove pkgs='["foo", "bar"]'
    """
    try:
        pkg_params = __salt__["pkg_resource.parse_targets"](name, pkgs)[0]
    except MinionError as exc:
        raise CommandExecutionError(exc)

    old = list_pkgs()
    if (name and not pkgs and (slot is not None or fromrepo is not None)
            and len(pkg_params) == 1):
        fullatom = name
        if slot is not None:
            targets = ["{0}:{1}".format(fullatom, slot)]
        if fromrepo is not None:
            targets = ["{0}::{1}".format(fullatom, fromrepo)]
        targets = [fullatom]
    else:
        targets = [x for x in pkg_params if x in old]

    if not targets:
        return {}

    cmd = []
    if salt.utils.systemd.has_scope(__context__) and __salt__["config.get"](
            "systemd.scope", True):
        cmd.extend(["systemd-run", "--scope"])
    cmd.extend([
        "emerge", "--ask", "n", "--quiet", "--unmerge", "--quiet-unmerge-warn"
    ])
    cmd.extend(targets)

    out = __salt__["cmd.run_all"](cmd,
                                  output_loglevel="trace",
                                  python_shell=False)
    if out["retcode"] != 0 and out["stderr"]:
        errors = [out["stderr"]]
    else:
        errors = []

    __context__.pop("pkg.list_pkgs", None)
    new = list_pkgs()
    ret = salt.utils.data.compare_dicts(old, new)

    if errors:
        raise CommandExecutionError(
            "Problem encountered removing package(s)",
            info={
                "errors": errors,
                "changes": ret
            },
        )

    return ret
Пример #20
0
def runas_unpriv(cmd, username, password, cwd=None):
    """
    Runas that works for non-privileged users
    """
    # Validate the domain and sid exist for the username
    try:
        _, domain, _ = win32security.LookupAccountName(None, username)
        username, _ = split_username(username)
    except pywintypes.error as exc:
        message = win32api.FormatMessage(exc.winerror).rstrip("\n")
        raise CommandExecutionError(message)

    # Create a pipe to set as stdout in the child. The write handle needs to be
    # inheritable.
    c2pread, c2pwrite = salt.platform.win.CreatePipe(
        inherit_read=False,
        inherit_write=True,
    )
    errread, errwrite = salt.platform.win.CreatePipe(
        inherit_read=False,
        inherit_write=True,
    )

    # Create inheritable copy of the stdin
    stdin = salt.platform.win.kernel32.GetStdHandle(
        salt.platform.win.STD_INPUT_HANDLE, )
    dupin = salt.platform.win.DuplicateHandle(srchandle=stdin, inherit=True)

    # Get startup info structure
    startup_info = salt.platform.win.STARTUPINFO(
        dwFlags=win32con.STARTF_USESTDHANDLES,
        hStdInput=dupin,
        hStdOutput=c2pwrite,
        hStdError=errwrite,
    )

    try:
        # Run command and return process info structure
        process_info = salt.platform.win.CreateProcessWithLogonW(
            username=username,
            domain=domain,
            password=password,
            logonflags=salt.platform.win.LOGON_WITH_PROFILE,
            commandline=cmd,
            startupinfo=startup_info,
            currentdirectory=cwd,
        )
        salt.platform.win.kernel32.CloseHandle(process_info.hThread)
    finally:
        salt.platform.win.kernel32.CloseHandle(dupin)
        salt.platform.win.kernel32.CloseHandle(c2pwrite)
        salt.platform.win.kernel32.CloseHandle(errwrite)

    # Initialize ret and set first element
    ret = {"pid": process_info.dwProcessId}

    # Get Standard Out
    fd_out = msvcrt.open_osfhandle(c2pread, os.O_RDONLY | os.O_TEXT)
    with os.fdopen(fd_out, "r") as f_out:
        ret["stdout"] = f_out.read()

    # Get Standard Error
    fd_err = msvcrt.open_osfhandle(errread, os.O_RDONLY | os.O_TEXT)
    with os.fdopen(fd_err, "r") as f_err:
        ret["stderr"] = f_err.read()

    # Get Return Code
    if (salt.platform.win.kernel32.WaitForSingleObject(
            process_info.hProcess,
            win32event.INFINITE) == win32con.WAIT_OBJECT_0):
        exitcode = salt.platform.win.wintypes.DWORD()
        salt.platform.win.kernel32.GetExitCodeProcess(process_info.hProcess,
                                                      ctypes.byref(exitcode))
        ret["retcode"] = exitcode.value

    # Close handle to process
    salt.platform.win.kernel32.CloseHandle(process_info.hProcess)

    return ret
Пример #21
0
def get_route(ip):
    '''
    Return routing information for given destination ip

    .. versionadded:: 2015.5.3

    .. versionchanged:: 2015.8.0
        Added support for SunOS (Solaris 10, Illumos, SmartOS)
        Added support for OpenBSD

    CLI Example::

        salt '*' network.get_route 10.10.10.10
    '''

    if __grains__['kernel'] == 'Linux':
        cmd = 'ip route get {0}'.format(ip)
        out = __salt__['cmd.run'](cmd, python_shell=True)
        regexp = re.compile(r'(via\s+(?P<gateway>[\w\.:]+))?\s+dev\s+(?P<interface>[\w\.\:]+)\s+.*src\s+(?P<source>[\w\.:]+)')
        m = regexp.search(out.splitlines()[0])
        ret = {
            'destination': ip,
            'gateway': m.group('gateway'),
            'interface': m.group('interface'),
            'source': m.group('source')
        }

        return ret

    if __grains__['kernel'] == 'SunOS':
        # [root@nacl ~]# route -n get 172.16.10.123
        #   route to: 172.16.10.123
        #destination: 172.16.10.0
        #       mask: 255.255.255.0
        #  interface: net0
        #      flags: <UP,DONE,KERNEL>
        # recvpipe  sendpipe  ssthresh    rtt,ms rttvar,ms  hopcount      mtu     expire
        #       0         0         0         0         0         0      1500         0
        cmd = '/usr/sbin/route -n get {0}'.format(ip)
        out = __salt__['cmd.run'](cmd, python_shell=False)

        ret = {
            'destination': ip,
            'gateway': None,
            'interface': None,
            'source': None
        }

        for line in out.splitlines():
            line = line.split(':')
            if 'route to' in line[0]:
                ret['destination'] = line[1].strip()
            if 'gateway' in line[0]:
                ret['gateway'] = line[1].strip()
            if 'interface' in line[0]:
                ret['interface'] = line[1].strip()
                ret['source'] = salt.utils.network.interface_ip(line[1].strip())

        return ret

    if __grains__['kernel'] == 'OpenBSD':
        # [root@exosphere] route -n get blackdot.be
        #   route to: 5.135.127.100
        #destination: default
        #       mask: default
        #    gateway: 192.168.0.1
        #  interface: vio0
        # if address: 192.168.0.2
        #   priority: 8 (static)
        #      flags: <UP,GATEWAY,DONE,STATIC>
        #     use       mtu    expire
        # 8352657         0         0
        cmd = 'route -n get {0}'.format(ip)
        out = __salt__['cmd.run'](cmd, python_shell=False)

        ret = {
            'destination': ip,
            'gateway': None,
            'interface': None,
            'source': None
        }

        for line in out.splitlines():
            line = line.split(':')
            if 'route to' in line[0]:
                ret['destination'] = line[1].strip()
            if 'gateway' in line[0]:
                ret['gateway'] = line[1].strip()
            if 'interface' in line[0]:
                ret['interface'] = line[1].strip()
            if 'if address' in line[0]:
                ret['source'] = line[1].strip()

        return ret

    else:
        raise CommandExecutionError('Not yet supported on this platform')
Пример #22
0
def runas(cmdLine, username, password=None, cwd=None):
    """
    Run a command as another user. If the process is running as an admin or
    system account this method does not require a password. Other non
    privileged accounts need to provide a password for the user to runas.
    Commands are run in with the highest level privileges possible for the
    account provided.
    """
    # Validate the domain and sid exist for the username
    try:
        _, domain, _ = win32security.LookupAccountName(None, username)
        username, _ = split_username(username)
    except pywintypes.error as exc:
        message = win32api.FormatMessage(exc.winerror).rstrip("\n")
        raise CommandExecutionError(message)

    # Elevate the token from the current process
    access = win32security.TOKEN_QUERY | win32security.TOKEN_ADJUST_PRIVILEGES
    th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), access)
    salt.platform.win.elevate_token(th)

    # Try to impersonate the SYSTEM user. This process needs to be running as a
    # user who as been granted the SeImpersonatePrivilege, Administrator
    # accounts have this permission by default.
    try:
        impersonation_token = salt.platform.win.impersonate_sid(
            salt.platform.win.SYSTEM_SID,
            session_id=0,
            privs=["SeTcbPrivilege"],
        )
    except OSError:
        log.debug("Unable to impersonate SYSTEM user")
        impersonation_token = None
        win32api.CloseHandle(th)

    # Impersonation of the SYSTEM user failed. Fallback to an un-privileged
    # runas.
    if not impersonation_token:
        log.debug("No impersonation token, using unprivileged runas")
        return runas_unpriv(cmdLine, username, password, cwd)

    if domain == "NT AUTHORITY":
        # Logon as a system level account, SYSTEM, LOCAL SERVICE, or NETWORK
        # SERVICE.
        user_token = win32security.LogonUser(
            username,
            domain,
            "",
            win32con.LOGON32_LOGON_SERVICE,
            win32con.LOGON32_PROVIDER_DEFAULT,
        )
    elif password:
        # Login with a password.
        user_token = win32security.LogonUser(
            username,
            domain,
            password,
            win32con.LOGON32_LOGON_INTERACTIVE,
            win32con.LOGON32_PROVIDER_DEFAULT,
        )
    else:
        # Login without a password. This always returns an elevated token.
        user_token = salt.platform.win.logon_msv1_s4u(username).Token

    # Get a linked user token to elevate if needed
    elevation_type = win32security.GetTokenInformation(
        user_token, win32security.TokenElevationType)
    if elevation_type > 1:
        user_token = win32security.GetTokenInformation(
            user_token, win32security.TokenLinkedToken)

    # Elevate the user token
    salt.platform.win.elevate_token(user_token)

    # Make sure the user's token has access to a windows station and desktop
    salt.platform.win.grant_winsta_and_desktop(user_token)

    # Create pipes for standard in, out and error streams
    security_attributes = win32security.SECURITY_ATTRIBUTES()
    security_attributes.bInheritHandle = 1

    stdin_read, stdin_write = win32pipe.CreatePipe(security_attributes, 0)
    stdin_read = salt.platform.win.make_inheritable(stdin_read)

    stdout_read, stdout_write = win32pipe.CreatePipe(security_attributes, 0)
    stdout_write = salt.platform.win.make_inheritable(stdout_write)

    stderr_read, stderr_write = win32pipe.CreatePipe(security_attributes, 0)
    stderr_write = salt.platform.win.make_inheritable(stderr_write)

    # Run the process without showing a window.
    creationflags = (win32process.CREATE_NO_WINDOW
                     | win32process.CREATE_NEW_CONSOLE
                     | win32process.CREATE_SUSPENDED)

    startup_info = salt.platform.win.STARTUPINFO(
        dwFlags=win32con.STARTF_USESTDHANDLES,
        hStdInput=stdin_read.handle,
        hStdOutput=stdout_write.handle,
        hStdError=stderr_write.handle,
    )

    # Create the environment for the user
    env = create_env(user_token, False)

    hProcess = None
    try:
        # Start the process in a suspended state.
        process_info = salt.platform.win.CreateProcessWithTokenW(
            int(user_token),
            logonflags=1,
            applicationname=None,
            commandline=cmdLine,
            currentdirectory=cwd,
            creationflags=creationflags,
            startupinfo=startup_info,
            environment=env,
        )

        hProcess = process_info.hProcess
        hThread = process_info.hThread
        dwProcessId = process_info.dwProcessId
        dwThreadId = process_info.dwThreadId

        # We don't use these so let's close the handle
        salt.platform.win.kernel32.CloseHandle(stdin_write.handle)
        salt.platform.win.kernel32.CloseHandle(stdout_write.handle)
        salt.platform.win.kernel32.CloseHandle(stderr_write.handle)

        ret = {"pid": dwProcessId}
        # Resume the process
        psutil.Process(dwProcessId).resume()

        # Wait for the process to exit and get its return code.
        if (win32event.WaitForSingleObject(
                hProcess, win32event.INFINITE) == win32con.WAIT_OBJECT_0):
            exitcode = win32process.GetExitCodeProcess(hProcess)
            ret["retcode"] = exitcode

        # Read standard out
        fd_out = msvcrt.open_osfhandle(stdout_read.handle,
                                       os.O_RDONLY | os.O_TEXT)
        with os.fdopen(fd_out, "r") as f_out:
            stdout = f_out.read()
            ret["stdout"] = stdout

        # Read standard error
        fd_err = msvcrt.open_osfhandle(stderr_read.handle,
                                       os.O_RDONLY | os.O_TEXT)
        with os.fdopen(fd_err, "r") as f_err:
            stderr = f_err.read()
            ret["stderr"] = stderr
    finally:
        if hProcess is not None:
            salt.platform.win.kernel32.CloseHandle(hProcess)
        win32api.CloseHandle(th)
        win32api.CloseHandle(user_token)
        if impersonation_token:
            win32security.RevertToSelf()
        win32api.CloseHandle(impersonation_token)

    return ret
Пример #23
0
def list_(device, unit=None):
    '''
    Prints partition information of given <device>

    CLI Examples:

    .. code-block:: bash

        salt '*' partition.list /dev/sda
        salt '*' partition.list /dev/sda unit=s
        salt '*' partition.list /dev/sda unit=kB
    '''
    _validate_device(device)

    if unit:
        if unit not in VALID_UNITS:
            raise CommandExecutionError(
                'Invalid unit passed to partition.part_list')
        cmd = 'parted -m -s {0} unit {1} print'.format(device, unit)
    else:
        cmd = 'parted -m -s {0} print'.format(device)

    out = __salt__['cmd.run_stdout'](cmd).splitlines()
    ret = {'info': {}, 'partitions': {}}
    mode = 'info'
    for line in out:
        if line in ('BYT;', 'CHS;', 'CYL;'):
            continue
        cols = line.replace(';', '').split(':')
        if mode == 'info':
            if 7 <= len(cols) <= 8:
                ret['info'] = {
                    'disk': cols[0],
                    'size': cols[1],
                    'interface': cols[2],
                    'logical sector': cols[3],
                    'physical sector': cols[4],
                    'partition table': cols[5],
                    'model': cols[6]
                }
                if len(cols) == 8:
                    ret['info']['disk flags'] = cols[7]
                    # Older parted (2.x) doesn't show disk flags in the 'print'
                    # output, and will return a 7-column output for the info
                    # line. In these cases we just leave this field out of the
                    # return dict.
                mode = 'partitions'
            else:
                raise CommandExecutionError(
                    'Problem encountered while parsing output from parted')
        else:
            if len(cols) == 7:
                ret['partitions'][cols[0]] = {
                    'number': cols[0],
                    'start': cols[1],
                    'end': cols[2],
                    'size': cols[3],
                    'type': cols[4],
                    'file system': cols[5],
                    'flags': cols[6]
                }
            else:
                raise CommandExecutionError(
                    'Problem encountered while parsing output from parted')
    return ret
Пример #24
0
def install(name=None, sources=None, saltenv='base', **kwargs):
    '''
    Install the passed package. Can install packages from the following
    sources::

        * Locally (package already exists on the minion
        * HTTP/HTTPS server
        * FTP server
        * Salt master

    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}

    CLI Example, installing a data stream pkg that already exists on the
    minion::

        salt '*' pkg.install sources='[{"<pkg name>": "/dir/on/minion/<pkg filename>"}]'
        salt '*' pkg.install sources='[{"SMClgcc346": "/var/spool/pkg/gcc-3.4.6-sol10-sparc-local.pkg"}]'

    CLI Example, installing a data stream pkg that exists on the salt master::

        salt '*' pkg.install sources='[{"<pkg name>": "salt://pkgs/<pkg filename>"}]'
        salt '*' pkg.install sources='[{"SMClgcc346": "salt://pkgs/gcc-3.4.6-sol10-sparc-local.pkg"}]'

    CLI Example, installing a data stream pkg that exists on a HTTP server::

        salt '*' pkg.install sources='[{"<pkg name>": "http://packages.server.com/<pkg filename>"}]'
        salt '*' pkg.install sources='[{"SMClgcc346": "http://packages.server.com/gcc-3.4.6-sol10-sparc-local.pkg"}]'

    If working with solaris zones and you want to install a package only in the
    global zone you can pass 'current_zone_only=True' to salt to have the
    package only installed in the global zone. (Behind the scenes this is
    passing '-G' to the pkgadd command.) Solaris default when installing a
    package in the global zone is to install it in all zones. This overrides
    that and installs the package only in the global.

    CLI Example, installing a data stream package only in the global zone::

        salt 'global_zone' pkg.install sources='[{"SMClgcc346": "/var/spool/pkg/gcc-3.4.6-sol10-sparc-local.pkg"}]' current_zone_only=True

    By default salt automatically provides an adminfile, to automate package
    installation, with these options set::

        email=
        instance=quit
        partial=nocheck
        runlevel=nocheck
        idepend=nocheck
        rdepend=nocheck
        space=nocheck
        setuid=nocheck
        conflict=nocheck
        action=nocheck
        basedir=default

    You can override any of these options in two ways. First you can optionally
    pass any of the options as a kwarg to the module/state to override the
    default value or you can optionally pass the 'admin_source' option
    providing your own adminfile to the minions.

    Note: You can find all of the possible options to provide to the adminfile
    by reading the admin man page::

        man -s 4 admin

    CLI Example - Overriding the 'instance' adminfile option when calling the
    module directly::

        salt '*' pkg.install sources='[{"<pkg name>": "salt://pkgs/<pkg filename>"}]' instance="overwrite"

    CLI Example - Overriding the 'instance' adminfile option when used in a
    state::

        SMClgcc346:
          pkg.installed:
            - sources:
              - SMClgcc346: salt://srv/salt/pkgs/gcc-3.4.6-sol10-sparc-local.pkg
            - instance: overwrite

    Note: the ID declaration is ignored, as the package name is read from the
    "sources" parameter.

    CLI Example - Providing your own adminfile when calling the module
    directly::

        salt '*' pkg.install sources='[{"<pkg name>": "salt://pkgs/<pkg filename>"}]' admin_source='salt://pkgs/<adminfile filename>'

    CLI Example - Providing your own adminfile when using states::

        <pkg name>:
          pkg.installed:
            - sources:
              - <pkg name>: salt://pkgs/<pkg filename>
            - admin_source: salt://pkgs/<adminfile filename>

    Note: the ID declaration is ignored, as the package name is read from the
    "sources" parameter.
    '''
    if salt.utils.is_true(kwargs.get('refresh')):
        log.warning('\'refresh\' argument not implemented for solarispkg '
                    'module')

    # pkgs is not supported, but must be passed here for API compatibility
    pkgs = kwargs.pop('pkgs', None)
    try:
        pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](name,
                                                                      pkgs,
                                                                      sources,
                                                                      **kwargs)
    except MinionError as exc:
        raise CommandExecutionError(exc)

    if pkg_params is None or len(pkg_params) == 0:
        return {}

    if not sources:
        log.error('"sources" param required for solaris pkg_add installs')
        return {}

    if 'admin_source' in kwargs:
        adminfile = __salt__['cp.cache_file'](kwargs['admin_source'], saltenv)
    else:
        adminfile = _write_adminfile(kwargs)

    old = list_pkgs()
    cmd = '/usr/sbin/pkgadd -n -a {0} '.format(adminfile)

    # Only makes sense in a global zone but works fine in non-globals.
    if kwargs.get('current_zone_only') == 'True':
        cmd += '-G '

    for pkg in pkg_params:
        temp_cmd = cmd + '-d {0} "all"'.format(pkg)
        # Install the package{s}
        __salt__['cmd.run'](temp_cmd, output_loglevel='trace')

    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()

    # Remove the temp adminfile
    if 'admin_source' not in kwargs:
        os.unlink(adminfile)

    return salt.utils.compare_dicts(old, new)
Пример #25
0
def info_installed(*names, **kwargs):
    '''
    Return the information of the named package(s), installed on the system.

    .. versionadded:: 2017.7.0

    :param names:
        Names of the packages to get information about. If none are specified,
        will return information for all installed packages.

    :param attr:
        Comma-separated package attributes. If no 'attr' is specified, all available attributes returned.

        Valid attributes are:
            arch, conffiles, conflicts, depends, description, filename, group,
            install_date_time_t, md5sum, packager, provides, recommends,
            replaces, size, source, suggests, url, version

    CLI example:

    .. code-block:: bash

        salt '*' pkg.info_installed
        salt '*' pkg.info_installed attr=version,packager
        salt '*' pkg.info_installed <package1>
        salt '*' pkg.info_installed <package1> <package2> <package3> ...
        salt '*' pkg.info_installed <package1> attr=version,packager
        salt '*' pkg.info_installed <package1> <package2> <package3> ... attr=version,packager
    '''
    attr = kwargs.pop('attr', None)
    if attr is None:
        filter_attrs = None
    elif isinstance(attr, six.string_types):
        filter_attrs = set(attr.split(','))
    else:
        filter_attrs = set(attr)

    ret = {}
    if names:
        # Specific list of names of installed packages
        for name in names:
            cmd = ['opkg', 'status', name]
            call = __salt__['cmd.run_all'](cmd,
                                           output_loglevel='trace',
                                           python_shell=False)
            if call['retcode'] != 0:
                comment = ''
                if call['stderr']:
                    comment += call['stderr']
                else:
                    comment += call['stdout']

                raise CommandExecutionError(comment)
            ret.update(_process_info_installed_output(call['stdout'], filter_attrs))
    else:
        # All installed packages
        cmd = ['opkg', 'status']
        call = __salt__['cmd.run_all'](cmd,
                                       output_loglevel='trace',
                                       python_shell=False)
        if call['retcode'] != 0:
            comment = ''
            if call['stderr']:
                comment += call['stderr']
            else:
                comment += call['stdout']

            raise CommandExecutionError(comment)
        ret.update(_process_info_installed_output(call['stdout'], filter_attrs))

    return ret
Пример #26
0
def remove(name=None, pkgs=None, saltenv='base', **kwargs):
    '''
    Remove packages with pkgrm

    name
        The name of the package to be deleted

    By default salt automatically provides an adminfile, to automate package
    removal, with these options set::

        email=
        instance=quit
        partial=nocheck
        runlevel=nocheck
        idepend=nocheck
        rdepend=nocheck
        space=nocheck
        setuid=nocheck
        conflict=nocheck
        action=nocheck
        basedir=default

    You can override any of these options in two ways. First you can optionally
    pass any of the options as a kwarg to the module/state to override the
    default value or you can optionally pass the 'admin_source' option
    providing your own adminfile to the minions.

    Note: You can find all of the possible options to provide to the adminfile
    by reading the admin man page:

    .. code-block:: bash

        man -s 4 admin


    Multiple Package Options:

    pkgs
        A list of packages to delete. Must be passed as a python list. The
        ``name`` parameter will be ignored if this option is passed.

    .. versionadded:: 0.16.0


    Returns a dict containing the changes.

    CLI Example:

    .. code-block:: bash

        salt '*' pkg.remove <package name>
        salt '*' pkg.remove SUNWgit
        salt '*' pkg.remove <package1>,<package2>,<package3>
        salt '*' pkg.remove pkgs='["foo", "bar"]'
    '''
    try:
        pkg_params = __salt__['pkg_resource.parse_targets'](name, pkgs)[0]
    except MinionError as exc:
        raise CommandExecutionError(exc)

    old = list_pkgs()
    targets = [x for x in pkg_params if x in old]
    if not targets:
        return {}

    if 'admin_source' in kwargs:
        adminfile = __salt__['cp.cache_file'](kwargs['admin_source'], saltenv)
    else:
        # Set the adminfile default variables
        email = kwargs.get('email', '')
        instance = kwargs.get('instance', 'quit')
        partial = kwargs.get('partial', 'nocheck')
        runlevel = kwargs.get('runlevel', 'nocheck')
        idepend = kwargs.get('idepend', 'nocheck')
        rdepend = kwargs.get('rdepend', 'nocheck')
        space = kwargs.get('space', 'nocheck')
        setuid = kwargs.get('setuid', 'nocheck')
        conflict = kwargs.get('conflict', 'nocheck')
        action = kwargs.get('action', 'nocheck')
        basedir = kwargs.get('basedir', 'default')

        # Make tempfile to hold the adminfile contents.
        fd_, adminfile = salt.utils.mkstemp(prefix="salt-", close_fd=False)

        # Write to file then close it.
        os.write(fd_, 'email={0}\n'.format(email))
        os.write(fd_, 'instance={0}\n'.format(instance))
        os.write(fd_, 'partial={0}\n'.format(partial))
        os.write(fd_, 'runlevel={0}\n'.format(runlevel))
        os.write(fd_, 'idepend={0}\n'.format(idepend))
        os.write(fd_, 'rdepend={0}\n'.format(rdepend))
        os.write(fd_, 'space={0}\n'.format(space))
        os.write(fd_, 'setuid={0}\n'.format(setuid))
        os.write(fd_, 'conflict={0}\n'.format(conflict))
        os.write(fd_, 'action={0}\n'.format(action))
        os.write(fd_, 'basedir={0}\n'.format(basedir))
        os.close(fd_)

    # Remove the package
    cmd = '/usr/sbin/pkgrm -n -a {0} {1}'.format(adminfile, ' '.join(targets))
    __salt__['cmd.run'](cmd, output_loglevel='trace')
    # Remove the temp adminfile
    if 'admin_source' not in kwargs:
        os.unlink(adminfile)
    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()
    return salt.utils.compare_dicts(old, new)
Пример #27
0
def refresh_db(failhard=False, **kwargs):  # pylint: disable=unused-argument
    '''
    Updates the opkg database to latest packages based upon repositories

    Returns a dict, with the keys being package databases and the values being
    the result of the update attempt. Values can be one of the following:

    - ``True``: Database updated successfully
    - ``False``: Problem updating database

    failhard
        If False, return results of failed lines as ``False`` for the package
        database that encountered the error.
        If True, raise an error with a list of the package databases that
        encountered errors.

        .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: bash

        salt '*' pkg.refresh_db
    '''
    # Remove rtag file to keep multiple refreshes from happening in pkg states
    salt.utils.pkg.clear_rtag(__opts__)
    ret = {}
    error_repos = []
    cmd = ['opkg', 'update']
    # opkg returns a non-zero retcode when there is a failure to refresh
    # from one or more repos. Due to this, ignore the retcode.
    call = __salt__['cmd.run_all'](cmd,
                                   output_loglevel='trace',
                                   python_shell=False,
                                   ignore_retcode=True,
                                   redirect_stderr=True)

    out = call['stdout']
    prev_line = ''
    for line in salt.utils.itertools.split(out, '\n'):
        if 'Inflating' in line:
            key = line.strip().split()[1][:-1]
            ret[key] = True
        elif 'Updated source' in line:
            # Use the previous line.
            key = prev_line.strip().split()[1][:-1]
            ret[key] = True
        elif 'Failed to download' in line:
            key = line.strip().split()[5].split(',')[0]
            ret[key] = False
            error_repos.append(key)
        prev_line = line

    if failhard and error_repos:
        raise CommandExecutionError(
            'Error getting repos: {0}'.format(', '.join(error_repos))
        )

    # On a non-zero exit code where no failed repos were found, raise an
    # exception because this appears to be a different kind of error.
    if call['retcode'] != 0 and not error_repos:
        raise CommandExecutionError(out)

    return ret
Пример #28
0
    def create_vs(self, name, ip, port, protocol, profile, pool_name):
        '''
        Create a virtual server
        '''
        vs = self.bigIP.LocalLB.VirtualServer
        vs_def = vs.typefactory.create('Common.VirtualServerDefinition')

        vs_def.name = name
        vs_def.address = ip
        vs_def.port = port

        common_protocols = vs.typefactory.create('Common.ProtocolType')

        p = [i[0] for i in common_protocols if i[0].split('_')[1] == protocol.upper()]

        if p:
            vs_def.protocol = p
        else:
            raise CommandExecutionError('Unknown protocol')

        vs_def_seq = vs.typefactory.create('Common.VirtualServerSequence')
        vs_def_seq.item = [vs_def]

        vs_type = vs.typefactory.create(
            'LocalLB.VirtualServer.VirtualServerType'
        )
        vs_resource = vs.typefactory.create(
            'LocalLB.VirtualServer.VirtualServerResource'
        )

        vs_resource.type = vs_type.RESOURCE_TYPE_POOL
        vs_resource.default_pool_name = pool_name

        resource_seq = vs.typefactory.create(
            'LocalLB.VirtualServer.VirtualServerResourceSequence'
        )

        resource_seq.item = [vs_resource]

        vs_context = vs.typefactory.create('LocalLB.ProfileContextType')
        vs_profile = vs.typefactory.create(
            'LocalLB.VirtualServer.VirtualServerProfile'
        )

        vs_profile.profile_context = vs_context.PROFILE_CONTEXT_TYPE_ALL
        vs_profile.profile_name = protocol

        vs_profile_http = vs.typefactory.create(
            'LocalLB.VirtualServer.VirtualServerProfile'
        )
        vs_profile_http.profile_name = profile

        vs_profile_conn = vs.typefactory.create(
            'LocalLB.VirtualServer.VirtualServerProfile'
        )
        vs_profile_conn.profile_name = 'oneconnect'

        vs_profile_seq = vs.typefactory.create(
            'LocalLB.VirtualServer.VirtualServerProfileSequence'
        )
        vs_profile_seq.item = [vs_profile, vs_profile_http, vs_profile_conn]

        try:
            vs.create(definitions=vs_def_seq,
                      wildmasks=['255.255.255.255'],
                      resources=resource_seq,
                      profiles=[vs_profile_seq])
        except Exception as e:
            raise Exception(
                'Unable to create `{0}` virtual server\n\n{1}'.format(name, e)
            )
        return True
Пример #29
0
def remove(name=None, pkgs=None, **kwargs):  # pylint: disable=unused-argument
    '''
    Remove packages using ``opkg remove``.

    name
        The name of the package to be deleted.


    Multiple Package Options:

    pkgs
        A list of packages to delete. Must be passed as a python list. The
        ``name`` parameter will be ignored if this option is passed.

    remove_dependencies
        Remove package and all dependencies

        .. versionadded:: 2019.2.0

    auto_remove_deps
        Remove packages that were installed automatically to satisfy dependencies

        .. versionadded:: 2019.2.0

    Returns a dict containing the changes.

    CLI Example:

    .. code-block:: bash

        salt '*' pkg.remove <package name>
        salt '*' pkg.remove <package1>,<package2>,<package3>
        salt '*' pkg.remove pkgs='["foo", "bar"]'
        salt '*' pkg.remove pkgs='["foo", "bar"]' remove_dependencies=True auto_remove_deps=True
    '''
    try:
        pkg_params = __salt__['pkg_resource.parse_targets'](name, pkgs)[0]
    except MinionError as exc:
        raise CommandExecutionError(exc)

    old = list_pkgs()
    targets = [x for x in pkg_params if x in old]
    if not targets:
        return {}
    cmd = ['opkg', 'remove']
    _append_noaction_if_testmode(cmd, **kwargs)
    if kwargs.get('remove_dependencies', False):
        cmd.append('--force-removal-of-dependent-packages')
    if kwargs.get('auto_remove_deps', False):
        cmd.append('--autoremove')
    cmd.extend(targets)

    out = __salt__['cmd.run_all'](
        cmd,
        output_loglevel='trace',
        python_shell=False
    )
    if out['retcode'] != 0:
        if out['stderr']:
            errors = [out['stderr']]
        else:
            errors = [out['stdout']]
    else:
        errors = []

    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()
    if _is_testmode(**kwargs):
        reportedPkgs = _parse_reported_packages_from_remove_output(out['stdout'])
        new = {k: v for k, v in new.items() if k not in reportedPkgs}
    ret = salt.utils.data.compare_dicts(old, new)

    rs_result = _get_restartcheck_result(errors)

    if errors:
        raise CommandExecutionError(
            'Problem encountered removing package(s)',
            info={'errors': errors, 'changes': ret}
        )

    _process_restartcheck_result(rs_result, **kwargs)

    return ret
Пример #30
0
def set_value(
    hive,
    key,
    vname=None,
    vdata=None,
    vtype="REG_SZ",
    use_32bit_registry=False,
    volatile=False,
):
    """
    Sets a value in the registry. If ``vname`` is passed, it will be the value
    for that value name, otherwise it will be the default value for the
    specified key

    Args:

        hive (str):
            The name of the hive. Can be one of the following

                - HKEY_LOCAL_MACHINE or HKLM
                - HKEY_CURRENT_USER or HKCU
                - HKEY_USER or HKU
                - HKEY_CLASSES_ROOT or HKCR
                - HKEY_CURRENT_CONFIG or HKCC

        key (str):
            The key (looks like a path) to the value name.

        vname (str):
            The value name. These are the individual name/data pairs under the
            key. If not passed, the key (Default) value will be set.

        vdata (str, int, list, bytes):
            The value you'd like to set. If a value name (vname) is passed, this
            will be the data for that value name. If not, this will be the
            (Default) value for the key.

            The type of data this parameter expects is determined by the value
            type specified in ``vtype``. The correspondence is as follows:

                - REG_BINARY: Binary data (str in Py2, bytes in Py3)
                - REG_DWORD: int
                - REG_EXPAND_SZ: str
                - REG_MULTI_SZ: list of str
                - REG_QWORD: int
                - REG_SZ: str

                .. note::
                    When setting REG_BINARY, string data will be converted to
                    binary. You can pass base64 encoded using the ``binascii``
                    built-in module. Use ``binascii.b2a_base64('your data')``

            .. note::
                The type for the (Default) value is always REG_SZ and cannot be
                changed.

            .. note::
                This parameter is optional. If not passed, the Key will be
                created with no associated item/value pairs.

        vtype (str):
            The value type. The possible values of the vtype parameter are
            indicated above in the description of the vdata parameter.

        use_32bit_registry (bool):
            Sets the 32bit portion of the registry on 64bit installations. On
            32bit machines this is ignored.

        volatile (bool):
            When this parameter has a value of True, the registry key will be
            made volatile (i.e. it will not persist beyond a system reset or
            shutdown). This parameter only has an effect when a key is being
            created and at no other time.

    Returns:
        bool: True if successful, otherwise False

    Usage:

        This will set the version value to 2015.5.2 in the SOFTWARE\\Salt key in
        the HKEY_LOCAL_MACHINE hive

        .. code-block:: python

            import salt.utils.win_reg
            winreg.set_value(hive='HKLM', key='SOFTWARE\\Salt', vname='version', vdata='2015.5.2')

    Usage:

        This function is strict about the type of vdata. For instance this
        example will fail because vtype has a value of REG_SZ and vdata has a
        type of int (as opposed to str as expected).

        .. code-block:: python

            import salt.utils.win_reg
            winreg.set_value(hive='HKLM', key='SOFTWARE\\Salt', vname='str_data', vdata=1.2)

    Usage:

        In this next example vdata is properly quoted and should succeed.

        .. code-block:: python

            import salt.utils.win_reg
            winreg.set_value(hive='HKLM', key='SOFTWARE\\Salt', vname='str_data', vdata='1.2')

    Usage:

        This is an example of using vtype REG_BINARY. Both ``set_value``
        commands will set the same value ``Salty Test``

        .. code-block:: python

            import salt.utils.win_reg
            winreg.set_value(hive='HKLM', key='SOFTWARE\\Salt', vname='bin_data', vdata='Salty Test', vtype='REG_BINARY')

            import binascii
            bin_data = binascii.b2a_base64('Salty Test')
            winreg.set_value(hive='HKLM', key='SOFTWARE\\Salt', vname='bin_data_encoded', vdata=bin_data, vtype='REG_BINARY')

    Usage:

        An example using vtype REG_MULTI_SZ is as follows:

        .. code-block:: python

            import salt.utils.win_reg
            winreg.set_value(hive='HKLM', key='SOFTWARE\\Salt', vname='list_data', vdata=['Salt', 'is', 'great'], vtype='REG_MULTI_SZ')
    """
    local_hive = _to_unicode(hive)
    local_key = _to_unicode(key)
    local_vname = _to_unicode(vname)
    local_vtype = _to_unicode(vtype)

    registry = Registry()
    try:
        hkey = registry.hkeys[local_hive]
    except KeyError:
        raise CommandExecutionError("Invalid Hive: {0}".format(local_hive))
    vtype_value = registry.vtype[local_vtype]
    access_mask = registry.registry_32[
        use_32bit_registry] | win32con.KEY_ALL_ACCESS

    local_vdata = cast_vdata(vdata=vdata, vtype=local_vtype)

    if volatile:
        create_options = registry.opttype["REG_OPTION_VOLATILE"]
    else:
        create_options = registry.opttype["REG_OPTION_NON_VOLATILE"]

    handle = None
    try:
        handle, result = win32api.RegCreateKeyEx(hkey,
                                                 local_key,
                                                 access_mask,
                                                 Options=create_options)
        msg = ("Created new key: %s\\%s"
               if result == 1 else "Opened existing key: %s\\%s")
        log.debug(msg, local_hive, local_key)

        try:
            win32api.RegSetValueEx(handle, local_vname, 0, vtype_value,
                                   local_vdata)
            win32api.RegFlushKey(handle)
            broadcast_change()
            return True
        except TypeError as exc:
            log.exception('"vdata" does not match the expected data type.\n%s',
                          exc)
            return False
        except (SystemError, ValueError) as exc:
            log.exception("Encountered error setting registry value.\n%s", exc)
            return False

    except win32api.error as exc:
        log.exception(
            "Error creating/opening key: %s\\%s\n%s",
            local_hive,
            local_key,
            exc.winerror,
        )
        return False

    finally:
        if handle:
            win32api.RegCloseKey(handle)