Merge pull request #13366 from terminalmage/refine-pkg-hold

Refine hold/unhold behavior in pkg.installed state
This commit is contained in:
Colton Myers 2014-06-10 16:25:48 -06:00
commit b807af5cbe
3 changed files with 226 additions and 152 deletions

View File

@ -585,6 +585,8 @@ def upgrade(refresh=True, dist_upgrade=True, **kwargs):
def hold(name=None, pkgs=None, sources=None, *kwargs):
'''
.. versionadded:: Helium
Set package in 'hold' state, meaning it will not be upgraded.
name
@ -604,49 +606,60 @@ def hold(name=None, pkgs=None, sources=None, *kwargs):
.. code-block:: bash
salt '*' pkg.hold pkgs='["foo", "bar"]'
.. versionadded:: Helium
'''
if not name and not pkgs and not sources:
return 'Error: name, pkgs or sources needs to be specified.'
raise SaltInvocationError(
'One of name, pkgs, or sources must be specified.'
)
if pkgs and sources:
raise SaltInvocationError(
'Only one of pkgs or sources can be specified.'
)
if name and not pkgs:
pkgs = []
pkgs.append(name)
elif name and sources:
pkgs = []
targets = []
if pkgs:
targets.extend(pkgs)
elif sources:
for source in sources:
pkgs += source.keys()
targets.append(next(iter(source)))
else:
targets.append(name)
ret = {}
for pkg in pkgs:
if isinstance(pkg, dict):
pkg = pkg.keys()[0]
for target in targets:
if isinstance(target, dict):
target = next(iter(target))
ret[pkg] = {'name': pkg, 'changes': {}, 'result': False, 'comment': ''}
state = get_selections(pattern=pkg, state=hold)
ret[target] = {'name': target,
'changes': {},
'result': False,
'comment': ''}
state = get_selections(pattern=target, state='hold')
if not state:
ret[pkg]['comment'] = 'Package {0} not currently held.'.format(pkg)
ret[target]['comment'] = ('Package {0} not currently held.'
.format(target))
elif not salt.utils.is_true(state.get('hold', False)):
if 'test' in kwargs and kwargs['test']:
ret[pkg].update(result=None)
ret[pkg]['comment'] = 'Package {0} is set to be held.'.format(pkg)
ret[target].update(result=None)
ret[target]['comment'] = ('Package {0} is set to be held.'
.format(target))
else:
result = set_selections(
selection={'hold': [pkg]}
)
ret[pkg].update(changes=result[pkg], result=True)
ret[pkg]['comment'] = 'Package {0} is now being held.'.format(pkg)
result = set_selections(selection={'hold': [target]})
ret[target].update(changes=result[target], result=True)
ret[target]['comment'] = ('Package {0} is now being held.'
.format(target))
else:
ret[pkg].update(result=True)
ret[pkg]['comment'] = 'Package {0} is already set to be held.'.format(pkg)
ret[target].update(result=True)
ret[target]['comment'] = ('Package {0} is already set to be held.'
.format(target))
return ret
def unhold(name=None, pkgs=None, sources=None, **kwargs):
'''
.. versionadded:: Helium
Set package current in 'hold' state to install state,
meaning it will be upgraded.
@ -667,46 +680,53 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs):
.. code-block:: bash
salt '*' pkg.unhold pkgs='["foo", "bar"]'
.. versionadded:: Helium
'''
if not name and not pkgs and not sources:
return 'Error: name, pkgs or sources needs to be specified.'
raise SaltInvocationError(
'One of name, pkgs, or sources must be specified.'
)
if pkgs and sources:
raise SaltInvocationError(
'Only one of pkgs or sources can be specified.'
)
if name and not pkgs:
pkgs = []
pkgs.append(name)
elif name and sources:
pkgs = []
targets = []
if pkgs:
targets.extend(pkgs)
elif sources:
for source in sources:
pkgs += source.keys()
targets.append(next(iter(source)))
else:
targets.append(name)
ret = {}
for pkg in pkgs:
if isinstance(pkg, dict):
pkg = pkg.keys()[0]
for target in targets:
if isinstance(target, dict):
target = next(iter(target))
ret[pkg] = {'changes': {}, 'result': False, 'comment': ''}
state = get_selections(pattern=pkg)
ret[target] = {'name': target,
'changes': {},
'result': False,
'comment': ''}
state = get_selections(pattern=target)
if not state:
ret[pkg]['comment'] = 'Package {0} does not have a state.'.format(pkg)
ret[target]['comment'] = ('Package {0} does not have a state.'
.format(target))
elif salt.utils.is_true(state.get('hold', False)):
if 'test' in kwargs and kwargs['test']:
ret[pkg].update(result=None)
ret['comment'] = 'Package {0} is set not to be held.'.format(pkg)
ret[target].update(result=None)
ret['comment'] = ('Package {0} is set not to be held.'
.format(target))
else:
result = set_selections(
selection={'install': [pkg]}
)
ret[pkg].update(changes=result[pkg], result=True)
ret[pkg]['comment'] = 'Package {0} is no longer being held.'.format(pkg)
result = set_selections(selection={'install': [target]})
ret[target].update(changes=result[target], result=True)
ret[target]['comment'] = ('Package {0} is no longer being '
'held.'.format(target))
else:
ret[pkg].update(result=True)
ret[pkg]['comment'] = 'Package {0} is already set not to be held.'.format(pkg)
log.debug('in unhold {0}'.format(ret))
ret[target].update(result=True)
ret[target]['comment'] = ('Package {0} is already set not to be '
'held.'.format(target))
return ret

View File

@ -1026,6 +1026,8 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
'''
.. versionadded:: Helium
Hold packages with ``yum -q versionlock``.
name
@ -1037,9 +1039,6 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
A list of packages to hold. Must be passed as a python list. The
``name`` parameter will be ignored if this option is passed.
.. versionadded:: Helium
Returns a dict containing the changes.
CLI Example:
@ -1049,54 +1048,68 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
salt '*' pkg.hold <package name>
salt '*' pkg.hold pkgs='["foo", "bar"]'
'''
if 'yum-plugin-versionlock' not in list_pkgs():
raise SaltInvocationError(
'Packages cannot be held, yum-plugin-versionlock is not installed.'
)
if not name and not pkgs and not sources:
return 'Error: name or pkgs needs to be specified.'
raise SaltInvocationError(
'One of name, pkgs, or sources must be specified.'
)
if pkgs and sources:
raise SaltInvocationError(
'Only one of pkgs or sources can be specified.'
)
if name and not pkgs and not sources:
pkgs = []
pkgs.append(name)
elif name and sources:
pkgs = []
targets = []
if pkgs:
targets.extend(pkgs)
elif sources:
for source in sources:
pkgs += source.keys()
current_pkgs = list_pkgs()
if 'yum-plugin-versionlock' not in current_pkgs:
ret = {}
ret['result'] = False
ret['comment'] = 'Packages cannot be held, yum-plugin-versionlock needs to be installed.'
return ret
targets.append(next(iter(source)))
else:
targets.append(name)
current_locks = get_locked_packages()
ret = {}
for pkg in pkgs:
if isinstance(pkg, dict):
pkg = pkg.keys()[0]
for target in targets:
if isinstance(target, dict):
target = next(iter(target))
ret[pkg] = {'name': pkg, 'changes': {}, 'result': False, 'comment': ''}
if pkg not in current_locks:
ret[target] = {'name': target,
'changes': {},
'result': False,
'comment': ''}
if target not in current_locks:
if 'test' in kwargs and kwargs['test']:
ret[pkg].update(result=None)
ret[pkg]['comment'] = 'Package {0} is set to be held.'.format(pkg)
ret[target].update(result=None)
ret[target]['comment'] = ('Package {0} is set to be held.'
.format(target))
else:
cmd = 'yum -q versionlock {0}'.format(pkg)
cmd = 'yum -q versionlock {0}'.format(target)
out = __salt__['cmd.run_all'](cmd)
if out['retcode'] == 0:
ret[pkg].update(result=True)
ret[pkg]['comment'] = 'Package {0} is now being held.'.format(pkg)
ret[pkg]['changes']['new'] = 'hold'
ret[pkg]['changes']['old'] = ''
ret[target].update(result=True)
ret[target]['comment'] = ('Package {0} is now being held.'
.format(target))
ret[target]['changes']['new'] = 'hold'
ret[target]['changes']['old'] = ''
else:
ret[pkg]['comment'] = 'Package {0} was unable to be held.'.format(pkg)
ret[target]['comment'] = ('Package {0} was unable to be held.'
.format(target))
else:
ret[pkg].update(result=True)
ret[pkg]['comment'] = 'Package {0} is already set to be held.'.format(pkg)
ret[target].update(result=True)
ret[target]['comment'] = ('Package {0} is already set to be held.'
.format(target))
return ret
def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613
'''
.. versionadded:: Helium
Hold packages with ``yum -q versionlock``.
name
@ -1108,9 +1121,6 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06
A list of packages to unhold. Must be passed as a python list. The
``name`` parameter will be ignored if this option is passed.
.. versionadded:: Helium
Returns a dict containing the changes.
CLI Example:
@ -1120,52 +1130,64 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06
salt '*' pkg.unhold <package name>
salt '*' pkg.unhold pkgs='["foo", "bar"]'
'''
if 'yum-plugin-versionlock' not in list_pkgs():
raise SaltInvocationError(
'Packages cannot be unheld, yum-plugin-versionlock is not installed.'
)
if not name and not pkgs and not sources:
return 'Error: name, pkgs or sources needs to be specified.'
raise SaltInvocationError(
'One of name, pkgs, or sources must be specified.'
)
if pkgs and sources:
raise SaltInvocationError(
'Only one of pkgs or sources can be specified.'
)
if name and not pkgs:
pkgs = []
pkgs.append(name)
elif name and sources:
pkgs = []
targets = []
if pkgs:
targets.extend(pkgs)
elif sources:
for source in sources:
pkgs += source.keys()
current_pkgs = list_pkgs()
if 'yum-plugin-versionlock' not in current_pkgs:
ret = {}
ret['result'] = False
ret['comment'] = 'Error: Package yum-plugin-versionlock needs to be installed.'
return ret
targets.append(next(iter(source)))
else:
targets.append(name)
current_locks = get_locked_packages(full=True)
ret = {}
for pkg in pkgs:
if isinstance(pkg, dict):
pkg = pkg.keys()[0]
for target in targets:
if isinstance(target, dict):
target = next(iter(target))
ret[pkg] = {'name': pkg, 'changes': {}, 'result': False, 'comment': ''}
ret[target] = {'name': target,
'changes': {},
'result': False,
'comment': ''}
search_locks = [lock for lock in current_locks if lock.startswith(pkg)]
search_locks = [lock for lock in current_locks
if lock.startswith(target)]
if search_locks:
if 'test' in kwargs and kwargs['test']:
ret[pkg].update(result=None)
ret[pkg]['comment'] = 'Package {0} is set to be unheld.'.format(pkg)
ret[target].update(result=None)
ret[target]['comment'] = ('Package {0} is set to be unheld.'
.format(target))
else:
_pkgs = ' '.join('"0:' + item + '"' for item in search_locks)
cmd = 'yum -q versionlock delete {0}'.format(_pkgs)
_targets = ' '.join('"0:' + item + '"' for item in search_locks)
cmd = 'yum -q versionlock delete {0}'.format(_targets)
out = __salt__['cmd.run_all'](cmd)
if out['retcode'] == 0:
ret[pkg].update(result=True)
ret[pkg]['comment'] = 'Package {0} is no longer held.'.format(pkg)
ret[pkg]['changes']['new'] = ''
ret[pkg]['changes']['old'] = 'hold'
ret[target].update(result=True)
ret[target]['comment'] = ('Package {0} is no longer held.'
.format(target))
ret[target]['changes']['new'] = ''
ret[target]['changes']['old'] = 'hold'
else:
ret[pkg]['comment'] = 'Package {0} was unable to be unheld.'.format(pkg)
ret[target]['comment'] = ('Package {0} was unable to be '
'unheld.'.format(target))
else:
ret[pkg].update(result=True)
ret[pkg]['comment'] = 'Package {0} is not being held.'.format(pkg)
ret[target].update(result=True)
ret[target]['comment'] = ('Package {0} is not being held.'
.format(target))
return ret

View File

@ -44,7 +44,9 @@ from salt.output import nested
from salt.utils import namespaced_function as _namespaced_function
from salt.utils.odict import OrderedDict
from salt._compat import string_types
from salt.exceptions import CommandExecutionError, MinionError
from salt.exceptions import (
CommandExecutionError, MinionError, SaltInvocationError
)
from salt.modules.pkg_resource import _repack_pkgs
_repack_pkgs = _namespaced_function(_repack_pkgs, globals())
@ -184,7 +186,7 @@ def _find_install_targets(name=None,
'changes': {},
'result': True,
'comment': 'Version {0} of package {1!r} is already '
'installed'.format(version, name)}
'installed.'.format(version, name)}
# if cver is not an empty string, the package is already installed
elif cver and version is None and not pkg_verify:
@ -193,7 +195,7 @@ def _find_install_targets(name=None,
'changes': {},
'result': True,
'comment': 'Package {0} is already '
'installed'.format(name)}
'installed.'.format(name)}
version_spec = False
# Find out which packages will be targeted in the call to pkg.install
@ -655,28 +657,42 @@ def installed(
# check that the hold function is available
if 'pkg.hold' in __salt__:
if 'hold' in kwargs:
if kwargs['hold']:
hold_ret = __salt__['pkg.hold'](name=name, pkgs=pkgs, sources=sources)
else:
hold_ret = __salt__['pkg.unhold'](name=name, pkgs=pkgs, sources=sources)
try:
if kwargs['hold']:
hold_ret = __salt__['pkg.hold'](
name=name, pkgs=pkgs, sources=sources
)
else:
hold_ret = __salt__['pkg.unhold'](
name=name, pkgs=pkgs, sources=sources
)
except (CommandExecutionError, SaltInvocationError) as exc:
return {'name': name,
'changes': {},
'result': False,
'comment': exc.message}
if 'result' in hold_ret and not hold_ret['result']:
return {'name': name,
'changes': {},
'result': False,
'comment': 'An error was encountered while holding/unholding '
'package(s): {0}'.format(hold_ret['comment'])}
'comment': 'An error was encountered while '
'holding/unholding package(s): {0}'
.format(hold_ret['comment'])}
else:
modified_hold = [hold_ret[x] for x in hold_ret.keys() if hold_ret[x]['changes']]
not_modified_hold = [hold_ret[x] for x in hold_ret.keys() if not hold_ret[x]['changes'] and hold_ret[x]['result']]
failed_hold = [hold_ret[x] for x in hold_ret.keys() if not hold_ret[x]['result']]
modified_hold = [hold_ret[x] for x in hold_ret
if hold_ret[x]['changes']]
not_modified_hold = [hold_ret[x] for x in hold_ret
if not hold_ret[x]['changes']
and hold_ret[x]['result']]
failed_hold = [hold_ret[x] for x in hold_ret
if not hold_ret[x]['result']]
if modified_hold:
for i in modified_hold:
result['comment'] += ' {0}'.format(i['comment'])
result['result'] = i['result']
change_name = i['name']
result['changes'][change_name] = i['changes']
result['changes'][i['name']] = i['changes']
if not_modified_hold:
for i in not_modified_hold:
@ -759,31 +775,47 @@ def installed(
'changes': {},
'result': False,
'comment': 'An error was encountered while installing '
'package(s): {0}'.format(exc)}
if 'pkg.hold' in __salt__:
if 'hold' in kwargs:
if kwargs['hold']:
hold_ret = __salt__['pkg.hold'](name=name, pkgs=pkgs, sources=sources)
else:
hold_ret = __salt__['pkg.unhold'](name=name, pkgs=pkgs, sources=sources)
if 'result' in hold_ret and not hold_ret['result']:
return {'name': name,
'changes': {},
'result': False,
'comment': 'An error was encountered while holding/unholding '
'package(s): {0}'.format(hold_ret['comment'])}
else:
modified_hold = [hold_ret[x] for x in hold_ret.keys() if hold_ret[x]['changes']]
not_modified_hold = [hold_ret[x] for x in hold_ret.keys() if not hold_ret[x]['changes'] and hold_ret[x]['result']]
failed_hold = [hold_ret[x] for x in hold_ret.keys() if not hold_ret[x]['result']]
'package(s): {0}'.format(exc)}
if isinstance(pkg_ret, dict):
changes['installed'].update(pkg_ret)
elif isinstance(pkg_ret, string_types):
comment.append(pkg_ret)
if 'pkg.hold' in __salt__:
if 'hold' in kwargs:
try:
if kwargs['hold']:
hold_ret = __salt__['pkg.hold'](
name=name, pkgs=pkgs, sources=sources
)
else:
hold_ret = __salt__['pkg.unhold'](
name=name, pkgs=pkgs, sources=sources
)
except (CommandExecutionError, SaltInvocationError) as exc:
comment.append(exc.message)
return {'name': name,
'changes': changes,
'result': False,
'comment': ' '.join(comment)}
else:
if 'result' in hold_ret and not hold_ret['result']:
return {'name': name,
'changes': {},
'result': False,
'comment': 'An error was encountered while '
'holding/unholding package(s): {0}'
.format(hold_ret['comment'])}
else:
modified_hold = [hold_ret[x] for x in hold_ret
if hold_ret[x]['changes']]
not_modified_hold = [hold_ret[x] for x in hold_ret
if not hold_ret[x]['changes']
and hold_ret[x]['result']]
failed_hold = [hold_ret[x] for x in hold_ret
if not hold_ret[x]['result']]
if to_unpurge:
changes['purge_desired'] = __salt__['lowpkg.unpurge'](*to_unpurge)