mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 09:23:56 +00:00
implement resolve_capabilities option for packages
This commit is contained in:
parent
b8db7ab7bf
commit
3d28be0938
@ -20,6 +20,7 @@ import re
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
|
import copy
|
||||||
|
|
||||||
# Import 3rd-party libs
|
# Import 3rd-party libs
|
||||||
# pylint: disable=import-error,redefined-builtin,no-name-in-module
|
# pylint: disable=import-error,redefined-builtin,no-name-in-module
|
||||||
@ -1049,6 +1050,10 @@ def install(name=None,
|
|||||||
operator (<, >, <=, >=, =) and a version number (ex. '>1.2.3-4').
|
operator (<, >, <=, >=, =) and a version number (ex. '>1.2.3-4').
|
||||||
This parameter is ignored if ``pkgs`` or ``sources`` is passed.
|
This parameter is ignored if ``pkgs`` or ``sources`` is passed.
|
||||||
|
|
||||||
|
resolve_capabilities
|
||||||
|
If this option is set to True zypper will take capabilites into
|
||||||
|
account. In this case names which are just provided by a package
|
||||||
|
will get installed. Default is False.
|
||||||
|
|
||||||
Multiple Package Installation Options:
|
Multiple Package Installation Options:
|
||||||
|
|
||||||
@ -1164,7 +1169,13 @@ def install(name=None,
|
|||||||
log.info('Targeting repo \'{0}\''.format(fromrepo))
|
log.info('Targeting repo \'{0}\''.format(fromrepo))
|
||||||
else:
|
else:
|
||||||
fromrepoopt = ''
|
fromrepoopt = ''
|
||||||
cmd_install = ['install', '--name', '--auto-agree-with-licenses']
|
cmd_install = ['install', '--auto-agree-with-licenses']
|
||||||
|
|
||||||
|
if kwargs.get('resolve_capabilities', False):
|
||||||
|
cmd_install.append('--capability')
|
||||||
|
else:
|
||||||
|
cmd_install.append('--name')
|
||||||
|
|
||||||
if not refresh:
|
if not refresh:
|
||||||
cmd_install.insert(0, '--no-refresh')
|
cmd_install.insert(0, '--no-refresh')
|
||||||
if skip_verify:
|
if skip_verify:
|
||||||
@ -1195,6 +1206,7 @@ def install(name=None,
|
|||||||
__zypper__(no_repo_failure=ignore_repo_failure).call(*cmd)
|
__zypper__(no_repo_failure=ignore_repo_failure).call(*cmd)
|
||||||
|
|
||||||
__context__.pop('pkg.list_pkgs', None)
|
__context__.pop('pkg.list_pkgs', None)
|
||||||
|
__context__.pop('pkg.list_list_provides', None)
|
||||||
new = list_pkgs(attr=diff_attr) if not downloadonly else list_downloaded()
|
new = list_pkgs(attr=diff_attr) if not downloadonly else list_downloaded()
|
||||||
|
|
||||||
# Handle packages which report multiple new versions
|
# Handle packages which report multiple new versions
|
||||||
@ -1312,6 +1324,7 @@ def upgrade(refresh=True,
|
|||||||
|
|
||||||
__zypper__(systemd_scope=_systemd_scope()).noraise.call(*cmd_update)
|
__zypper__(systemd_scope=_systemd_scope()).noraise.call(*cmd_update)
|
||||||
__context__.pop('pkg.list_pkgs', None)
|
__context__.pop('pkg.list_pkgs', None)
|
||||||
|
__context__.pop('pkg.list_list_provides', None)
|
||||||
new = list_pkgs()
|
new = list_pkgs()
|
||||||
|
|
||||||
# Handle packages which report multiple new versions
|
# Handle packages which report multiple new versions
|
||||||
@ -1361,6 +1374,7 @@ def _uninstall(name=None, pkgs=None):
|
|||||||
targets = targets[500:]
|
targets = targets[500:]
|
||||||
|
|
||||||
__context__.pop('pkg.list_pkgs', None)
|
__context__.pop('pkg.list_pkgs', None)
|
||||||
|
__context__.pop('pkg.list_list_provides', None)
|
||||||
ret = salt.utils.data.compare_dicts(old, list_pkgs())
|
ret = salt.utils.data.compare_dicts(old, list_pkgs())
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
@ -2109,3 +2123,85 @@ def list_installed_patches():
|
|||||||
salt '*' pkg.list_installed_patches
|
salt '*' pkg.list_installed_patches
|
||||||
'''
|
'''
|
||||||
return _get_patches(installed_only=True)
|
return _get_patches(installed_only=True)
|
||||||
|
|
||||||
|
def list_provides(**kwargs):
|
||||||
|
'''
|
||||||
|
List package provides currently installed as a dict.
|
||||||
|
{'<provided_name>': ['<package_name', 'package_name', ...]}
|
||||||
|
'''
|
||||||
|
if 'pkg.list_provides' in __context__:
|
||||||
|
cached = __context__['pkg.list_provides']
|
||||||
|
return cached
|
||||||
|
|
||||||
|
cmd = ['rpm', '-qa', '--queryformat', '[%{PROVIDES}_|-%{NAME}\n]']
|
||||||
|
ret = {}
|
||||||
|
for line in __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False).splitlines():
|
||||||
|
provide, realname = line.split('_|-')
|
||||||
|
|
||||||
|
if provide == realname:
|
||||||
|
continue
|
||||||
|
if provide not in ret:
|
||||||
|
ret[provide] = list()
|
||||||
|
ret[provide].append(realname)
|
||||||
|
|
||||||
|
__context__['pkg.list_list_provides'] = ret
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def resolve_capabilities(pkgs, refresh, **kwargs):
|
||||||
|
'''
|
||||||
|
.. versionadded:: Oxygen
|
||||||
|
|
||||||
|
Convert name provides in ``pkgs`` into real package names if
|
||||||
|
``resolve_capabilities`` parameter is set to True. In case of
|
||||||
|
``resolve_capabilities`` is set to False the package list
|
||||||
|
is returned unchanged.
|
||||||
|
|
||||||
|
refresh
|
||||||
|
force a refresh if set to True.
|
||||||
|
If set to False (default) it depends on zypper if a refresh is
|
||||||
|
executed.
|
||||||
|
|
||||||
|
resolve_capabilities
|
||||||
|
If this option is set to True the input will be checked if
|
||||||
|
a package with this name exists. If not, this function will
|
||||||
|
search for a package which provides this name. If one is found
|
||||||
|
the output is exchanged with the real package name.
|
||||||
|
In case this option is set to False (Default) the input will
|
||||||
|
be returned unchanged.
|
||||||
|
|
||||||
|
CLI Examples:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
salt '*' pkg.resolve_capabilities resolve_capabilities=True w3m_ssl
|
||||||
|
'''
|
||||||
|
if refresh:
|
||||||
|
refresh_db()
|
||||||
|
|
||||||
|
ret = list()
|
||||||
|
for pkg in pkgs:
|
||||||
|
if isinstance(pkg, dict):
|
||||||
|
for name, version in pkg.items():
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = pkg
|
||||||
|
version = None
|
||||||
|
|
||||||
|
if kwargs.get('resolve_capabilities', False):
|
||||||
|
try:
|
||||||
|
search(name, match='exact')
|
||||||
|
except CommandExecutionError as e:
|
||||||
|
# no package this such a name found
|
||||||
|
# search for a package which provides this name
|
||||||
|
result = search(name, provides=True, match='exact')
|
||||||
|
if len(result.keys()) == 1:
|
||||||
|
name = result.keys()[0]
|
||||||
|
elif len(result.keys()) > 1:
|
||||||
|
log.warn("Found ambiguous match for capability '{0}'.".format(pkg))
|
||||||
|
|
||||||
|
if version:
|
||||||
|
ret.append({name: version})
|
||||||
|
else:
|
||||||
|
ret.append(name)
|
||||||
|
return ret
|
||||||
|
@ -508,8 +508,11 @@ def _find_install_targets(name=None,
|
|||||||
# add it to the kwargs.
|
# add it to the kwargs.
|
||||||
kwargs['refresh'] = refresh
|
kwargs['refresh'] = refresh
|
||||||
|
|
||||||
|
|
||||||
|
resolve_capabilities = kwargs.get('resolve_capabilities', False) and 'pkg.list_provides' in __salt__
|
||||||
try:
|
try:
|
||||||
cur_pkgs = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs)
|
cur_pkgs = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs)
|
||||||
|
cur_prov = resolve_capabilities and __salt__['pkg.list_provides'](**kwargs) or dict()
|
||||||
except CommandExecutionError as exc:
|
except CommandExecutionError as exc:
|
||||||
return {'name': name,
|
return {'name': name,
|
||||||
'changes': {},
|
'changes': {},
|
||||||
@ -669,6 +672,9 @@ def _find_install_targets(name=None,
|
|||||||
failed_verify = False
|
failed_verify = False
|
||||||
for key, val in six.iteritems(desired):
|
for key, val in six.iteritems(desired):
|
||||||
cver = cur_pkgs.get(key, [])
|
cver = cur_pkgs.get(key, [])
|
||||||
|
if resolve_capabilities and not cver and key in cur_prov:
|
||||||
|
cver = cur_pkgs.get(cur_prov.get(key)[0], [])
|
||||||
|
|
||||||
# Package not yet installed, so add to targets
|
# Package not yet installed, so add to targets
|
||||||
if not cver:
|
if not cver:
|
||||||
targets[key] = val
|
targets[key] = val
|
||||||
@ -786,7 +792,7 @@ def _find_install_targets(name=None,
|
|||||||
warnings, was_refreshed)
|
warnings, was_refreshed)
|
||||||
|
|
||||||
|
|
||||||
def _verify_install(desired, new_pkgs, ignore_epoch=False):
|
def _verify_install(desired, new_pkgs, ignore_epoch=False, new_caps={}):
|
||||||
'''
|
'''
|
||||||
Determine whether or not the installed packages match what was requested in
|
Determine whether or not the installed packages match what was requested in
|
||||||
the SLS file.
|
the SLS file.
|
||||||
@ -809,6 +815,8 @@ def _verify_install(desired, new_pkgs, ignore_epoch=False):
|
|||||||
cver = new_pkgs.get(pkgname.split('=')[0])
|
cver = new_pkgs.get(pkgname.split('=')[0])
|
||||||
else:
|
else:
|
||||||
cver = new_pkgs.get(pkgname)
|
cver = new_pkgs.get(pkgname)
|
||||||
|
if not cver and pkgname in new_caps:
|
||||||
|
cver = new_pkgs.get(new_caps.get(pkgname)[0])
|
||||||
|
|
||||||
if not cver:
|
if not cver:
|
||||||
failed.append(pkgname)
|
failed.append(pkgname)
|
||||||
@ -872,6 +880,27 @@ def _nested_output(obj):
|
|||||||
ret = nested.output(obj).rstrip()
|
ret = nested.output(obj).rstrip()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def _resolve_capabilities(pkgs, refresh=False, **kwargs):
|
||||||
|
'''
|
||||||
|
Resolve capabilities in ``pkgs`` and exchange them with real package
|
||||||
|
names, when the result is distinct.
|
||||||
|
This feature can be turned on while setting the paramter
|
||||||
|
``resolve_capabilities`` to True.
|
||||||
|
|
||||||
|
Return the input dictionary with replaced capability names and as
|
||||||
|
second return value a bool which indicate if a refresh was run.
|
||||||
|
|
||||||
|
In case of ``resolve_capabilities`` is False (disabled) or not
|
||||||
|
supported by the implementation the input is returned unchanged.
|
||||||
|
'''
|
||||||
|
was_refreshed = False
|
||||||
|
if not pkgs or 'pkg.resolve_capabilities' not in __salt__:
|
||||||
|
return (pkgs, was_refreshed)
|
||||||
|
|
||||||
|
ret = __salt__['pkg.resolve_capabilities'](pkgs, refresh=refresh, **kwargs)
|
||||||
|
was_refreshed = refresh
|
||||||
|
return (ret, was_refreshed)
|
||||||
|
|
||||||
|
|
||||||
def installed(
|
def installed(
|
||||||
name,
|
name,
|
||||||
@ -1105,6 +1134,11 @@ def installed(
|
|||||||
|
|
||||||
.. versionadded:: 2014.1.1
|
.. versionadded:: 2014.1.1
|
||||||
|
|
||||||
|
:param bool resolve_capabilities:
|
||||||
|
Turn on resolving capabilities. This allow to name "provides" or alias names for packages.
|
||||||
|
|
||||||
|
.. versionadded:: Oxygen
|
||||||
|
|
||||||
:param bool allow_updates:
|
:param bool allow_updates:
|
||||||
Allow the package to be updated outside Salt's control (e.g. auto
|
Allow the package to be updated outside Salt's control (e.g. auto
|
||||||
updates on Windows). This means a package on the Minion can have a
|
updates on Windows). This means a package on the Minion can have a
|
||||||
@ -1448,6 +1482,14 @@ def installed(
|
|||||||
|
|
||||||
kwargs['saltenv'] = __env__
|
kwargs['saltenv'] = __env__
|
||||||
refresh = salt.utils.pkg.check_refresh(__opts__, refresh)
|
refresh = salt.utils.pkg.check_refresh(__opts__, refresh)
|
||||||
|
|
||||||
|
# check if capabilities should be checked and modify the requested packages
|
||||||
|
# accordingly.
|
||||||
|
if pkgs:
|
||||||
|
(pkgs, was_refreshed) = _resolve_capabilities(pkgs, refresh=refresh, **kwargs)
|
||||||
|
if was_refreshed:
|
||||||
|
refresh = False
|
||||||
|
|
||||||
if not isinstance(pkg_verify, list):
|
if not isinstance(pkg_verify, list):
|
||||||
pkg_verify = pkg_verify is True
|
pkg_verify = pkg_verify is True
|
||||||
if (pkg_verify or isinstance(pkg_verify, list)) \
|
if (pkg_verify or isinstance(pkg_verify, list)) \
|
||||||
@ -1707,8 +1749,13 @@ def installed(
|
|||||||
if __grains__['os'] == 'FreeBSD':
|
if __grains__['os'] == 'FreeBSD':
|
||||||
kwargs['with_origin'] = True
|
kwargs['with_origin'] = True
|
||||||
new_pkgs = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs)
|
new_pkgs = __salt__['pkg.list_pkgs'](versions_as_list=True, **kwargs)
|
||||||
|
if kwargs.get('resolve_capabilities', False) and 'pkg.list_provides' in __salt__:
|
||||||
|
new_caps = __salt__['pkg.list_provides'](**kwargs)
|
||||||
|
else:
|
||||||
|
new_caps = {}
|
||||||
ok, failed = _verify_install(desired, new_pkgs,
|
ok, failed = _verify_install(desired, new_pkgs,
|
||||||
ignore_epoch=ignore_epoch)
|
ignore_epoch=ignore_epoch,
|
||||||
|
new_caps=new_caps)
|
||||||
modified = [x for x in ok if x in targets]
|
modified = [x for x in ok if x in targets]
|
||||||
not_modified = [x for x in ok
|
not_modified = [x for x in ok
|
||||||
if x not in targets
|
if x not in targets
|
||||||
@ -1927,6 +1974,11 @@ def downloaded(name,
|
|||||||
- dos2unix
|
- dos2unix
|
||||||
- salt-minion: 2015.8.5-1.el6
|
- salt-minion: 2015.8.5-1.el6
|
||||||
|
|
||||||
|
:param bool resolve_capabilities:
|
||||||
|
Turn on resolving capabilities. This allow to name "provides" or alias names for packages.
|
||||||
|
|
||||||
|
.. versionadded:: Oxygen
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
@ -1952,11 +2004,24 @@ def downloaded(name,
|
|||||||
ret['comment'] = 'No packages to download provided'
|
ret['comment'] = 'No packages to download provided'
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
# If just a name (and optionally a version) is passed, just pack them into
|
||||||
|
# the pkgs argument.
|
||||||
|
if name and not pkgs:
|
||||||
|
if version:
|
||||||
|
pkgs = [{name: version}]
|
||||||
|
version = None
|
||||||
|
else:
|
||||||
|
pkgs = [name]
|
||||||
|
|
||||||
# It doesn't make sense here to received 'downloadonly' as kwargs
|
# It doesn't make sense here to received 'downloadonly' as kwargs
|
||||||
# as we're explicitely passing 'downloadonly=True' to execution module.
|
# as we're explicitely passing 'downloadonly=True' to execution module.
|
||||||
if 'downloadonly' in kwargs:
|
if 'downloadonly' in kwargs:
|
||||||
del kwargs['downloadonly']
|
del kwargs['downloadonly']
|
||||||
|
|
||||||
|
(pkgs, was_refreshed) = _resolve_capabilities(pkgs, **kwargs)
|
||||||
|
if was_refreshed:
|
||||||
|
refresh = False
|
||||||
|
|
||||||
# Only downloading not yet downloaded packages
|
# Only downloading not yet downloaded packages
|
||||||
targets = _find_download_targets(name,
|
targets = _find_download_targets(name,
|
||||||
version,
|
version,
|
||||||
@ -2203,6 +2268,10 @@ def latest(
|
|||||||
This parameter is available only on Debian based distributions and
|
This parameter is available only on Debian based distributions and
|
||||||
has no effect on the rest.
|
has no effect on the rest.
|
||||||
|
|
||||||
|
:param bool resolve_capabilities:
|
||||||
|
Turn on resolving capabilities. This allow to name "provides" or alias names for packages.
|
||||||
|
|
||||||
|
.. versionadded:: Oxygen
|
||||||
|
|
||||||
Multiple Package Installation Options:
|
Multiple Package Installation Options:
|
||||||
|
|
||||||
@ -2300,6 +2369,12 @@ def latest(
|
|||||||
|
|
||||||
kwargs['saltenv'] = __env__
|
kwargs['saltenv'] = __env__
|
||||||
|
|
||||||
|
# check if capabilities should be checked and modify the requested packages
|
||||||
|
# accordingly.
|
||||||
|
(desired_pkgs, was_refreshed) = _resolve_capabilities(desired_pkgs, refresh=refresh, **kwargs)
|
||||||
|
if was_refreshed:
|
||||||
|
refresh = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
avail = __salt__['pkg.latest_version'](*desired_pkgs,
|
avail = __salt__['pkg.latest_version'](*desired_pkgs,
|
||||||
fromrepo=fromrepo,
|
fromrepo=fromrepo,
|
||||||
@ -2822,6 +2897,11 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs):
|
|||||||
This parameter available only on Debian based distributions, and
|
This parameter available only on Debian based distributions, and
|
||||||
have no effect on the rest.
|
have no effect on the rest.
|
||||||
|
|
||||||
|
:param bool resolve_capabilities:
|
||||||
|
Turn on resolving capabilities. This allow to name "provides" or alias names for packages.
|
||||||
|
|
||||||
|
.. versionadded:: Oxygen
|
||||||
|
|
||||||
kwargs
|
kwargs
|
||||||
Any keyword arguments to pass through to ``pkg.upgrade``.
|
Any keyword arguments to pass through to ``pkg.upgrade``.
|
||||||
|
|
||||||
@ -2841,7 +2921,11 @@ def uptodate(name, refresh=False, pkgs=None, **kwargs):
|
|||||||
ret['comment'] = '\'fromrepo\' argument not supported on this platform'
|
ret['comment'] = '\'fromrepo\' argument not supported on this platform'
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
if isinstance(refresh, bool):
|
if isinstance(refresh, bool):
|
||||||
|
(pkgs, was_refreshed) = _resolve_capabilities(pkgs, refresh=refresh, **kwargs)
|
||||||
|
if was_refreshed:
|
||||||
|
refresh = False
|
||||||
try:
|
try:
|
||||||
packages = __salt__['pkg.list_upgrades'](refresh=refresh, **kwargs)
|
packages = __salt__['pkg.list_upgrades'](refresh=refresh, **kwargs)
|
||||||
if isinstance(pkgs, list):
|
if isinstance(pkgs, list):
|
||||||
|
Loading…
Reference in New Issue
Block a user