Merge pull request #35510 from terminalmage/issue33516

Better systemd integration
This commit is contained in:
Thomas S Hatch 2016-08-17 12:54:11 -06:00 committed by GitHub
commit fd3274c800
11 changed files with 983 additions and 126 deletions

View file

@ -39,6 +39,7 @@ from salt.ext.six.moves.urllib.request import Request as _Request, urlopen as _u
# Import salt libs
from salt.modules.cmdmod import _parse_env
import salt.utils
import salt.utils.systemd
from salt.exceptions import (
CommandExecutionError, MinionError, SaltInvocationError
)
@ -377,6 +378,20 @@ def install(name=None,
reinstall=False,
**kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 apt-get/dpkg 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, add refresh=True to update the dpkg database.
name
@ -533,11 +548,14 @@ def install(name=None,
if pkg_params is None or len(pkg_params) == 0:
return {}
use_scope = salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True)
cmd_prefix = ['systemd-run', '--scope'] if use_scope else []
old = list_pkgs()
targets = []
downgrade = []
to_reinstall = {}
cmd_prefix = []
if pkg_type == 'repository':
pkg_params_items = six.iteritems(pkg_params)
# Build command prefix
@ -545,9 +563,9 @@ def install(name=None,
if kwargs.get('force_yes', False):
cmd_prefix.append('--force-yes')
if 'force_conf_new' in kwargs and kwargs['force_conf_new']:
cmd_prefix += ['-o', 'DPkg::Options::=--force-confnew']
cmd_prefix.extend(['-o', 'DPkg::Options::=--force-confnew'])
else:
cmd_prefix += ['-o', 'DPkg::Options::=--force-confold']
cmd_prefix.extend(['-o', 'DPkg::Options::=--force-confold'])
cmd_prefix += ['-o', 'DPkg::Options::=--force-confdef']
if 'install_recommends' in kwargs and not kwargs['install_recommends']:
cmd_prefix.append('--no-install-recommends')
@ -700,7 +718,11 @@ def _uninstall(action='remove', name=None, pkgs=None, **kwargs):
targets.extend([x for x in pkg_params if x in old_removed])
if not targets:
return {}
cmd = ['apt-get', '-q', '-y', action]
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend(['apt-get', '-q', '-y', action])
cmd.extend(targets)
env = _parse_env(kwargs.get('env'))
env.update(DPKG_ENV_VARS.copy())
@ -746,9 +768,13 @@ def autoremove(list_only=False, purge=False):
salt '*' pkg.autoremove list_only=True
salt '*' pkg.autoremove purge=True
'''
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
if list_only:
ret = []
cmd = ['apt-get', '--assume-no']
cmd.extend(['apt-get', '--assume-no'])
if purge:
cmd.append('--purge')
cmd.append('autoremove')
@ -766,7 +792,7 @@ def autoremove(list_only=False, purge=False):
return ret
else:
old = list_pkgs()
cmd = ['apt-get', '--assume-yes']
cmd.extend(['apt-get', '--assume-yes'])
if purge:
cmd.append('--purge')
cmd.append('autoremove')
@ -778,6 +804,20 @@ def autoremove(list_only=False, purge=False):
def remove(name=None, pkgs=None, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 apt-get/dpkg 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 using ``apt-get remove``.
name
@ -808,6 +848,20 @@ def remove(name=None, pkgs=None, **kwargs):
def purge(name=None, pkgs=None, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 apt-get/dpkg 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 ``apt-get purge`` along with all configuration files.
name
@ -838,6 +892,20 @@ def purge(name=None, pkgs=None, **kwargs):
def upgrade(refresh=True, dist_upgrade=False, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 apt-get/dpkg 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
Upgrades all packages via ``apt-get upgrade`` or ``apt-get dist-upgrade``
if ``dist_upgrade`` is ``True``.
@ -876,13 +944,19 @@ def upgrade(refresh=True, dist_upgrade=False, **kwargs):
force_conf = '--force-confnew'
else:
force_conf = '--force-confold'
if dist_upgrade:
cmd = ['apt-get', '-q', '-y', '-o', 'DPkg::Options::={0}'.format(force_conf),
'-o', 'DPkg::Options::=--force-confdef', 'dist-upgrade']
else:
cmd = ['apt-get', '-q', '-y', '-o', 'DPkg::Options::={0}'.format(force_conf),
'-o', 'DPkg::Options::=--force-confdef', 'upgrade']
call = __salt__['cmd.run_all'](cmd, python_shell=False, output_loglevel='trace',
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend(['apt-get', '-q', '-y',
'-o', 'DPkg::Options::={0}'.format(force_conf),
'-o', 'DPkg::Options::=--force-confdef'])
cmd.append('dist-upgrade' if dist_upgrade else 'upgrade')
call = __salt__['cmd.run_all'](cmd,
output_loglevel='trace',
python_shell=False,
env=DPKG_ENV_VARS.copy())
if call['retcode'] != 0:
ret['result'] = False

View file

@ -22,6 +22,7 @@ import re
# Import salt libs
import salt.utils
import salt.utils.systemd
from salt.exceptions import CommandExecutionError, MinionError
import salt.ext.six as six
@ -464,6 +465,20 @@ def install(name=None,
binhost=None,
**kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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.
@ -591,16 +606,16 @@ def install(name=None,
if pkg_params is None or len(pkg_params) == 0:
return {}
elif pkg_type == 'file':
emerge_opts = 'tbz2file'
emerge_opts = ['tbz2file']
else:
emerge_opts = ''
emerge_opts = []
if binhost == 'try':
bin_opts = '-g'
bin_opts = ['-g']
elif binhost == 'force':
bin_opts = '-G'
bin_opts = ['-G']
else:
bin_opts = ''
bin_opts = []
changes = {}
@ -627,11 +642,11 @@ def install(name=None,
# 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)
target = '{0}{1}-{2}'.format(prefix, param, verstr)
else:
target = '"{0}{1}"'.format(param, verstr)
target = '{0}{1}'.format(param, verstr)
else:
target = '"{0}"'.format(param)
target = '{0}'.format(param)
if '[' in target:
old = __salt__['portage_config.get_flags_from_package_conf']('use', target[1:-1])
@ -661,7 +676,15 @@ def install(name=None,
targets.append(target)
else:
targets = pkg_params
cmd = 'emerge --ask n --quiet {0} {1} {2}'.format(bin_opts, emerge_opts, ' '.join(targets))
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,
@ -677,6 +700,20 @@ def install(name=None,
def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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
@ -714,14 +751,25 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
full_atom = '{0}::{1}'.format(full_atom, fromrepo)
if binhost == 'try':
bin_opts = '-g'
bin_opts = ['-g']
elif binhost == 'force':
bin_opts = '-G'
bin_opts = ['-G']
else:
bin_opts = ''
bin_opts = []
old = list_pkgs()
cmd = 'emerge --ask n --quiet --update --newuse --oneshot {0} {1}'.format(bin_opts, full_atom)
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)
@ -734,6 +782,20 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
def upgrade(refresh=True, binhost=None, backtrack=3):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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
@ -775,13 +837,17 @@ def upgrade(refresh=True, binhost=None, backtrack=3):
bin_opts = ''
old = list_pkgs()
cmd = ['emerge',
'--ask', 'n',
'--quiet',
'--backtrack', '{0}'.format(backtrack),
'--update',
'--newuse',
'--deep']
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.append(bin_opts)
cmd.append('@world')
@ -804,6 +870,20 @@ def upgrade(refresh=True, binhost=None, backtrack=3):
def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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
@ -852,8 +932,17 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
if not targets:
return {}
cmd = 'emerge --ask n --quiet --unmerge --quiet-unmerge-warn ' \
'{0}'.format(' '.join(targets))
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)
__salt__['cmd.run_all'](cmd,
output_loglevel='trace',
python_shell=False)
@ -864,6 +953,20 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
def purge(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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
Portage does not have a purge, this function calls remove followed
by depclean to emulate a purge process

View file

@ -18,6 +18,7 @@ import re
# Import salt libs
import salt.utils
import salt.utils.systemd
from salt.exceptions import CommandExecutionError, MinionError
# Import 3rd-party libs
@ -210,7 +211,7 @@ def list_pkgs(versions_as_list=False, **kwargs):
name, version_num = line.split()[0:2]
except ValueError:
log.error('Problem parsing pacman -Q: Unexpected formatting in '
'line: "{0}"'.format(line))
'line: \'{0}\''.format(line))
else:
__salt__['pkg_resource.add_pkg'](ret, name, version_num)
@ -269,15 +270,29 @@ def install(name=None,
sources=None,
**kwargs):
'''
Install (pacman -S) the passed package, add refresh=True to install with
-y, add sysupgrade=True to install with -u.
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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.
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:
@ -344,17 +359,27 @@ def install(name=None,
# Allow "version" to work for single package target
pkg_params = {name: version_num}
else:
log.warning('"version" parameter will be ignored for multiple '
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 = 'pacman -U --noprogressbar --noconfirm ' \
'{0}'.format(' '.join(pkg_params))
targets = pkg_params
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 = []
options = ['--noprogressbar', '--noconfirm', '--needed']
for param, version_num in six.iteritems(pkg_params):
if version_num is None:
targets.append(param)
@ -368,23 +393,18 @@ def install(name=None,
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)
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 {}
if salt.utils.is_true(refresh):
options.append('-y')
if salt.utils.is_true(sysupgrade):
options.append('-u')
cmd = 'pacman -S "{0}"'.format('" "'.join(options+targets))
cmd.extend(targets)
old = list_pkgs()
__salt__['cmd.run'](cmd, output_loglevel='trace')
__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)
@ -392,6 +412,20 @@ def install(name=None,
def upgrade(refresh=False, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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
Run a full system upgrade, a pacman -Syu
refresh
@ -414,10 +448,18 @@ def upgrade(refresh=False, **kwargs):
}
old = list_pkgs()
cmd = 'pacman -Su --noprogressbar --noconfirm'
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend(['pacman', '-Su', '--noprogressbar', '--noconfirm'])
if salt.utils.is_true(refresh):
cmd += ' -y'
call = __salt__['cmd.run_all'](cmd, output_loglevel='trace')
cmd.append('-y')
call = __salt__['cmd.run_all'](cmd,
output_loglevel='trace',
python_shell=False)
if call['retcode'] != 0:
ret['result'] = False
if 'stderr' in call:
@ -446,12 +488,15 @@ def _uninstall(action='remove', name=None, pkgs=None, **kwargs):
if not targets:
return {}
remove_arg = '-Rsc' if action == 'purge' else '-R'
cmd = (
'pacman {0} '
'--noprogressbar '
'--noconfirm {1}'
).format(remove_arg, ' '.join(targets))
__salt__['cmd.run'](cmd, output_loglevel='trace')
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend(['pacman', remove_arg, '--noprogressbar', '--noconfirm'])
cmd.extend(targets)
__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)
@ -459,6 +504,20 @@ def _uninstall(action='remove', name=None, pkgs=None, **kwargs):
def remove(name=None, pkgs=None, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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
Remove packages with ``pacman -R``.
name
@ -489,6 +548,20 @@ def remove(name=None, pkgs=None, **kwargs):
def purge(name=None, pkgs=None, **kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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
Recursively remove a package and all dependencies which were installed
with it, this will call a ``pacman -Rsc``

View file

@ -235,12 +235,17 @@ def _runlevel():
return ret
def _systemctl_cmd(action, name=None):
def _systemctl_cmd(action, name=None, systemd_scope=False):
'''
Build a systemctl command line. Treat unit names without one
of the valid suffixes as a service.
'''
ret = ['systemctl']
ret = []
if systemd_scope \
and salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
ret.extend(['systemd-run', '--scope'])
ret.append('systemctl')
if isinstance(action, six.string_types):
action = shlex.split(action)
ret.extend(action)
@ -503,6 +508,16 @@ def missing(name):
def unmask(name):
'''
.. versionadded:: 2015.5.0
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Unmask the specified service with systemd
@ -519,7 +534,7 @@ def unmask(name):
return True
cmd = 'unmask --runtime' if 'runtime' in mask_status else 'unmask'
out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name),
out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name, systemd_scope=True),
python_shell=False,
redirect_stderr=True)
@ -532,6 +547,16 @@ def unmask(name):
def mask(name, runtime=False):
'''
.. versionadded:: 2015.5.0
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Mask the specified service with systemd
@ -549,7 +574,7 @@ def mask(name, runtime=False):
_check_for_unit_changes(name)
cmd = 'mask --runtime' if runtime else 'mask'
out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name),
out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name, systemd_scope=True),
python_shell=False,
redirect_stderr=True)
@ -588,6 +613,17 @@ def masked(name):
def start(name):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Start the specified service with systemd
CLI Example:
@ -599,11 +635,24 @@ def start(name):
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
systemctl_reload()
unmask(name)
return not __salt__['cmd.retcode'](_systemctl_cmd('start', name))
return __salt__['cmd.retcode'](
_systemctl_cmd('start', name, systemd_scope=True),
python_shell=False) == 0
def stop(name):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Stop the specified service with systemd
CLI Example:
@ -613,12 +662,24 @@ def stop(name):
salt '*' service.stop <service name>
'''
_check_for_unit_changes(name)
return __salt__['cmd.retcode'](_systemctl_cmd('stop', name),
python_shell=False) == 0
return __salt__['cmd.retcode'](
_systemctl_cmd('stop', name, systemd_scope=True),
python_shell=False) == 0
def restart(name):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Restart the specified service with systemd
CLI Example:
@ -629,12 +690,24 @@ def restart(name):
'''
_check_for_unit_changes(name)
unmask(name)
return __salt__['cmd.retcode'](_systemctl_cmd('restart', name),
python_shell=False) == 0
return __salt__['cmd.retcode'](
_systemctl_cmd('restart', name, systemd_scope=True),
python_shell=False) == 0
def reload_(name):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Reload the specified service with systemd
CLI Example:
@ -645,12 +718,24 @@ def reload_(name):
'''
_check_for_unit_changes(name)
unmask(name)
return __salt__['cmd.retcode'](_systemctl_cmd('reload', name),
python_shell=False) == 0
return __salt__['cmd.retcode'](
_systemctl_cmd('reload', name, systemd_scope=True),
python_shell=False) == 0
def force_reload(name):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
.. versionadded:: 0.12.0
Force-reload the specified service with systemd
@ -663,8 +748,9 @@ def force_reload(name):
'''
_check_for_unit_changes(name)
unmask(name)
return __salt__['cmd.retcode'](_systemctl_cmd('force-reload', name),
python_shell=False) == 0
return __salt__['cmd.retcode'](
_systemctl_cmd('force-reload', name, systemd_scope=True),
python_shell=False) == 0
# The unused sig argument is required to maintain consistency with the API
@ -690,6 +776,17 @@ def status(name, sig=None): # pylint: disable=unused-argument
# established by Salt's service management states.
def enable(name, **kwargs): # pylint: disable=unused-argument
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Enable the named service to start when the system boots
CLI Example:
@ -701,23 +798,39 @@ def enable(name, **kwargs): # pylint: disable=unused-argument
_check_for_unit_changes(name)
unmask(name)
if name in _get_sysv_services():
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
service_exec = _get_service_exec()
if service_exec.endswith('/update-rc.d'):
cmd = [service_exec, '-f', name, 'defaults', '99']
cmd.extend([service_exec, '-f', name, 'defaults', '99'])
elif service_exec.endswith('/chkconfig'):
cmd = [service_exec, name, 'on']
cmd.extend([service_exec, name, 'on'])
return __salt__['cmd.retcode'](cmd,
python_shell=False,
ignore_retcode=True) == 0
return __salt__['cmd.retcode'](_systemctl_cmd('enable', name),
python_shell=False,
ignore_retcode=True) == 0
return __salt__['cmd.retcode'](
_systemctl_cmd('enable', name, systemd_scope=True),
python_shell=False,
ignore_retcode=True) == 0
# The unused kwargs argument is required to maintain consistency with the API
# established by Salt's service management states.
def disable(name, **kwargs): # pylint: disable=unused-argument
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
On minions running systemd>=205, `systemd-run(1)`_ is now used to
isolate commands run by this function from the ``salt-minion`` daemon's
control group. This is done to avoid a race condition in cases where
the ``salt-minion`` service is restarted while a service is being
modified. 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
Disable the named service to not start when the system boots
CLI Example:
@ -728,17 +841,22 @@ def disable(name, **kwargs): # pylint: disable=unused-argument
'''
_check_for_unit_changes(name)
if name in _get_sysv_services():
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
service_exec = _get_service_exec()
if service_exec.endswith('/update-rc.d'):
cmd = [service_exec, '-f', name, 'remove']
cmd.extend([service_exec, '-f', name, 'remove'])
elif service_exec.endswith('/chkconfig'):
cmd = [service_exec, name, 'off']
cmd.extend([service_exec, name, 'off'])
return __salt__['cmd.retcode'](cmd,
python_shell=False,
ignore_retcode=True) == 0
return __salt__['cmd.retcode'](_systemctl_cmd('disable', name),
python_shell=False,
ignore_retcode=True) == 0
return __salt__['cmd.retcode'](
_systemctl_cmd('disable', name, systemd_scope=True),
python_shell=False,
ignore_recode=True) == 0
# The unused kwargs argument is required to maintain consistency with the API

View file

@ -51,6 +51,7 @@ except ImportError:
# Import salt libs
import salt.utils
import salt.utils.itertools
import salt.utils.systemd
import salt.utils.decorators as decorators
import salt.utils.pkg.rpm
from salt.exceptions import (
@ -1102,6 +1103,20 @@ def install(name=None,
normalize=True,
**kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 yum/dnf 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 clean the yum database
before package is installed.
@ -1373,7 +1388,11 @@ def install(name=None,
cmd.append('--nogpgcheck')
if targets:
cmd = [_yum(), '-y']
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend([_yum(), '-y'])
if _yum() == 'dnf':
cmd.extend(['--best', '--allowerasing'])
_add_common_args(cmd)
@ -1387,7 +1406,11 @@ def install(name=None,
)
if downgrade:
cmd = [_yum(), '-y']
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend([_yum(), '-y'])
_add_common_args(cmd)
cmd.append('downgrade')
cmd.extend(downgrade)
@ -1399,7 +1422,11 @@ def install(name=None,
)
if to_reinstall:
cmd = [_yum(), '-y']
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend([_yum(), '-y'])
_add_common_args(cmd)
cmd.append('reinstall')
cmd.extend(six.itervalues(to_reinstall))
@ -1426,9 +1453,22 @@ def install(name=None,
def upgrade(refresh=True, skip_verify=False, **kwargs):
'''
Run a full system upgrade, a yum upgrade
.. versionchanged:: 2014.7.0
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 yum/dnf 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, a yum upgrade
Return a dict containing the new package names and versions::
@ -1458,8 +1498,6 @@ def upgrade(refresh=True, skip_verify=False, **kwargs):
disableexcludes
Disable exclude from main, for a repo or for everything.
(e.g., ``yum --disableexcludes='main'``)
.. versionadded:: 2014.7.0
'''
repo_arg = _get_repo_options(**kwargs)
exclude_arg = _get_excludes_option(**kwargs)
@ -1469,7 +1507,11 @@ def upgrade(refresh=True, skip_verify=False, **kwargs):
refresh_db(**kwargs)
old = list_pkgs()
cmd = [_yum(), '--quiet', '-y']
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend([_yum(), '--quiet', '-y'])
for args in (repo_arg, exclude_arg, branch_arg):
if args:
cmd.extend(args)
@ -1488,6 +1530,20 @@ def upgrade(refresh=True, skip_verify=False, **kwargs):
def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 yum/dnf 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
name
@ -1522,7 +1578,11 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
targets = [x for x in pkg_params if x in old]
if not targets:
return {}
cmd = [_yum(), '-y', 'remove'] + targets
cmd = []
if salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True):
cmd.extend(['systemd-run', '--scope'])
cmd.extend([_yum(), '-y', 'remove'] + targets)
__salt__['cmd.run'](cmd, output_loglevel='trace')
__context__.pop('pkg.list_pkgs', None)
new = list_pkgs()
@ -1534,6 +1594,20 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
def purge(name=None, pkgs=None, **kwargs): # pylint: disable=W0613
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 yum/dnf 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
Package purges are not supported by yum, this function is identical to
:mod:`pkg.remove <salt.modules.yumpkg.remove>`.

View file

@ -34,6 +34,7 @@ from xml.parsers.expat import ExpatError
# Import salt libs
import salt.utils
import salt.utils.systemd
from salt.exceptions import (
CommandExecutionError, MinionError)
@ -100,6 +101,7 @@ class _Zypper(object):
self.__no_raise = False
self.__refresh = False
self.__ignore_repo_failure = False
self.__systemd_scope = False
def __call__(self, *args, **kwargs):
'''
@ -110,6 +112,8 @@ class _Zypper(object):
# Ignore exit code for 106 (repo is not available)
if 'no_repo_failure' in kwargs:
self.__ignore_repo_failure = kwargs['no_repo_failure']
if 'systemd_scope' in kwargs:
self.__systemd_scope = kwargs['systemd_scope']
return self
def __getattr__(self, item):
@ -251,8 +255,12 @@ class _Zypper(object):
# However, Zypper lock needs to be always respected.
was_blocked = False
while True:
log.debug("Calling Zypper: " + ' '.join(self.__cmd))
self.__call_result = __salt__['cmd.run_all'](self.__cmd, **kwargs)
cmd = []
if self.__systemd_scope:
cmd.extend(['systemd-run', '--scope'])
cmd.extend(self.__cmd)
log.debug("Calling Zypper: " + ' '.join(cmd))
self.__call_result = __salt__['cmd.run_all'](cmd, **kwargs)
if self._check_result():
break
@ -295,6 +303,11 @@ class _Zypper(object):
__zypper__ = _Zypper()
def _systemd_scope():
return salt.utils.systemd.has_scope(__context__) \
and __salt__['config.get']('systemd.scope', True)
def list_upgrades(refresh=True, **kwargs):
'''
List all available package upgrades on this system
@ -874,6 +887,20 @@ def install(name=None,
ignore_repo_failure=False,
**kwargs):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 zypper 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 force a 'zypper refresh'
before package is installed.
@ -1000,10 +1027,11 @@ def install(name=None,
cmd_install.extend(fromrepoopt)
# Split the targets into batches of 500 packages each, so that
# the maximal length of the command line is not broken
systemd_scope = _systemd_scope()
while targets:
cmd = cmd_install + targets[:500]
targets = targets[500:]
for line in __zypper__(no_repo_failure=ignore_repo_failure).call(*cmd).splitlines():
for line in __zypper__(no_repo_failure=ignore_repo_failure, systemd_scope=systemd_scope).call(*cmd).splitlines():
match = re.match(r"^The selected package '([^']+)'.+has lower version", line)
if match:
downgrades.append(match.group(1))
@ -1021,6 +1049,20 @@ def install(name=None,
def upgrade(refresh=True):
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 zypper 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, a zypper upgrade
refresh
@ -1047,7 +1089,7 @@ def upgrade(refresh=True):
if refresh:
refresh_db()
old = list_pkgs()
__zypper__.noraise.call('update', '--auto-agree-with-licenses')
__zypper__(systemd_scope=_systemd_scope()).noraise.call('update', '--auto-agree-with-licenses')
if __zypper__.exit_code not in __zypper__.SUCCESS_EXIT_CODES:
ret['result'] = False
ret['comment'] = (__zypper__.stdout() + os.linesep + __zypper__.stderr()).strip()
@ -1074,8 +1116,9 @@ def _uninstall(name=None, pkgs=None):
if not targets:
return {}
systemd_scope = _systemd_scope()
while targets:
__zypper__.call('remove', *targets[:500])
__zypper__(systemd_scope=systemd_scope).call('remove', *targets[:500])
targets = targets[500:]
__context__.pop('pkg.list_pkgs', None)
@ -1084,6 +1127,20 @@ def _uninstall(name=None, pkgs=None):
def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 zypper 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 with ``zypper -n remove``
name
@ -1114,6 +1171,20 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
'''
.. versionchanged:: 2015.8.12,2016.3.3,Carbon
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 zypper 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
Recursively remove a package and all dependencies which were installed
with it, this will call a ``zypper -n remove -u``

View file

@ -115,6 +115,9 @@ def salt_minion():
'''
Start the salt minion.
'''
import salt.utils.process
salt.utils.process.notify_systemd()
import salt.cli.daemons
import multiprocessing
if '' in sys.path:
@ -272,6 +275,9 @@ def salt_syndic():
'''
Start the salt syndic.
'''
import salt.utils.process
salt.utils.process.notify_systemd()
import salt.cli.daemons
pid = os.getpid()
try:
@ -444,6 +450,9 @@ def salt_api():
'''
The main function for salt-api
'''
import salt.utils.process
salt.utils.process.notify_systemd()
import salt.cli.api
sapi = salt.cli.api.SaltAPI() # pylint: disable=E1120
sapi.run()

View file

@ -3,6 +3,19 @@
Installation of packages using OS package managers such as yum or apt-get
=========================================================================
..note::
On minions running systemd>=205, as of version 2015.8.12, 2016.3.3, and
Carbon, `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 the package manager commands spawned by
Salt, when Salt updates itself (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.use_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
Salt can manage software packages via the pkg state module, packages can be
set up to be installed, latest, removed and purged. Package management
declarations are typically rather simple:

View file

@ -15,22 +15,34 @@ import salt.utils
log = logging.getLogger(__name__)
def booted(context):
def booted(context=None):
'''
Return True if the system was booted with systemd, False otherwise.
Pass in the loader context "__context__", this function will set the
systemd.sd_booted key to represent if systemd is running
'''
# We can cache this for as long as the minion runs.
if 'systemd.sd_booted' not in context:
try:
# This check does the same as sd_booted() from libsystemd-daemon:
# http://www.freedesktop.org/software/systemd/man/sd_booted.html
if os.stat('/run/systemd/system'):
context['systemd.sd_booted'] = True
except OSError:
context['systemd.sd_booted'] = False
return context['systemd.sd_booted']
contextkey = 'salt.utils.systemd.booted'
if isinstance(context, dict):
# Can't put this if block on the same line as the above if block,
# because it willl break the elif below.
if contextkey in context:
return context[contextkey]
elif context is not None:
raise SaltInvocationError('context must be a dictionary if passed')
try:
# This check does the same as sd_booted() from libsystemd-daemon:
# http://www.freedesktop.org/software/systemd/man/sd_booted.html
ret = bool(os.stat('/run/systemd/system'))
except OSError:
ret = False
try:
context[contextkey] = ret
except TypeError:
pass
return ret
def version(context=None):
@ -38,11 +50,14 @@ def version(context=None):
Attempts to run systemctl --version. Returns None if unable to determine
version.
'''
contextkey = 'salt.utils.systemd.version'
if isinstance(context, dict):
if 'systemd.version' in context:
return context['systemd.version']
# Can't put this if block on the same line as the above if block,
# because it willl break the elif below.
if contextkey in context:
return context[contextkey]
elif context is not None:
raise SaltInvocationError('context must be a dictionary or None')
raise SaltInvocationError('context must be a dictionary if passed')
stdout = subprocess.Popen(
['systemctl', '--version'],
close_fds=True,
@ -58,7 +73,20 @@ def version(context=None):
return None
else:
try:
context['systemd.version'] = ret
context[contextkey] = ret
except TypeError:
pass
return ret
def has_scope(context=None):
'''
Scopes were introduced in systemd 205, this function returns a boolean
which is true when the minion is systemd-booted and running systemd>=205.
'''
if not booted(context):
return False
_sd_version = version(context)
if _sd_version is None:
return False
return _sd_version >= 205

View file

@ -428,15 +428,22 @@ class ZypperTestCase(TestCase):
'stderr': ''
}
with patch.dict(zypper.__salt__, {'cmd.run_all': MagicMock(return_value=cmd_out)}):
with patch.dict(zypper.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=parsed_targets)}):
with patch.dict(zypper.__salt__, {'pkg_resource.stringify': MagicMock()}):
with patch('salt.modules.zypper.list_pkgs', ListPackages()):
diff = zypper.remove(name='vim,pico')
for pkg_name in ['vim', 'pico']:
self.assertTrue(diff.get(pkg_name))
self.assertTrue(diff[pkg_name]['old'])
self.assertFalse(diff[pkg_name]['new'])
# If config.get starts being used elsewhere, we'll need to write a
# side_effect function.
patches = {
'cmd.run_all': MagicMock(return_value=cmd_out),
'pkg_resource.parse_targets': MagicMock(return_value=parsed_targets),
'pkg_resource.stringify': MagicMock(),
'config.get': MagicMock(return_value=True)
}
with patch.dict(zypper.__salt__, patches):
with patch('salt.modules.zypper.list_pkgs', ListPackages()):
diff = zypper.remove(name='vim,pico')
for pkg_name in ['vim', 'pico']:
self.assertTrue(diff.get(pkg_name))
self.assertTrue(diff[pkg_name]['old'])
self.assertFalse(diff[pkg_name]['new'])
def test_repo_value_info(self):
'''

View file

@ -0,0 +1,287 @@
# -*- coding: utf-8 -*-
# Import python libs
from __future__ import absolute_import
import errno
import os
# Import Salt Testing libs
from salttesting import TestCase, skipIf
from salttesting.mock import Mock, patch, NO_MOCK, NO_MOCK_REASON
# Import Salt libs
from salt.exceptions import SaltInvocationError
from salt.utils import systemd as _systemd
def _booted_effect(path):
return True if path == '/run/systemd/system' else os.stat(path)
def _not_booted_effect(path):
if path == '/run/systemd/system':
raise OSError(errno.ENOENT, 'No such file or directory', path)
return os.stat(path)
@skipIf(NO_MOCK, NO_MOCK_REASON)
class SystemdTestCase(TestCase):
'''
Tests the functions in salt.utils.systemd
'''
def test_booted(self):
'''
Test that salt.utils.systemd.booted() returns True when minion is
systemd-booted.
'''
# Ensure that os.stat returns True. os.stat doesn't return a bool
# normally, but the code is doing a simple truth check on the return
# data, so it is sufficient enough to mock it as True for these tests.
with patch('os.stat', side_effect=_booted_effect):
# Test without context dict passed
self.assertTrue(_systemd.booted())
# Test that context key is set when context dict is passed
context = {}
self.assertTrue(_systemd.booted(context))
self.assertEqual(context, {'salt.utils.systemd.booted': True})
def test_not_booted(self):
'''
Test that salt.utils.systemd.booted() returns False when minion is not
systemd-booted.
'''
# Ensure that os.stat raises an exception even if test is being run on
# a systemd-booted host.
with patch('os.stat', side_effect=_not_booted_effect):
# Test without context dict passed
self.assertFalse(_systemd.booted())
# Test that context key is set when context dict is passed
context = {}
self.assertFalse(_systemd.booted(context))
self.assertEqual(context, {'salt.utils.systemd.booted': False})
def test_booted_return_from_context(self):
'''
Test that the context data is returned when present. To ensure we're
getting data from the context dict, we use a non-boolean value to
differentiate it from the True/False return this function normally
produces.
'''
context = {'salt.utils.systemd.booted': 'foo'}
self.assertEqual(_systemd.booted(context), 'foo')
def test_booted_invalid_context(self):
'''
Test with invalid context data. The context value must be a dict, so
this should raise a SaltInvocationError.
'''
# Test with invalid context data
with self.assertRaises(SaltInvocationError):
_systemd.booted(99999)
@patch('subprocess.Popen')
def test_version(self, popen_mock):
'''
Test that salt.utils.systemd.booted() returns True when minion is
systemd-booted.
'''
_version = 231
output = 'systemd {0}\n-SYSVINIT'.format(_version)
popen_mock.return_value = Mock(
communicate=lambda *args, **kwargs: (output, None),
pid=lambda: 12345,
retcode=0
)
# Test without context dict passed
self.assertEqual(_systemd.version(), _version)
# Test that context key is set when context dict is passed
context = {}
self.assertTrue(_systemd.version(context))
self.assertEqual(context, {'salt.utils.systemd.version': _version})
def test_version_return_from_context(self):
'''
Test that the context data is returned when present. To ensure we're
getting data from the context dict, we use a non-integer value to
differentiate it from the integer return this function normally
produces.
'''
context = {'salt.utils.systemd.version': 'foo'}
self.assertEqual(_systemd.version(context), 'foo')
def test_version_invalid_context(self):
'''
Test with invalid context data. The context value must be a dict, so
this should raise a SaltInvocationError.
'''
# Test with invalid context data
with self.assertRaises(SaltInvocationError):
_systemd.version(99999)
@patch('subprocess.Popen')
def test_version_parse_problem(self, popen_mock):
'''
Test with invalid context data. The context value must be a dict, so
this should raise a SaltInvocationError.
'''
popen_mock.return_value = Mock(
communicate=lambda *args, **kwargs: ('invalid', None),
pid=lambda: 12345,
retcode=0
)
# Test without context dict passed
self.assertIsNone(_systemd.version())
# Test that context key is set when context dict is passed. A failure
# to parse the systemctl output should not set a context key, so it
# should not be present in the context dict.
context = {}
self.assertIsNone(_systemd.version(context))
self.assertEqual(context, {})
@patch('subprocess.Popen')
def test_has_scope_systemd204(self, popen_mock):
'''
Scopes are available in systemd>=205. Make sure that this function
returns the expected boolean. We do three separate unit tests for
versions 204 through 206 because mock doesn't like us altering the
return_value in a loop.
'''
_expected = False
_version = 204
_output = 'systemd {0}\n-SYSVINIT'.format(_version)
popen_mock.return_value = Mock(
communicate=lambda *args, **kwargs: (_output, None),
pid=lambda: 12345,
retcode=0
)
# Ensure that os.stat returns True. os.stat doesn't return a bool
# normally, but the code is doing a simple truth check on the
# return data, so it is sufficient enough to mock it as True for
# these tests.
with patch('os.stat', side_effect=_booted_effect):
# Test without context dict passed
self.assertEqual(_systemd.has_scope(), _expected)
# Test that context key is set when context dict is passed
context = {}
self.assertEqual(_systemd.has_scope(context), _expected)
self.assertEqual(
context,
{'salt.utils.systemd.booted': True,
'salt.utils.systemd.version': _version},
)
@patch('subprocess.Popen')
def test_has_scope_systemd205(self, popen_mock):
'''
Scopes are available in systemd>=205. Make sure that this function
returns the expected boolean. We do three separate unit tests for
versions 204 through 206 because mock doesn't like us altering the
return_value in a loop.
'''
_expected = True
_version = 205
_output = 'systemd {0}\n-SYSVINIT'.format(_version)
popen_mock.return_value = Mock(
communicate=lambda *args, **kwargs: (_output, None),
pid=lambda: 12345,
retcode=0
)
# Ensure that os.stat returns True. os.stat doesn't return a bool
# normally, but the code is doing a simple truth check on the
# return data, so it is sufficient enough to mock it as True for
# these tests.
with patch('os.stat', side_effect=_booted_effect):
# Test without context dict passed
self.assertEqual(_systemd.has_scope(), _expected)
# Test that context key is set when context dict is passed
context = {}
self.assertEqual(_systemd.has_scope(context), _expected)
self.assertEqual(
context,
{'salt.utils.systemd.booted': True,
'salt.utils.systemd.version': _version},
)
@patch('subprocess.Popen')
def test_has_scope_systemd206(self, popen_mock):
'''
Scopes are available in systemd>=205. Make sure that this function
returns the expected boolean. We do three separate unit tests for
versions 204 through 206 because mock doesn't like us altering the
return_value in a loop.
'''
_expected = True
_version = 206
_output = 'systemd {0}\n-SYSVINIT'.format(_version)
popen_mock.return_value = Mock(
communicate=lambda *args, **kwargs: (_output, None),
pid=lambda: 12345,
retcode=0
)
# Ensure that os.stat returns True. os.stat doesn't return a bool
# normally, but the code is doing a simple truth check on the
# return data, so it is sufficient enough to mock it as True for
# these tests.
with patch('os.stat', side_effect=_booted_effect):
# Test without context dict passed
self.assertEqual(_systemd.has_scope(), _expected)
# Test that context key is set when context dict is passed
context = {}
self.assertEqual(_systemd.has_scope(context), _expected)
self.assertEqual(
context,
{'salt.utils.systemd.booted': True,
'salt.utils.systemd.version': _version},
)
def test_has_scope_no_systemd(self):
'''
Test the case where the system is not systemd-booted. We should not be
performing a version check in these cases as there is no need.
'''
with patch('os.stat', side_effect=_not_booted_effect):
# Test without context dict passed
self.assertFalse(_systemd.has_scope())
# Test that context key is set when context dict is passed.
# Because we are not systemd-booted, there should be no key in the
# context dict for the version check, as we shouldn't have
# performed this check.
context = {}
self.assertFalse(_systemd.has_scope(context))
self.assertEqual(context, {'salt.utils.systemd.booted': False})
@patch('subprocess.Popen')
def test_has_scope_version_parse_problem(self, popen_mock):
'''
Test the case where the system is systemd-booted, but we failed to
parse the "systemctl --version" output.
'''
popen_mock.return_value = Mock(
communicate=lambda *args, **kwargs: ('invalid', None),
pid=lambda: 12345,
retcode=0
)
with patch('os.stat', side_effect=_booted_effect):
# Test without context dict passed
self.assertFalse(_systemd.has_scope())
# Test that context key is set when context dict is passed. A
# failure to parse the systemctl output should not set a context
# key, so it should not be present in the context dict.
context = {}
self.assertFalse(_systemd.has_scope(context))
self.assertEqual(context, {'salt.utils.systemd.booted': True})
def test_has_scope_invalid_context(self):
'''
Test with invalid context data. The context value must be a dict, so
this should raise a SaltInvocationError.
'''
# Test with invalid context data
with self.assertRaises(SaltInvocationError):
_systemd.has_scope(99999)
if __name__ == '__main__':
from integration import run_tests
run_tests(SystemdTestCase, needs_daemon=False)