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:
Erik Johnson 2016-01-28 03:36:50 -06:00
parent 4008e1719a
commit 1ec13699b6

View file

@ -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: