Update to bugfix release 2015.5.9

e9
Erik Johnson 9 years ago
parent 87e4671a30
commit 2530cd6e8f

1
.gitignore vendored

@ -58,3 +58,4 @@
/salt-2015.5.5.tar.gz
/salt-2015.5.8.tar.gz
/salt-2015.8.3.tar.gz
/salt-2015.5.9.tar.gz

@ -0,0 +1,979 @@
diff --git a/doc/ref/modules/all/salt.modules.yumpkg.rst b/doc/ref/modules/all/salt.modules.yumpkg.rst
index b385a7d..cfebeea 100644
--- a/doc/ref/modules/all/salt.modules.yumpkg.rst
+++ b/doc/ref/modules/all/salt.modules.yumpkg.rst
@@ -4,4 +4,4 @@ salt.modules.yumpkg
.. automodule:: salt.modules.yumpkg
:members:
- :exclude-members: available_version
\ No newline at end of file
+ :exclude-members: available_version, get_locked_packages
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 25b26f0..5a15d4d 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
'''
-Support for YUM
+Support for YUM/DNF
.. note::
This module makes heavy use of the **repoquery** utility, from the
@@ -9,6 +9,10 @@ Support for YUM
host is being managed using salt-ssh, then as of version 2014.7.0
yum-utils_ will be installed automatically to satisfy this dependency.
+ DNF is fully supported as of version 2015.5.10 and 2015.8.4. For these
+ versions, repoquery is available from the ``dnf-plugins-core`` package.
+ DNF support has been backported into the Fedora RPMs for 2015.5.9.
+
.. _yum-utils: http://yum.baseurl.org/wiki/YumUtils
'''
@@ -19,13 +23,14 @@ import copy
import logging
import os
import re
+import string
from distutils.version import LooseVersion as _LooseVersion # pylint: disable=no-name-in-module,import-error
# Import 3rd-party libs
# pylint: disable=import-error,redefined-builtin
import salt.ext.six as six
from salt.ext.six import string_types
-from salt.ext.six.moves import shlex_quote as _cmd_quote, range
+from salt.ext.six.moves import shlex_quote as _cmd_quote
try:
import yum
@@ -133,20 +138,87 @@ def _repoquery_pkginfo(repoquery_args):
return ret
+def _yum():
+ '''
+ return yum or dnf depending on version
+ '''
+ contextkey = 'yum_bin'
+ if contextkey not in __context__:
+ if 'fedora' in __grains__['os'].lower() \
+ and int(__grains__['osrelease']) >= 22:
+ __context__[contextkey] = 'dnf'
+ else:
+ __context__[contextkey] = 'yum'
+ return __context__[contextkey]
+
+
def _check_repoquery():
'''
Check for existence of repoquery and install yum-utils if it is not
present.
'''
- if not salt.utils.which('repoquery'):
- __salt__['cmd.run'](
- ['yum', '-y', 'install', 'yum-utils'],
- python_shell=False,
- output_loglevel='trace'
+ contextkey = 'yumpkg.has_repoquery'
+ if contextkey in __context__:
+ # We don't really care about the return value, we're just using this
+ # context key as a marker so that we know that repoquery is available,
+ # and we don't have to continue to repeat the check if this function is
+ # called more than once per run. If repoquery is not available, we
+ # raise an exception.
+ return
+
+ if _yum() == 'dnf':
+ # For some silly reason the core plugins and their manpages are in
+ # separate packages. The dnf-plugins-core package contains the manpages
+ # and depends on python-dnf-plugins-core (which contains the actual
+ # plugins).
+ pkgs = ['dnf-plugins-core', 'python-dnf-plugins-core']
+
+ def _check_plugins():
+ if __salt__['cmd.retcode'](['rpm', '-q'] + pkgs,
+ python_shell=False,
+ ignore_retcode=True) == 0:
+ __context__[contextkey] = True
+ return True
+ return False
+
+ if not _check_plugins():
+ __salt__['cmd.run'](['dnf', '-y', 'install'] + pkgs,
+ python_shell=False,
+ output_loglevel='trace')
+ # Check again now that we've installed dnf-plugins-core
+ if not _check_plugins():
+ raise CommandExecutionError('Unable to install dnf-plugins-core')
+ else:
+ if salt.utils.which('repoquery'):
+ __context__[contextkey] = True
+ else:
+ __salt__['cmd.run'](
+ ['yum', '-y', 'install', 'yum-utils'],
+ python_shell=False,
+ output_loglevel='trace'
+ )
+ # Check again now that we've installed yum-utils
+ if salt.utils.which('repoquery'):
+ __context__[contextkey] = True
+ else:
+ raise CommandExecutionError('Unable to install yum-utils')
+
+
+def _check_versionlock():
+ '''
+ Ensure that the appropriate versionlock plugin is present
+ '''
+ if _yum() == 'dnf':
+ vl_plugin = 'python-dnf-plugins-extras-versionlock'
+ else:
+ vl_plugin = 'yum-versionlock' \
+ if __grains__.get('osmajorrelease') == '5' \
+ else 'yum-plugin-versionlock'
+
+ if vl_plugin not in list_pkgs():
+ raise SaltInvocationError(
+ 'Cannot proceed, {0} is not installed.'.format(vl_plugin)
)
- # Check again now that we've installed yum-utils
- if not salt.utils.which('repoquery'):
- raise CommandExecutionError('Unable to install yum-utils')
def _repoquery(repoquery_args, query_format=__QUERYFORMAT):
@@ -154,9 +226,17 @@ def _repoquery(repoquery_args, query_format=__QUERYFORMAT):
Runs a repoquery command and returns a list of namedtuples
'''
_check_repoquery()
- cmd = 'repoquery --plugins --queryformat {0} {1}'.format(
- _cmd_quote(query_format), repoquery_args
- )
+ if _yum() == 'dnf':
+ cmd = 'dnf repoquery --quiet --queryformat {0} {1}'.format(
+ _cmd_quote(
+ query_format.replace('-%{VERSION}_', '-%{EPOCH}:%{VERSION}_')
+ ),
+ repoquery_args
+ )
+ else:
+ cmd = 'repoquery --plugins --queryformat {0} {1}'.format(
+ _cmd_quote(query_format), repoquery_args
+ )
call = __salt__['cmd.run_all'](cmd, output_loglevel='trace')
if call['retcode'] != 0:
comment = ''
@@ -164,12 +244,13 @@ def _repoquery(repoquery_args, query_format=__QUERYFORMAT):
comment += call['stderr']
if 'stdout' in call:
comment += call['stdout']
- raise CommandExecutionError(
- '{0}'.format(comment)
- )
+ raise CommandExecutionError(comment)
else:
- out = call['stdout']
- return out.splitlines()
+ if _yum() == 'dnf':
+ # Remove the epoch when it is zero to maintain backward compatibility
+ return call['stdout'].replace('_|-0:', '_|-').splitlines()
+ else:
+ return call['stdout'].splitlines()
def _get_repo_options(**kwargs):
@@ -187,20 +268,39 @@ def _get_repo_options(**kwargs):
if repo and not fromrepo:
fromrepo = repo
- repo_arg = ''
+ use_dnf_repoquery = kwargs.get('repoquery', False) and _yum() == 'dnf'
+ repo_arg = []
if fromrepo:
- log.info('Restricting to repo {0!r}'.format(fromrepo))
- repo_arg = ('--disablerepo={0!r} --enablerepo={1!r}'
- .format('*', fromrepo))
+ log.info('Restricting to repo \'{0}\''.format(fromrepo))
+ if use_dnf_repoquery:
+ # dnf-plugins-core renamed --repoid to --repo in version 0.1.7, but
+ # still keeps it as a hidden option for backwards compatibility.
+ # This is good, because --repo does not work at all (see
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1299261 for more
+ # information). Using --repoid here so this will actually work.
+ repo_arg.append('--repoid=\'{0}\''.format(fromrepo))
+ else:
+ repo_arg.append(
+ '--disablerepo=\'*\' --enablerepo=\'{0}\''.format(fromrepo)
+ )
else:
- repo_arg = ''
if disablerepo:
- log.info('Disabling repo {0!r}'.format(disablerepo))
- repo_arg += '--disablerepo={0!r}'.format(disablerepo)
+ if use_dnf_repoquery:
+ log.warning(
+ 'ignoring disablerepo, not supported in dnf repoquery'
+ )
+ else:
+ log.info('Disabling repo \'{0}\''.format(disablerepo))
+ repo_arg.append('--disablerepo=\'{0}\''.format(disablerepo))
if enablerepo:
- log.info('Enabling repo {0!r}'.format(enablerepo))
- repo_arg += '--enablerepo={0!r}'.format(enablerepo)
- return repo_arg
+ if use_dnf_repoquery:
+ log.warning(
+ 'ignoring enablerepo, not supported in dnf repoquery'
+ )
+ else:
+ log.info('Enabling repo \'{0}\''.format(enablerepo))
+ repo_arg.append('--enablerepo=\'{0}\''.format(enablerepo))
+ return ' '.join(repo_arg)
def _get_excludes_option(**kwargs):
@@ -208,14 +308,18 @@ def _get_excludes_option(**kwargs):
Returns a string of '--disableexcludes' option to be used in the yum command,
based on the kwargs.
'''
- disable_excludes_arg = ''
disable_excludes = kwargs.get('disableexcludes', '')
if disable_excludes:
- log.info('Disabling excludes for {0!r}'.format(disable_excludes))
- disable_excludes_arg = ('--disableexcludes={0!r}'.format(disable_excludes))
-
- return disable_excludes_arg
+ if kwargs.get('repoquery', False) and _yum() == 'dnf':
+ log.warning(
+ 'Ignoring disableexcludes, not supported in dnf repoquery'
+ )
+ return ''
+ else:
+ log.info('Disabling excludes for \'{0}\''.format(disable_excludes))
+ return '--disableexcludes=\'{0}\''.format(disable_excludes)
+ return ''
def _get_branch_option(**kwargs):
@@ -248,7 +352,7 @@ def _rpm_pkginfo(name):
# with 'none'
queryformat = __QUERYFORMAT.replace('%{REPOID}', 'none')
output = __salt__['cmd.run_stdout'](
- 'rpm -qp --queryformat {0!r} {1}'.format(_cmd_quote(queryformat), name),
+ 'rpm -qp --queryformat {0} {1}'.format(_cmd_quote(queryformat), name),
output_loglevel='trace',
ignore_retcode=True
)
@@ -454,19 +558,61 @@ def latest_version(*names, **kwargs):
if refresh:
refresh_db(**kwargs)
- # Get updates for specified package(s)
- updates = _repoquery_pkginfo(
- '{0} {1} --pkgnarrow=available {2}'
- .format(repo_arg, exclude_arg, ' '.join(names))
- )
-
- for name in names:
- for pkg in (x for x in updates if x.name == name):
+ def _query_pkgs(name, pkgs):
+ '''
+ Return the newest available match from the _repoquery_pkginfo() output
+ '''
+ matches = []
+ for pkg in (x for x in pkgs if x.name == name):
if pkg.arch == 'noarch' or pkg.arch == namearch_map[name] \
or _check_32(pkg.arch):
- ret[name] = pkg.version
- # no need to check another match, if there was one
- break
+ matches.append(pkg.version)
+ sorted_matches = sorted(
+ [_LooseVersion(x) for x in matches],
+ reverse=True
+ )
+ try:
+ return sorted_matches[0].vstring
+ except IndexError:
+ return None
+
+ if _yum() == 'dnf':
+ avail_pkgs = _repoquery_pkginfo(
+ '{0} --available {1}'.format(repo_arg, ' '.join(names))
+ )
+ # When using 'dnf repoquery --available', all available versions are
+ # returned, irrespective of whether or not they are installed. This is
+ # different from how yum-utils' version of repoquery works.
+ all_pkgs = list_pkgs(versions_as_list=True)
+ for name in names:
+ # Get newest available version of package
+ newest_avail = _query_pkgs(name, avail_pkgs)
+ if newest_avail is None:
+ # No matches, no need to check if pacakge is already installed
+ continue
+ # Get newest installed version of package
+ try:
+ cver = all_pkgs.get(name, [])[-1]
+ except IndexError:
+ cver = None
+ if cver is None \
+ or salt.utils.compare_versions(ver1=newest_avail,
+ oper='>',
+ ver2=cver,
+ cmp_func=version_cmp):
+ ret[name] = newest_avail
+ else:
+ avail_pkgs = _repoquery_pkginfo(
+ '{0} {1} --pkgnarrow=available {2}'.format(
+ repo_arg,
+ exclude_arg,
+ ' '.join(names)
+ )
+ )
+ for name in names:
+ newest_avail = _query_pkgs(name, avail_pkgs)
+ if newest_avail is not None:
+ ret[name] = newest_avail
# Return a string if only one package name passed
if len(names) == 1:
@@ -568,8 +714,13 @@ def list_pkgs(versions_as_list=False, **kwargs):
__salt__['pkg_resource.stringify'](ret)
return ret
+ if _yum() == 'dnf':
+ list_cmd = '--installed'
+ else:
+ list_cmd = '--all --pkgnarrow=installed'
+
ret = {}
- for pkginfo in _repoquery_pkginfo('--all --pkgnarrow=installed'):
+ for pkginfo in _repoquery_pkginfo(list_cmd):
if pkginfo is None:
continue
__salt__['pkg_resource.add_pkg'](ret, pkginfo.name, pkginfo.version)
@@ -644,7 +795,11 @@ def list_repo_pkgs(*args, **kwargs):
ret = {}
for repo in repos:
- repoquery_cmd = '--all --repoid="{0}" --show-duplicates'.format(repo)
+ if _yum() == 'dnf':
+ # As of 0.1.15, dnf repoquery does not support showing duplicates
+ repoquery_cmd = '--repoid="{0}"'.format(repo)
+ else:
+ repoquery_cmd = '--all --repoid="{0}" --show-duplicates'.format(repo)
for arg in args:
repoquery_cmd += ' "{0}"'.format(arg)
all_pkgs = _repoquery_pkginfo(repoquery_cmd)
@@ -669,7 +824,8 @@ def list_upgrades(refresh=True, **kwargs):
The ``fromrepo``, ``enablerepo``, and ``disablerepo`` arguments are
supported, as used in pkg states, and the ``disableexcludes`` option is
- also supported.
+ also supported. However, in Fedora 22 and newer all of these but
+ ``fromrepo`` is ignored.
.. versionadded:: 2014.7.0
Support for the ``disableexcludes`` option
@@ -685,9 +841,14 @@ def list_upgrades(refresh=True, **kwargs):
if salt.utils.is_true(refresh):
refresh_db(**kwargs)
- updates = _repoquery_pkginfo(
- '{0} {1} --all --pkgnarrow=updates'.format(repo_arg, exclude_arg)
- )
+
+ if _yum() == 'dnf':
+ upgrades_cmd = '{0} --upgrades'.format(repo_arg)
+ else:
+ upgrades_cmd = '{0} {1} --all --pkgnarrow=updates'.format(
+ repo_arg, exclude_arg)
+
+ updates = _repoquery_pkginfo(upgrades_cmd)
return dict([(x.name, x.version) for x in updates])
@@ -705,7 +866,8 @@ def check_db(*names, **kwargs):
The ``fromrepo``, ``enablerepo`` and ``disablerepo`` arguments are
supported, as used in pkg states, and the ``disableexcludes`` option is
- also supported.
+ also supported. However, in Fedora 22 and newer all of these but
+ ``fromrepo`` is ignored.
.. versionadded:: 2014.7.0
Support for the ``disableexcludes`` option
@@ -719,29 +881,33 @@ def check_db(*names, **kwargs):
salt '*' pkg.check_db <package1> <package2> <package3> disableexcludes=main
'''
normalize = kwargs.pop('normalize') if kwargs.get('normalize') else False
- repo_arg = _get_repo_options(**kwargs)
- exclude_arg = _get_excludes_option(**kwargs)
- repoquery_base = \
- '{0} {1} --all --quiet --whatprovides'.format(repo_arg, exclude_arg)
+ repo_arg = _get_repo_options(repoquery=True, **kwargs)
+ exclude_arg = _get_excludes_option(repoquery=True, **kwargs)
+
+ if _yum() == 'dnf':
+ repoquery_base = '{0} --whatprovides'.format(repo_arg)
+ avail_cmd = repo_arg
+ else:
+ repoquery_base = '{0} {1} --all --quiet --whatprovides'.format(
+ repo_arg, exclude_arg)
+ avail_cmd = '{0} --pkgnarrow=all --all'.format(repo_arg)
if 'pkg._avail' in __context__:
avail = __context__['pkg._avail']
else:
# get list of available packages
- avail = []
- lines = _repoquery(
- '{0} --pkgnarrow=all --all'.format(repo_arg),
- query_format='%{NAME}_|-%{ARCH}'
- )
+ avail = set()
+ lines = _repoquery(avail_cmd, query_format='%{NAME}_|-%{ARCH}')
for line in lines:
try:
name, arch = line.split('_|-')
except ValueError:
continue
if normalize:
- avail.append(normalize_name('.'.join((name, arch))))
+ avail.add(normalize_name('.'.join((name, arch))))
else:
- avail.append('.'.join((name, arch)))
+ avail.add('.'.join((name, arch)))
+ avail = sorted(avail)
__context__['pkg._avail'] = avail
ret = {}
@@ -806,13 +972,16 @@ def refresh_db(**kwargs):
repo_arg = _get_repo_options(**kwargs)
exclude_arg = _get_excludes_option(**kwargs)
branch_arg = _get_branch_option(**kwargs)
+ yum_cmd = _yum()
- clean_cmd = 'yum -q clean expire-cache {repo} {exclude} {branch}'.format(
+ clean_cmd = '{yum} -q clean expire-cache {repo} {exclude} {branch}'.format(
+ yum=yum_cmd,
repo=repo_arg,
exclude=exclude_arg,
branch=branch_arg
)
- update_cmd = 'yum -q check-update {repo} {exclude} {branch}'.format(
+ update_cmd = '{yum} -q check-update {repo} {exclude} {branch}'.format(
+ yum=yum_cmd,
repo=repo_arg,
exclude=exclude_arg,
branch=branch_arg
@@ -1137,8 +1306,10 @@ def install(name=None,
else:
downgrade.append(pkgstr)
+ yum_cmd = _yum()
if targets:
- cmd = 'yum -y {repo} {exclude} {branch} {gpgcheck} install {pkg}'.format(
+ cmd = '{yum} -y {repo} {exclude} {branch} {gpgcheck} install {pkg}'.format(
+ yum=yum_cmd,
repo=repo_arg,
exclude=exclude_arg,
branch=branch_arg,
@@ -1148,7 +1319,8 @@ def install(name=None,
__salt__['cmd.run'](cmd, output_loglevel='trace')
if downgrade:
- cmd = 'yum -y {repo} {exclude} {branch} {gpgcheck} downgrade {pkg}'.format(
+ cmd = '{yum} -y {repo} {exclude} {branch} {gpgcheck} downgrade {pkg}'.format(
+ yum=yum_cmd,
repo=repo_arg,
exclude=exclude_arg,
branch=branch_arg,
@@ -1158,7 +1330,8 @@ def install(name=None,
__salt__['cmd.run'](cmd, output_loglevel='trace')
if to_reinstall:
- cmd = 'yum -y {repo} {exclude} {branch} {gpgcheck} reinstall {pkg}'.format(
+ cmd = '{yum} -y {repo} {exclude} {branch} {gpgcheck} reinstall {pkg}'.format(
+ yum=yum_cmd,
repo=repo_arg,
exclude=exclude_arg,
branch=branch_arg,
@@ -1228,7 +1401,8 @@ def upgrade(refresh=True, skip_verify=False, **kwargs):
refresh_db(**kwargs)
old = list_pkgs()
- cmd = 'yum -q -y {repo} {exclude} {branch} {gpgcheck} upgrade'.format(
+ cmd = '{yum} -q -y {repo} {exclude} {branch} {gpgcheck} upgrade'.format(
+ yum=_yum(),
repo=repo_arg,
exclude=exclude_arg,
branch=branch_arg,
@@ -1248,7 +1422,7 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
Remove packages with ``yum -q -y remove``.
name
- The name of the package to be deleted.
+ The name of the package to be removed
Multiple Package Options:
@@ -1280,7 +1454,7 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
if not targets:
return {}
quoted_targets = [_cmd_quote(target) for target in targets]
- cmd = 'yum -q -y remove {0}'.format(' '.join(quoted_targets))
+ cmd = _yum() + ' -y remove {0}'.format(' '.join(quoted_targets))
__salt__['cmd.run'](cmd, output_loglevel='trace')
__context__.pop('pkg.list_pkgs', None)
new = list_pkgs()
@@ -1296,7 +1470,7 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
:mod:`pkg.remove <salt.modules.yumpkg.remove>`.
name
- The name of the package to be deleted.
+ The name of the package to be purged
Multiple Package Options:
@@ -1325,7 +1499,15 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
'''
.. versionadded:: 2014.7.0
- Hold packages with ``yum -q versionlock``.
+ Version-lock packages
+
+ .. note::
+ Requires the appropriate ``versionlock`` plugin package to be installed:
+
+ - On RHEL 5: ``yum-versionlock``
+ - On RHEL 6 & 7: ``yum-plugin-versionlock``
+ - On Fedora: ``python-dnf-plugins-extras-versionlock``
+
name
The name of the package to be held.
@@ -1345,13 +1527,8 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
salt '*' pkg.hold <package name>
salt '*' pkg.hold pkgs='["foo", "bar"]'
'''
+ _check_versionlock()
- on_redhat_5 = __grains__.get('osmajorrelease', None) == '5'
- lock_pkg = 'yum-versionlock' if on_redhat_5 else 'yum-plugin-versionlock'
- if lock_pkg not in list_pkgs():
- raise SaltInvocationError(
- 'Packages cannot be held, {0} is not installed.'.format(lock_pkg)
- )
if not name and not pkgs and not sources:
raise SaltInvocationError(
'One of name, pkgs, or sources must be specified.'
@@ -1381,7 +1558,7 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
)
targets.append(name)
- current_locks = get_locked_packages(full=False)
+ current_locks = list_holds(full=False)
ret = {}
for target in targets:
if isinstance(target, dict):
@@ -1398,7 +1575,7 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
ret[target]['comment'] = ('Package {0} is set to be held.'
.format(target))
else:
- cmd = 'yum -q versionlock {0}'.format(target)
+ cmd = _yum() + ' versionlock {0}'.format(target)
out = __salt__['cmd.run_all'](cmd)
if out['retcode'] == 0:
@@ -1421,10 +1598,18 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06
'''
.. versionadded:: 2014.7.0
- Hold packages with ``yum -q versionlock``.
+ Remove version locks
+
+ .. note::
+ Requires the appropriate ``versionlock`` plugin package to be installed:
+
+ - On RHEL 5: ``yum-versionlock``
+ - On RHEL 6 & 7: ``yum-plugin-versionlock``
+ - On Fedora: ``python-dnf-plugins-extras-versionlock``
+
name
- The name of the package to be deleted.
+ The name of the package to be unheld
Multiple Package Options:
@@ -1441,13 +1626,8 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06
salt '*' pkg.unhold <package name>
salt '*' pkg.unhold pkgs='["foo", "bar"]'
'''
+ _check_versionlock()
- on_redhat_5 = __grains__.get('osmajorrelease', None) == '5'
- lock_pkg = 'yum-versionlock' if on_redhat_5 else 'yum-plugin-versionlock'
- if lock_pkg not in list_pkgs():
- raise SaltInvocationError(
- 'Packages cannot be unheld, {0} is not installed.'.format(lock_pkg)
- )
if not name and not pkgs and not sources:
raise SaltInvocationError(
'One of name, pkgs, or sources must be specified.'
@@ -1467,7 +1647,7 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06
else:
targets.append(name)
- current_locks = get_locked_packages(full=True)
+ current_locks = list_holds(full=False)
ret = {}
for target in targets:
if isinstance(target, dict):
@@ -1487,7 +1667,7 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06
.format(target))
else:
quoted_targets = [_cmd_quote(item) for item in search_locks]
- cmd = 'yum -q versionlock delete {0}'.format(
+ cmd = _yum() + ' -q versionlock delete {0}'.format(
' '.join(quoted_targets)
)
out = __salt__['cmd.run_all'](cmd)
@@ -1508,45 +1688,71 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06
return ret
-def get_locked_packages(pattern=None, full=True):
- '''
- Get packages that are currently locked
- ``yum -q versionlock list``.
+def list_holds(pattern=r'\w+(?:[.-][^-]+)*', full=True):
+ r'''
+ .. versionchanged:: Boron,2015.8.4,2015.5.10
+ Function renamed from ``pkg.get_locked_pkgs`` to ``pkg.list_holds``.
+
+ List information on locked packages
+
+ .. note::
+ Requires the appropriate ``versionlock`` plugin package to be installed:
+
+ - On RHEL 5: ``yum-versionlock``
+ - On RHEL 6 & 7: ``yum-plugin-versionlock``
+ - On Fedora: ``python-dnf-plugins-extras-versionlock``
+
+ pattern : \w+(?:[.-][^-]+)*
+ Regular expression used to match the package name
+
+ full : True
+ Show the full hold definition including version and epoch. Set to
+ ``False`` to return just the name of the package(s) being held.
+
CLI Example:
.. code-block:: bash
- salt '*' pkg.get_locked_packages
+ salt '*' pkg.list_holds
+ salt '*' pkg.list_holds full=False
'''
- cmd = 'yum -q versionlock list'
- ret = __salt__['cmd.run'](cmd).split('\n')
+ _check_versionlock()
- if pattern:
- if full:
- _pat = r'(\d\:{0}\-\S+)'.format(pattern)
+ # yum ==> 2:vim-enhanced-7.4.629-5.el6.*
+ # dnf ==> vim-enhanced-2:7.4.827-1.fc22.*
+
+ yum_cmd = _yum()
+ if full:
+ if yum_cmd == 'dnf':
+ lock_re = r'({0}-\S+)'.format(pattern)
else:
- _pat = r'\d\:({0}\-\S+)'.format(pattern)
+ lock_re = r'(\d+:{0}-\S+)'.format(pattern)
else:
- if full:
- _pat = r'(\d\:\w+(?:[\.\-][^\-]+)*-\S+)'
+ if yum_cmd == 'dnf':
+ lock_re = r'({0}-\S+)'.format(pattern)
else:
- _pat = r'\d\:(\w+(?:[\.\-][^\-]+)*-\S+)'
- pat = re.compile(_pat)
+ lock_re = r'\d+:({0}-\S+)'.format(pattern)
+
+ pat = re.compile(lock_re)
- current_locks = []
- for item in ret:
+ out = __salt__['cmd.run']([yum_cmd, 'versionlock', 'list'],
+ python_shell=False)
+ ret = []
+ for item in out.splitlines():
match = pat.search(item)
if match:
if not full:
woarch = match.group(1).rsplit('.', 1)[0]
worel = woarch.rsplit('-', 1)[0]
wover = worel.rsplit('-', 1)[0]
- _match = wover
+ target = wover
else:
- _match = match.group(1)
- current_locks.append(_match)
- return current_locks
+ target = match.group(1)
+ ret.append(target)
+ return ret
+
+get_locked_packages = list_holds
def verify(*names, **kwargs):
@@ -1582,42 +1788,62 @@ def group_list():
salt '*' pkg.group_list
'''
- ret = {'installed': [], 'available': [], 'available languages': {}}
- cmd = 'yum grouplist'
- out = __salt__['cmd.run_stdout'](cmd, output_loglevel='trace').splitlines()
+ ret = {'installed': [],
+ 'available': [],
+ 'installed environments': [],
+ 'available environments': [],
+ 'available languages': {}}
+
+ section_map = {
+ 'installed groups:': 'installed',
+ 'available groups:': 'available',
+ 'installed environment groups:': 'installed environments',
+ 'available environment groups:': 'available environments',
+ 'available language groups:': 'available languages',
+ }
+
+ out = __salt__['cmd.run_stdout'](
+ [_yum(), 'grouplist', 'hidden'],
+ output_loglevel='trace',
+ python_shell=False
+ )
key = None
- for idx in range(len(out)):
- if out[idx] == 'Installed Groups:':
- key = 'installed'
- continue
- elif out[idx] == 'Available Groups:':
- key = 'available'
- continue
- elif out[idx] == 'Available Language Groups:':
- key = 'available languages'
- continue
- elif out[idx] == 'Done':
+ for line in out.splitlines():
+ line_lc = line.lower()
+ if line_lc == 'done':
+ break
+
+ section_lookup = section_map.get(line_lc)
+ if section_lookup is not None and section_lookup != key:
+ key = section_lookup
continue
+ # Ignore any administrative comments (plugin info, repo info, etc.)
if key is None:
continue
+ line = line.strip()
if key != 'available languages':
- ret[key].append(out[idx].strip())
+ ret[key].append(line)
else:
- line = out[idx].strip()
- try:
- name, lang = re.match(r'(.+) \[(.+)\]', line).groups()
- except AttributeError:
- pass
- else:
+ match = re.match(r'(.+) \[(.+)\]', line)
+ if match:
+ name, lang = match.groups()
ret[key][line] = {'name': name, 'language': lang}
return ret
-def group_info(name):
+def group_info(name, expand=False):
'''
.. versionadded:: 2014.1.0
+ .. versionchanged:: Boron,2015.8.4,2015.5.10
+ The return data has changed. A new key ``type`` has been added to
+ distinguish environment groups from package groups. Also, keys for the
+ group name and group ID have been added. The ``mandatory packages``,
+ ``optional packages``, and ``default packages`` keys have been renamed
+ to ``mandatory``, ``optional``, and ``default`` for accuracy, as
+ environment groups include other groups, and not packages. Finally,
+ this function now properly identifies conditional packages.
Lists packages belonging to a certain group
@@ -1627,44 +1853,67 @@ def group_info(name):
salt '*' pkg.group_info 'Perl Support'
'''
- # Not using _repoquery_pkginfo() here because group queries are handled
- # differently, and ignore the '--queryformat' param
- ret = {
- 'mandatory packages': [],
- 'optional packages': [],
- 'default packages': [],
- 'description': ''
- }
- cmd_template = 'repoquery --plugins --group --grouppkgs={0} --list {1}'
-
- cmd = cmd_template.format('all', _cmd_quote(name))
- out = __salt__['cmd.run_stdout'](cmd, output_loglevel='trace')
- all_pkgs = set(out.splitlines())
-
- if not all_pkgs:
- raise CommandExecutionError('Group {0!r} not found'.format(name))
+ pkgtypes = ('mandatory', 'optional', 'default', 'conditional')
+ ret = {}
+ for pkgtype in pkgtypes:
+ ret[pkgtype] = set()
- for pkgtype in ('mandatory', 'optional', 'default'):
- cmd = cmd_template.format(pkgtype, _cmd_quote(name))
- packages = set(
- __salt__['cmd.run_stdout'](
- cmd, output_loglevel='trace'
- ).splitlines()
- )
- ret['{0} packages'.format(pkgtype)].extend(sorted(packages))
- all_pkgs -= packages
+ cmd = [_yum(), '--quiet', 'groupinfo', name]
+ out = __salt__['cmd.run_stdout'](
+ cmd,
+ output_loglevel='trace',
+ python_shell=False
+ )
- # 'contitional' is not a valid --grouppkgs value. Any pkgs that show up
- # in '--grouppkgs=all' that aren't in mandatory, optional, or default are
- # considered to be conditional packages.
- ret['conditional packages'] = sorted(all_pkgs)
+ g_info = {}
+ for line in out.splitlines():
+ try:
+ key, value = [x.strip() for x in line.split(':')]
+ g_info[key.lower()] = value
+ except ValueError:
+ continue
- cmd = 'repoquery --plugins --group --info {0}'.format(_cmd_quote(name))
- out = __salt__['cmd.run_stdout'](
- cmd, output_loglevel='trace'
+ if 'environment group' in g_info:
+ ret['type'] = 'environment group'
+ elif 'group' in g_info:
+ ret['type'] = 'package group'
+
+ ret['group'] = g_info.get('environment group') or g_info.get('group')
+ ret['id'] = g_info.get('environment-id') or g_info.get('group-id')
+ if not ret['group'] and not ret['id']:
+ raise CommandExecutionError('Group \'{0}\' not found'.format(name))
+
+ ret['description'] = g_info.get('description', '')
+
+ pkgtypes_capturegroup = '(' + '|'.join(pkgtypes) + ')'
+ for pkgtype in pkgtypes:
+ target_found = False
+ for line in out.splitlines():
+ line = line.strip().lstrip(string.punctuation)
+ match = re.match(
+ pkgtypes_capturegroup + r' (?:groups|packages):\s*$',
+ line.lower()
)
- if out:
- ret['description'] = '\n'.join(out.splitlines()[1:]).strip()
+ if match:
+ if target_found:
+ # We've reached a new section, break from loop
+ break
+ else:
+ if match.group(1) == pkgtype:
+ # We've reached the targeted section
+ target_found = True
+ continue
+ if target_found:
+ if expand and ret['type'] == 'environment group':
+ expanded = group_info(line, expand=True)
+ # Don't shadow the pkgtype variable from the outer loop
+ for p_type in pkgtypes:
+ ret[p_type].update(set(expanded[p_type]))
+ else:
+ ret[pkgtype].add(line)
+
+ for pkgtype in pkgtypes:
+ ret[pkgtype] = sorted(ret[pkgtype])
return ret
@@ -1672,6 +1921,10 @@ def group_info(name):
def group_diff(name):
'''
.. versionadded:: 2014.1.0
+ .. versionchanged:: Boron,2015.8.4,2015.5.10
+ Environment groups are now supported. The key names have been renamed,
+ similar to the changes made in :py:func:`pkg.group_info
+ <salt.modules.yumpkg.group_info>`.
Lists packages belonging to a certain group, and which are installed
@@ -1681,21 +1934,19 @@ def group_diff(name):
salt '*' pkg.group_diff 'Perl Support'
'''
- ret = {
- 'mandatory packages': {'installed': [], 'not installed': []},
- 'optional packages': {'installed': [], 'not installed': []},
- 'default packages': {'installed': [], 'not installed': []},
- 'conditional packages': {'installed': [], 'not installed': []},
- }
+ pkgtypes = ('mandatory', 'optional', 'default', 'conditional')
+ ret = {}
+ for pkgtype in pkgtypes:
+ ret[pkgtype] = {'installed': [], 'not installed': []}
+
pkgs = list_pkgs()
- group_pkgs = group_info(name)
- for pkgtype in ('mandatory', 'optional', 'default', 'conditional'):
- for member in group_pkgs.get('{0} packages'.format(pkgtype), []):
- key = '{0} packages'.format(pkgtype)
+ group_pkgs = group_info(name, expand=True)
+ for pkgtype in pkgtypes:
+ for member in group_pkgs.get(pkgtype, []):
if member in pkgs:
- ret[key]['installed'].append(member)
+ ret[pkgtype]['installed'].append(member)
else:
- ret[key]['not installed'].append(member)
+ ret[pkgtype]['not installed'].append(member)
return ret
@@ -1732,7 +1983,9 @@ def list_repos(basedir=None):
def get_repo(repo, basedir=None, **kwargs): # pylint: disable=W0613
'''
- Display a repo from <basedir> (default basedir: all dirs in `reposdir` yum option).
+
+ Display a repo from <basedir> (default basedir: all dirs in ``reposdir``
+ yum option).
CLI Examples:

@ -15,7 +15,7 @@
%define _salttesting_ver 2015.7.10
Name: salt
Version: 2015.5.8
Version: 2015.5.9
Release: 1%{?dist}
Summary: A parallel remote execution system
@ -36,7 +36,7 @@ Source10: README.fedora
Source11: logrotate.salt
Source12: salt.bash
#Patch0: salt-%{version}-tests.patch
Patch0: 2015.5.9-dnf.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@ -48,7 +48,12 @@ Requires: dmidecode
Requires: pciutils
Requires: which
%if 0%{?fedora} > 21
Requires: dnf-plugins-core
%else
Requires: yum-utils
%endif
%if 0%{?with_python26}
@ -190,8 +195,8 @@ of an agent (salt-minion) service.
%setup -c
%setup -T -D -a 1
#cd %{name}-%{version}
#%patch0 -p1
cd %{name}-%{version}
%patch0 -p1
%build
@ -455,6 +460,9 @@ rm -rf %{buildroot}
%endif
%changelog
* Thu Jan 21 2016 Erik Johnson <erik@saltstack.com> - 2015.5.9-1
- Update to bugfix release 2015.5.9, patched with proper dnf support
* Sun Dec 20 2015 Erik Johnson <erik@saltstack.com> - 2015.5.8-1
- Update to bugfix release 2015.5.8

@ -1,2 +1,2 @@
b5fe2959dd1a993c3c850e984459af13 salt-2015.5.9.tar.gz
993296e827d4198c0ff0e7cb17d13e45 SaltTesting-2015.7.10.tar.gz
91352440e28bbed556130920acd53c0f salt-2015.5.8.tar.gz

Loading…
Cancel
Save