mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Backport systemd optimizations from develop into 2015.8
This also makes additional optimizations, such as using globbing instead of using 'systemctl list-unit-files'.
This commit is contained in:
parent
4008e1719a
commit
1ec13699b6
1 changed files with 426 additions and 265 deletions
|
@ -1,18 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Provide the service module for systemd
|
||||
|
||||
.. versionadded:: 0.10.0
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import copy
|
||||
import errno
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import glob
|
||||
import shlex
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
import salt.utils.itertools
|
||||
import salt.utils.systemd
|
||||
import salt.exceptions
|
||||
from salt.exceptions import CommandExecutionError, CommandNotFoundError
|
||||
from salt.ext import six
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,20 +26,25 @@ __func_alias__ = {
|
|||
'reload_': 'reload'
|
||||
}
|
||||
|
||||
SYSTEM_CONFIG_PATH = '/lib/systemd/system'
|
||||
LOCAL_CONFIG_PATH = '/etc/systemd/system'
|
||||
LEGACY_INIT_SCRIPT_PATH = '/etc/init.d'
|
||||
VALID_UNIT_TYPES = ['service', 'socket', 'device', 'mount', 'automount',
|
||||
'swap', 'target', 'path', 'timer']
|
||||
INITSCRIPT_PATH = '/etc/init.d'
|
||||
VALID_UNIT_TYPES = ('service', 'socket', 'device', 'mount', 'automount',
|
||||
'swap', 'target', 'path', 'timer')
|
||||
|
||||
# Define the module's virtual name
|
||||
__virtualname__ = 'service'
|
||||
|
||||
# Disable check for string substitution
|
||||
# pylint: disable=E1321
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only work on systems that have been booted with systemd
|
||||
'''
|
||||
if __grains__['kernel'] == 'Linux' and salt.utils.systemd.booted(__context__):
|
||||
if __grains__['kernel'] == 'Linux' \
|
||||
and salt.utils.systemd.booted(__context__):
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
@ -45,117 +56,35 @@ def _canonical_unit_name(name):
|
|||
'''
|
||||
if any(name.endswith(suffix) for suffix in VALID_UNIT_TYPES):
|
||||
return name
|
||||
return '{0}.service'.format(name)
|
||||
return '%s.service' % name
|
||||
|
||||
|
||||
def _canonical_template_unit_name(name):
|
||||
def _check_for_unit_changes(name):
|
||||
'''
|
||||
Build a canonical unit name for unit instances based on templates.
|
||||
Check for modified/updated unit files, and run a daemon-reload if any are
|
||||
found.
|
||||
'''
|
||||
return re.sub(r'@.+?(\.|$)', r'@\1', name)
|
||||
contextkey = 'systemd._check_for_unit_changes'
|
||||
if contextkey not in __context__:
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
# Set context key to avoid repeating this check
|
||||
__context__[contextkey] = True
|
||||
|
||||
|
||||
def _systemctl_cmd(action, name):
|
||||
def _clear_context():
|
||||
'''
|
||||
Build a systemctl command line. Treat unit names without one
|
||||
of the valid suffixes as a service.
|
||||
Remove context
|
||||
'''
|
||||
return 'systemctl {0} {1}'.format(action, _canonical_unit_name(name))
|
||||
|
||||
|
||||
def _get_all_units():
|
||||
'''
|
||||
Get all units and their state. Units ending in .service
|
||||
are normalized so that they can be referenced without a type suffix.
|
||||
'''
|
||||
rexp = re.compile(r'(?m)^(?P<name>.+)\.(?P<type>' +
|
||||
'|'.join(VALID_UNIT_TYPES) +
|
||||
r')\s+loaded\s+(?P<active>[^\s]+)')
|
||||
|
||||
out = __salt__['cmd.run_stdout'](
|
||||
'systemctl --all --full --no-legend --no-pager list-units'
|
||||
)
|
||||
|
||||
ret = {}
|
||||
for match in rexp.finditer(out):
|
||||
name = match.group('name')
|
||||
if match.group('type') != 'service':
|
||||
name += '.' + match.group('type')
|
||||
ret[name] = match.group('active')
|
||||
return ret
|
||||
|
||||
|
||||
def _get_all_unit_files():
|
||||
'''
|
||||
Get all unit files and their state. Unit files ending in .service
|
||||
are normalized so that they can be referenced without a type suffix.
|
||||
'''
|
||||
rexp = re.compile(r'(?m)^(?P<name>.+)\.(?P<type>' +
|
||||
'|'.join(VALID_UNIT_TYPES) +
|
||||
r')\s+(?P<state>.+)$')
|
||||
|
||||
out = __salt__['cmd.run_stdout'](
|
||||
'systemctl --full --no-legend --no-pager list-unit-files'
|
||||
)
|
||||
|
||||
ret = {}
|
||||
for match in rexp.finditer(out):
|
||||
name = match.group('name')
|
||||
if match.group('type') != 'service':
|
||||
name += '.' + match.group('type')
|
||||
ret[name] = match.group('state')
|
||||
return ret
|
||||
|
||||
|
||||
def _get_all_legacy_init_scripts():
|
||||
'''
|
||||
Get all old-fashioned init-style scripts. State is always inactive, because
|
||||
systemd would already show them otherwise.
|
||||
'''
|
||||
ret = {}
|
||||
if not os.path.isdir(LEGACY_INIT_SCRIPT_PATH):
|
||||
return ret
|
||||
for fn in os.listdir(LEGACY_INIT_SCRIPT_PATH):
|
||||
if not os.path.isfile(os.path.join(LEGACY_INIT_SCRIPT_PATH, fn)) or fn.startswith('rc'):
|
||||
# Using list() here because modifying a dictionary during iteration will
|
||||
# raise a RuntimeError.
|
||||
for key in list(__context__):
|
||||
try:
|
||||
if key.startswith('systemd._systemctl_status.') \
|
||||
or key in ('systemd.systemd_services',):
|
||||
__context__.pop(key)
|
||||
except AttributeError:
|
||||
continue
|
||||
log.info('Legacy init script: "%s".', fn)
|
||||
ret[fn] = 'inactive'
|
||||
return ret
|
||||
|
||||
|
||||
def _untracked_custom_unit_found(name):
|
||||
'''
|
||||
If the passed service name is not in the output from get_all(), but a unit
|
||||
file exist in /etc/systemd/system, return True. Otherwise, return False.
|
||||
'''
|
||||
unit_path = os.path.join('/etc/systemd/system',
|
||||
_canonical_unit_name(name))
|
||||
return name not in get_all() and os.access(unit_path, os.R_OK)
|
||||
|
||||
|
||||
def _unit_file_changed(name):
|
||||
'''
|
||||
Returns True if systemctl reports that the unit file has changed, otherwise
|
||||
returns False.
|
||||
'''
|
||||
return 'warning: unit file changed on disk' in \
|
||||
__salt__['cmd.run'](_systemctl_cmd('status', name)).lower()
|
||||
|
||||
|
||||
def systemctl_reload():
|
||||
'''
|
||||
Reloads systemctl, an action needed whenever unit files are updated.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.systemctl_reload
|
||||
'''
|
||||
retcode = __salt__['cmd.retcode']('systemctl --system daemon-reload')
|
||||
if retcode != 0:
|
||||
log.error('Problem performing systemctl daemon-reload')
|
||||
return retcode == 0
|
||||
|
||||
|
||||
def _default_runlevel():
|
||||
|
@ -200,22 +129,6 @@ def _default_runlevel():
|
|||
return runlevel
|
||||
|
||||
|
||||
def _runlevel():
|
||||
'''
|
||||
Return the current runlevel
|
||||
'''
|
||||
if 'systemd._runlevel' in __context__:
|
||||
return __context__['systemd._runlevel']
|
||||
out = __salt__['cmd.run']('runlevel', python_shell=False)
|
||||
try:
|
||||
ret = out.split()[1]
|
||||
except IndexError:
|
||||
# The runlevel is unknown, return the default
|
||||
ret = _default_runlevel()
|
||||
__context__['systemd._runlevel'] = ret
|
||||
return ret
|
||||
|
||||
|
||||
def _get_service_exec():
|
||||
'''
|
||||
Debian uses update-rc.d to manage System-V style services.
|
||||
|
@ -226,53 +139,175 @@ def _get_service_exec():
|
|||
return executable
|
||||
|
||||
|
||||
def _get_systemd_services():
|
||||
'''
|
||||
Use os.listdir() to get all the unit files
|
||||
'''
|
||||
contextkey = 'systemd.systemd_services'
|
||||
if contextkey in __context__:
|
||||
return __context__[contextkey]
|
||||
ret = set()
|
||||
for path in (SYSTEM_CONFIG_PATH, LOCAL_CONFIG_PATH):
|
||||
for fullname in os.listdir(path):
|
||||
try:
|
||||
unit_name, unit_type = fullname.rsplit('.', 1)
|
||||
except ValueError:
|
||||
continue
|
||||
if unit_type in VALID_UNIT_TYPES:
|
||||
ret.add(unit_name if unit_type == 'service' else fullname)
|
||||
__context__[contextkey] = copy.deepcopy(ret)
|
||||
return ret
|
||||
|
||||
|
||||
def _get_sysv_services():
|
||||
'''
|
||||
Use os.listdir() and os.access() to get all the initscripts
|
||||
'''
|
||||
try:
|
||||
sysv_services = os.listdir(INITSCRIPT_PATH)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST:
|
||||
pass
|
||||
elif exc.errno == errno.EACCES:
|
||||
log.error(
|
||||
'Unable to check sysvinit scripts, permission denied to %s',
|
||||
INITSCRIPT_PATH
|
||||
)
|
||||
else:
|
||||
log.error(
|
||||
'Error %d encountered trying to check sysvinit scripts: %s',
|
||||
exc.errno,
|
||||
exc.strerror
|
||||
)
|
||||
return []
|
||||
|
||||
systemd_services = _get_systemd_services()
|
||||
ret = []
|
||||
for sysv_service in sysv_services:
|
||||
if os.access(os.path.join(INITSCRIPT_PATH, sysv_service), os.X_OK):
|
||||
if sysv_service in systemd_services:
|
||||
log.debug(
|
||||
'sysvinit script \'%s\' found, but systemd unit '
|
||||
'\'%s.service\' already exists',
|
||||
sysv_service, sysv_service
|
||||
)
|
||||
continue
|
||||
ret.append(sysv_service)
|
||||
return ret
|
||||
|
||||
|
||||
def _has_sysv_exec():
|
||||
'''
|
||||
Return the current runlevel
|
||||
'''
|
||||
if 'systemd._has_sysv_exec' not in __context__:
|
||||
contextkey = 'systemd._has_sysv_exec'
|
||||
if contextkey not in __context__:
|
||||
try:
|
||||
__context__['systemd._has_sysv_exec'] = bool(_get_service_exec())
|
||||
except(
|
||||
salt.exceptions.CommandExecutionError,
|
||||
salt.exceptions.CommandNotFoundError
|
||||
):
|
||||
__context__['systemd._has_sysv_exec'] = False
|
||||
return __context__['systemd._has_sysv_exec']
|
||||
__context__[contextkey] = bool(_get_service_exec())
|
||||
except (CommandExecutionError, CommandNotFoundError):
|
||||
__context__[contextkey] = False
|
||||
return __context__[contextkey]
|
||||
|
||||
|
||||
def _sysv_exists(name):
|
||||
script = '/etc/init.d/{0}'.format(name)
|
||||
return os.access(script, os.X_OK)
|
||||
|
||||
|
||||
def _service_is_sysv(name):
|
||||
def _runlevel():
|
||||
'''
|
||||
A System-V style service will have a control script in
|
||||
/etc/init.d.
|
||||
Return True only if the service doesnt also provide a systemd unit file.
|
||||
Return the current runlevel
|
||||
'''
|
||||
return (_has_sysv_exec() and
|
||||
name in _get_all_units() and
|
||||
name not in _get_all_unit_files() and
|
||||
_sysv_exists(name))
|
||||
contextkey = 'systemd._runlevel'
|
||||
if contextkey in __context__:
|
||||
return __context__[contextkey]
|
||||
out = __salt__['cmd.run']('runlevel', python_shell=False)
|
||||
try:
|
||||
ret = out.split()[1]
|
||||
except IndexError:
|
||||
# The runlevel is unknown, return the default
|
||||
ret = _default_runlevel()
|
||||
__context__[contextkey] = ret
|
||||
return ret
|
||||
|
||||
|
||||
def _sysv_is_disabled(name):
|
||||
def _systemctl_cmd(action, name=None):
|
||||
'''
|
||||
A System-V style service is assumed disabled if there is no
|
||||
start-up link (starts with "S") to its script in /etc/init.d in
|
||||
the current runlevel.
|
||||
Build a systemctl command line. Treat unit names without one
|
||||
of the valid suffixes as a service.
|
||||
'''
|
||||
return not bool(glob.glob('/etc/rc{0}.d/S*{1}'.format(_runlevel(), name)))
|
||||
ret = ['systemctl']
|
||||
if isinstance(action, six.string_types):
|
||||
action = shlex.split(action)
|
||||
ret.extend(action)
|
||||
if name is not None:
|
||||
ret.append(_canonical_unit_name(name))
|
||||
if 'status' in ret:
|
||||
ret.extend(['-n', '0'])
|
||||
return ret
|
||||
|
||||
|
||||
def _sysv_is_enabled(name):
|
||||
def _systemctl_status(name):
|
||||
'''
|
||||
Assume that if a System-V style service is not disabled then it
|
||||
must be enabled.
|
||||
Helper function which leverages __context__ to keep from running 'systemctl
|
||||
status' more than once.
|
||||
'''
|
||||
return not _sysv_is_disabled(name)
|
||||
contextkey = 'systemd._systemctl_status.%s' % name
|
||||
if contextkey in __context__:
|
||||
return __context__[contextkey]
|
||||
__context__[contextkey] = __salt__['cmd.run'](
|
||||
_systemctl_cmd('status', name),
|
||||
python_shell=False,
|
||||
ignore_retcode=True
|
||||
)
|
||||
return __context__[contextkey]
|
||||
|
||||
|
||||
def _sysv_enabled(name):
|
||||
'''
|
||||
A System-V style service is assumed disabled if the "startup" symlink
|
||||
(starts with "S") to its script is found in /etc/init.d in the current
|
||||
runlevel.
|
||||
'''
|
||||
return bool(glob.glob('/etc/rc%s.d/S*%s' % (_runlevel(), name)))
|
||||
|
||||
|
||||
def _untracked_custom_unit_found(name):
|
||||
'''
|
||||
If the passed service name is not available, but a unit file exist in
|
||||
/etc/systemd/system, return True. Otherwise, return False.
|
||||
'''
|
||||
unit_path = os.path.join('/etc/systemd/system',
|
||||
_canonical_unit_name(name))
|
||||
return os.access(unit_path, os.R_OK) and not available(name)
|
||||
|
||||
|
||||
def _unit_file_changed(name):
|
||||
'''
|
||||
Returns True if systemctl reports that the unit file has changed, otherwise
|
||||
returns False.
|
||||
'''
|
||||
return "'systemctl daemon-reload'" in _systemctl_status(name).lower()
|
||||
|
||||
|
||||
def systemctl_reload():
|
||||
'''
|
||||
.. versionadded:: 0.15.0
|
||||
|
||||
Reloads systemctl, an action needed whenever unit files are updated.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.systemctl_reload
|
||||
'''
|
||||
out = __salt__['cmd.run_all'](
|
||||
_systemctl_cmd('--system daemon-reload'),
|
||||
python_shell=False,
|
||||
redirect_stderr=True
|
||||
)
|
||||
if out['retcode'] != 0:
|
||||
raise CommandExecutionError(
|
||||
'Problem performing systemctl daemon-reload: %s' % out['stdout']
|
||||
)
|
||||
_clear_context()
|
||||
return True
|
||||
|
||||
|
||||
def get_enabled():
|
||||
|
@ -285,21 +320,33 @@ def get_enabled():
|
|||
|
||||
salt '*' service.get_enabled
|
||||
'''
|
||||
ret = []
|
||||
units = _get_all_unit_files()
|
||||
services = _get_all_units()
|
||||
for name, state in six.iteritems(units):
|
||||
if state == 'enabled':
|
||||
ret.append(name)
|
||||
for name, state in six.iteritems(services):
|
||||
if name in units:
|
||||
ret = set()
|
||||
# Get enabled systemd units. Can't use --state=enabled here because it's
|
||||
# not present until systemd 216.
|
||||
out = __salt__['cmd.run'](
|
||||
_systemctl_cmd('--full --no-legend --no-pager list-unit-files'),
|
||||
python_shell=False,
|
||||
ignore_retcode=True,
|
||||
)
|
||||
for line in salt.utils.itertools.split(out, '\n'):
|
||||
try:
|
||||
fullname, unit_state = line.strip().split(None, 1)
|
||||
except ValueError:
|
||||
continue
|
||||
# performance; if the legacy initscript doesnt exists,
|
||||
# don't contiue up with systemd query
|
||||
if not _service_is_sysv(name):
|
||||
else:
|
||||
if unit_state != 'enabled':
|
||||
continue
|
||||
try:
|
||||
unit_name, unit_type = fullname.rsplit('.', 1)
|
||||
except ValueError:
|
||||
continue
|
||||
if _sysv_is_enabled(name):
|
||||
ret.append(name)
|
||||
if unit_type in VALID_UNIT_TYPES:
|
||||
ret.add(unit_name if unit_type == 'service' else fullname)
|
||||
|
||||
# Add in any sysvinit services that are enabled
|
||||
ret.update(set(
|
||||
[x for x in _get_sysv_services() if _sysv_enabled(x)]
|
||||
))
|
||||
return sorted(ret)
|
||||
|
||||
|
||||
|
@ -313,12 +360,72 @@ def get_disabled():
|
|||
|
||||
salt '*' service.get_disabled
|
||||
'''
|
||||
ret = []
|
||||
known_services = _get_all_unit_files()
|
||||
known_services.update(_get_all_legacy_init_scripts())
|
||||
for name, state in six.iteritems(known_services):
|
||||
if state == 'disabled':
|
||||
ret.append(name)
|
||||
ret = set()
|
||||
# Get disabled systemd units. Can't use --state=disabled here because it's
|
||||
# not present until systemd 216.
|
||||
out = __salt__['cmd.run'](
|
||||
_systemctl_cmd('--full --no-legend --no-pager list-unit-files'),
|
||||
python_shell=False,
|
||||
ignore_retcode=True,
|
||||
)
|
||||
for line in salt.utils.itertools.split(out, '\n'):
|
||||
try:
|
||||
fullname, unit_state = line.strip().split(None, 1)
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
if unit_state != 'disabled':
|
||||
continue
|
||||
try:
|
||||
unit_name, unit_type = fullname.rsplit('.', 1)
|
||||
except ValueError:
|
||||
continue
|
||||
if unit_type in VALID_UNIT_TYPES:
|
||||
ret.add(unit_name if unit_type == 'service' else fullname)
|
||||
|
||||
# Add in any sysvinit services that are disabled
|
||||
ret.update(set(
|
||||
[x for x in _get_sysv_services() if not _sysv_enabled(x)]
|
||||
))
|
||||
return sorted(ret)
|
||||
|
||||
|
||||
def get_static():
|
||||
'''
|
||||
.. versionadded:: 2015.8.5
|
||||
|
||||
Return a list of all static services
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.get_static
|
||||
'''
|
||||
ret = set()
|
||||
# Get static systemd units. Can't use --state=static here because it's
|
||||
# not present until systemd 216.
|
||||
out = __salt__['cmd.run'](
|
||||
_systemctl_cmd('--full --no-legend --no-pager list-unit-files'),
|
||||
python_shell=False,
|
||||
ignore_retcode=True,
|
||||
)
|
||||
for line in salt.utils.itertools.split(out, '\n'):
|
||||
try:
|
||||
fullname, unit_state = line.strip().split(None, 1)
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
if unit_state != 'static':
|
||||
continue
|
||||
try:
|
||||
unit_name, unit_type = fullname.rsplit('.', 1)
|
||||
except ValueError:
|
||||
continue
|
||||
if unit_type in VALID_UNIT_TYPES:
|
||||
ret.add(unit_name if unit_type == 'service' else fullname)
|
||||
|
||||
# sysvinit services cannot be static
|
||||
return sorted(ret)
|
||||
|
||||
|
||||
|
@ -332,14 +439,17 @@ def get_all():
|
|||
|
||||
salt '*' service.get_all
|
||||
'''
|
||||
return sorted(set(list(_get_all_units().keys()) + list(_get_all_unit_files().keys())
|
||||
+ list(_get_all_legacy_init_scripts().keys())))
|
||||
ret = _get_systemd_services()
|
||||
ret.update(set(_get_sysv_services()))
|
||||
return sorted(ret)
|
||||
|
||||
|
||||
def available(name):
|
||||
'''
|
||||
Check that the given service is available taking into account
|
||||
template units.
|
||||
.. versionadded:: 0.10.4
|
||||
|
||||
Check that the given service is available taking into account template
|
||||
units.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -347,24 +457,26 @@ def available(name):
|
|||
|
||||
salt '*' service.available sshd
|
||||
'''
|
||||
name = _canonical_template_unit_name(name)
|
||||
if name.endswith('.service'):
|
||||
name = name[:-8] # len('.service') is 8
|
||||
units = get_all()
|
||||
if name in units:
|
||||
return True
|
||||
elif '@' in name:
|
||||
templatename = name[:name.find('@') + 1]
|
||||
return templatename in units
|
||||
out = _systemctl_status(name).lower()
|
||||
for line in salt.utils.itertools.split(out, '\n'):
|
||||
match = re.match(r'\s+loaded:\s+(\S+)', line)
|
||||
if match:
|
||||
ret = match.group(1) != 'not-found'
|
||||
break
|
||||
else:
|
||||
return False
|
||||
raise CommandExecutionError(
|
||||
'Failed to get information on unit \'%s\'' % name
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
def missing(name):
|
||||
'''
|
||||
The inverse of service.available.
|
||||
Returns ``True`` if the specified service is not available, otherwise returns
|
||||
``False``.
|
||||
.. versionadded:: 2014.1.0
|
||||
|
||||
The inverse of :py:func:`service.available
|
||||
<salt.modules.systemd.available>`. Returns ``True`` if the specified
|
||||
service is not available, otherwise returns ``False``.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -377,6 +489,8 @@ def missing(name):
|
|||
|
||||
def unmask(name):
|
||||
'''
|
||||
.. versionadded:: 2015.5.0
|
||||
|
||||
Unmask the specified service with systemd
|
||||
|
||||
CLI Example:
|
||||
|
@ -385,32 +499,64 @@ def unmask(name):
|
|||
|
||||
salt '*' service.unmask <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
return not (__salt__['cmd.retcode'](_systemctl_cmd('unmask', name))
|
||||
or __salt__['cmd.retcode'](_systemctl_cmd('unmask --runtime', name)))
|
||||
_check_for_unit_changes(name)
|
||||
mask_status = masked(name)
|
||||
if not mask_status:
|
||||
log.debug('Service \'%s\' is not masked', name)
|
||||
return True
|
||||
|
||||
cmd = 'unmask --runtime' if 'runtime' in mask_status else 'unmask'
|
||||
out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name),
|
||||
python_shell=False,
|
||||
redirect_stderr=True)
|
||||
|
||||
if out['retcode'] != 0:
|
||||
raise CommandExecutionError('Failed to unmask service \'%s\'' % name)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def mask(name):
|
||||
def mask(name, runtime=False):
|
||||
'''
|
||||
.. versionadded:: 2015.5.0
|
||||
|
||||
Mask the specified service with systemd
|
||||
|
||||
runtime : False
|
||||
Set to ``True`` to mask this service only until the next reboot
|
||||
|
||||
.. versionadded:: 2015.8.5
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' service.mask <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('mask', name))
|
||||
_check_for_unit_changes(name)
|
||||
|
||||
cmd = 'mask --runtime' if runtime else 'mask'
|
||||
out = __salt__['cmd.run_all'](_systemctl_cmd(cmd, name),
|
||||
python_shell=False,
|
||||
redirect_stderr=True)
|
||||
|
||||
if out['retcode'] != 0:
|
||||
raise CommandExecutionError('Failed to mask service \'%s\'' % name)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def masked(name):
|
||||
'''
|
||||
Return if the named service is masked.
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
.. versionchanged:: 2015.8.5
|
||||
The return data for this function has changed. If the service is
|
||||
masked, the return value will now be the output of the ``systemctl
|
||||
is-enabled`` command (so that a persistent mask can be distinguished
|
||||
from a runtime mask). If the service is not masked, then ``False`` will
|
||||
be returned.
|
||||
|
||||
Check whether or not a service is masked
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -418,10 +564,13 @@ def masked(name):
|
|||
|
||||
salt '*' service.masked <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
out = __salt__['cmd.run_all'](_systemctl_cmd('is-enabled', name), ignore_retcode=True)
|
||||
return out['retcode'] == 1 and 'masked' in out['stdout']
|
||||
_check_for_unit_changes(name)
|
||||
out = __salt__['cmd.run'](
|
||||
_systemctl_cmd('is-enabled', name),
|
||||
python_shell=False,
|
||||
ignore_retcode=True,
|
||||
)
|
||||
return out if 'masked' in out else False
|
||||
|
||||
|
||||
def start(name):
|
||||
|
@ -450,9 +599,9 @@ def stop(name):
|
|||
|
||||
salt '*' service.stop <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('stop', name))
|
||||
_check_for_unit_changes(name)
|
||||
return __salt__['cmd.retcode'](_systemctl_cmd('stop', name),
|
||||
python_shell=False) == 0
|
||||
|
||||
|
||||
def restart(name):
|
||||
|
@ -465,10 +614,10 @@ def restart(name):
|
|||
|
||||
salt '*' service.restart <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
_check_for_unit_changes(name)
|
||||
unmask(name)
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('restart', name))
|
||||
return __salt__['cmd.retcode'](_systemctl_cmd('restart', name),
|
||||
python_shell=False) == 0
|
||||
|
||||
|
||||
def reload_(name):
|
||||
|
@ -481,14 +630,16 @@ def reload_(name):
|
|||
|
||||
salt '*' service.reload <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
_check_for_unit_changes(name)
|
||||
unmask(name)
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('reload', name))
|
||||
return __salt__['cmd.retcode'](_systemctl_cmd('reload', name),
|
||||
python_shell=False) == 0
|
||||
|
||||
|
||||
def force_reload(name):
|
||||
'''
|
||||
.. versionadded:: 0.12.0
|
||||
|
||||
Force-reload the specified service with systemd
|
||||
|
||||
CLI Example:
|
||||
|
@ -497,15 +648,15 @@ def force_reload(name):
|
|||
|
||||
salt '*' service.force_reload <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
_check_for_unit_changes(name)
|
||||
unmask(name)
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('force-reload', name))
|
||||
return __salt__['cmd.retcode'](_systemctl_cmd('force-reload', name),
|
||||
python_shell=False) == 0
|
||||
|
||||
|
||||
# The unused sig argument is required to maintain consistency in the state
|
||||
# system
|
||||
def status(name, sig=None):
|
||||
# The unused sig argument is required to maintain consistency with the API
|
||||
# established by Salt's service management states.
|
||||
def status(name, sig=None): # pylint: disable=unused-argument
|
||||
'''
|
||||
Return the status for a service via systemd, returns a bool
|
||||
whether the service is running.
|
||||
|
@ -516,13 +667,15 @@ def status(name, sig=None):
|
|||
|
||||
salt '*' service.status <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('is-active', name),
|
||||
ignore_retcode=True)
|
||||
_check_for_unit_changes(name)
|
||||
return __salt__['cmd.retcode'](_systemctl_cmd('is-active', name),
|
||||
python_shell=False,
|
||||
ignore_retcode=True) == 0
|
||||
|
||||
|
||||
def enable(name, **kwargs):
|
||||
# The unused kwargs argument is required to maintain consistency with the API
|
||||
# established by Salt's service management states.
|
||||
def enable(name, **kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Enable the named service to start when the system boots
|
||||
|
||||
|
@ -532,17 +685,21 @@ def enable(name, **kwargs):
|
|||
|
||||
salt '*' service.enable <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
_check_for_unit_changes(name)
|
||||
unmask(name)
|
||||
if _service_is_sysv(name):
|
||||
executable = _get_service_exec()
|
||||
cmd = '{0} -f {1} defaults 99'.format(executable, name)
|
||||
return not __salt__['cmd.retcode'](cmd, python_shell=False)
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('enable', name))
|
||||
if name in _get_sysv_services():
|
||||
cmd = [_get_service_exec(), '-f', name, 'defaults', '99']
|
||||
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
|
||||
|
||||
|
||||
def disable(name, **kwargs):
|
||||
# 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
|
||||
'''
|
||||
Disable the named service to not start when the system boots
|
||||
|
||||
|
@ -552,38 +709,20 @@ def disable(name, **kwargs):
|
|||
|
||||
salt '*' service.disable <service name>
|
||||
'''
|
||||
if _untracked_custom_unit_found(name) or _unit_file_changed(name):
|
||||
systemctl_reload()
|
||||
if _service_is_sysv(name):
|
||||
executable = _get_service_exec()
|
||||
cmd = [executable, '-f', name, 'remove']
|
||||
return not __salt__['cmd.retcode'](cmd, python_shell=False)
|
||||
return not __salt__['cmd.retcode'](_systemctl_cmd('disable', name))
|
||||
_check_for_unit_changes(name)
|
||||
if name in _get_sysv_services():
|
||||
cmd = [_get_service_exec(), '-f', name, 'remove']
|
||||
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
|
||||
|
||||
|
||||
def _templated_instance_enabled(name):
|
||||
'''
|
||||
Services instantiated based on templates can not be checked with
|
||||
systemctl is-enabled. Presence of the actual symlinks is checked
|
||||
as a fall-back.
|
||||
'''
|
||||
if '@' not in name:
|
||||
return False
|
||||
find_unit_by_name = 'find {0} -name {1} -type l -print -quit'
|
||||
return len(__salt__['cmd.run'](
|
||||
find_unit_by_name.format(LOCAL_CONFIG_PATH,
|
||||
_canonical_unit_name(name))
|
||||
))
|
||||
|
||||
|
||||
def _enabled(name):
|
||||
is_enabled = \
|
||||
not __salt__['cmd.retcode'](_systemctl_cmd('is-enabled', name),
|
||||
ignore_retcode=True)
|
||||
return is_enabled or _templated_instance_enabled(name) or _sysv_is_enabled(name)
|
||||
|
||||
|
||||
def enabled(name, **kwargs):
|
||||
# The unused kwargs argument is required to maintain consistency with the API
|
||||
# established by Salt's service management states.
|
||||
def enabled(name, **kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Return if the named service is enabled to start on boot
|
||||
|
||||
|
@ -593,7 +732,25 @@ def enabled(name, **kwargs):
|
|||
|
||||
salt '*' service.enabled <service name>
|
||||
'''
|
||||
return _enabled(name)
|
||||
# Try 'systemctl is-enabled' first, then look for a symlink created by
|
||||
# systemctl (older systemd releases did not support using is-enabled to
|
||||
# check templated services), and lastly check for a sysvinit service.
|
||||
if __salt__['cmd.retcode'](_systemctl_cmd('is-enabled', name),
|
||||
python_shell=False,
|
||||
ignore_retcode=True) == 0:
|
||||
return True
|
||||
elif '@' in name:
|
||||
# On older systemd releases, templated services could not be checked
|
||||
# with ``systemctl is-enabled``. As a fallback, look for the symlinks
|
||||
# created by systemctl when enabling templated services.
|
||||
cmd = ['find', LOCAL_CONFIG_PATH, '-name', name,
|
||||
'-type', 'l', '-print', '-quit']
|
||||
# If the find command returns any matches, there will be output and the
|
||||
# string will be non-empty.
|
||||
if bool(__salt__['cmd.run'](cmd, python_shell=False)):
|
||||
return True
|
||||
else:
|
||||
return _sysv_enabled(name)
|
||||
|
||||
|
||||
def disabled(name):
|
||||
|
@ -606,11 +763,13 @@ def disabled(name):
|
|||
|
||||
salt '*' service.disabled <service name>
|
||||
'''
|
||||
return not _enabled(name) and not _sysv_is_enabled(name)
|
||||
return not enabled(name)
|
||||
|
||||
|
||||
def show(name):
|
||||
'''
|
||||
.. versionadded:: 2014.7.0
|
||||
|
||||
Show properties of one or more units/jobs or the manager
|
||||
|
||||
CLI Example:
|
||||
|
@ -638,6 +797,8 @@ def show(name):
|
|||
|
||||
def execs():
|
||||
'''
|
||||
.. versionadded:: 2014.7.0
|
||||
|
||||
Return a list of all files specified as ``ExecStart`` for all services.
|
||||
|
||||
CLI Example:
|
||||
|
|
Loading…
Add table
Reference in a new issue