Mini Shell
"""
Top level package command wrapper, used to translate the os detected by grains
to the correct service manager
.. important::
If you feel that Salt should be using this module to manage services on a
minion, and it is using a different module (or gives an error similar to
*'service.start' is not available*), see :ref:`here
<module-provider-override>`.
"""
import fnmatch
import logging
import re
import salt.utils.odict as odict
import salt.utils.systemd
# Set up logging
log = logging.getLogger(__name__)
# Define the module's virtual name
__virtualname__ = "service"
# Define the module's function aliases
__func_alias__ = {"reload_": "reload"}
def __virtual__():
"""
Only work on systems which default to OpenRC
"""
if __grains__["os"] == "Gentoo" and not salt.utils.systemd.booted(__context__):
return __virtualname__
if __grains__["os"] == "Alpine":
return __virtualname__
return (
False,
"The gentoo_service execution module cannot be loaded: "
"only available on Gentoo/Open-RC systems.",
)
def _ret_code(cmd, ignore_retcode=False):
log.debug("executing [%s]", cmd)
sts = __salt__["cmd.retcode"](
cmd, python_shell=False, ignore_retcode=ignore_retcode
)
return sts
def _list_services():
return __salt__["cmd.run"]("rc-update -v show").splitlines()
def _get_service_list(include_enabled=True, include_disabled=False):
enabled_services = dict()
disabled_services = set()
lines = _list_services()
for line in lines:
if "|" not in line:
continue
service = [l.strip() for l in line.split("|")]
# enabled service should have runlevels
if service[1]:
if include_enabled:
enabled_services.update({service[0]: sorted(service[1].split())})
continue
# in any other case service is disabled
if include_disabled:
disabled_services.update({service[0]: []})
return enabled_services, disabled_services
def _enable_delta(name, requested_runlevels):
all_enabled = get_enabled()
current_levels = set(all_enabled[name] if name in all_enabled else [])
enabled_levels = requested_runlevels - current_levels
disabled_levels = current_levels - requested_runlevels
return enabled_levels, disabled_levels
def _disable_delta(name, requested_runlevels):
all_enabled = get_enabled()
current_levels = set(all_enabled[name] if name in all_enabled else [])
return current_levels & requested_runlevels
def _service_cmd(*args):
return "/etc/init.d/{} {}".format(args[0], " ".join(args[1:]))
def _enable_disable_cmd(name, command, runlevels=()):
return "rc-update {} {} {}".format(
command, name, " ".join(sorted(runlevels))
).strip()
def get_enabled():
"""
Return a list of service that are enabled on boot
CLI Example:
.. code-block:: bash
salt '*' service.get_enabled
"""
(enabled_services, disabled_services) = _get_service_list()
return odict.OrderedDict(enabled_services)
def get_disabled():
"""
Return a set of services that are installed but disabled
CLI Example:
.. code-block:: bash
salt '*' service.get_disabled
"""
(enabled_services, disabled_services) = _get_service_list(
include_enabled=False, include_disabled=True
)
return sorted(disabled_services)
def available(name):
"""
Returns ``True`` if the specified service is available, otherwise returns
``False``.
CLI Example:
.. code-block:: bash
salt '*' service.available sshd
"""
(enabled_services, disabled_services) = _get_service_list(
include_enabled=True, include_disabled=True
)
return name in enabled_services or name in disabled_services
def missing(name):
"""
The inverse of service.available.
Returns ``True`` if the specified service is not available, otherwise returns
``False``.
CLI Example:
.. code-block:: bash
salt '*' service.missing sshd
"""
return not available(name)
def get_all():
"""
Return all available boot services
CLI Example:
.. code-block:: bash
salt '*' service.get_all
"""
(enabled_services, disabled_services) = _get_service_list(
include_enabled=True, include_disabled=True
)
enabled_services.update({s: [] for s in disabled_services})
return odict.OrderedDict(enabled_services)
def start(name):
"""
Start the specified service
CLI Example:
.. code-block:: bash
salt '*' service.start <service name>
"""
cmd = _service_cmd(name, "start")
return not _ret_code(cmd)
def stop(name):
"""
Stop the specified service
CLI Example:
.. code-block:: bash
salt '*' service.stop <service name>
"""
cmd = _service_cmd(name, "stop")
return not _ret_code(cmd)
def restart(name):
"""
Restart the named service
CLI Example:
.. code-block:: bash
salt '*' service.restart <service name>
"""
cmd = _service_cmd(name, "restart")
return not _ret_code(cmd)
def reload_(name):
"""
Reload the named service
CLI Example:
.. code-block:: bash
salt '*' service.reload <service name>
"""
cmd = _service_cmd(name, "reload")
return not _ret_code(cmd)
def zap(name):
"""
Resets service state
CLI Example:
.. code-block:: bash
salt '*' service.zap <service name>
"""
cmd = _service_cmd(name, "zap")
return not _ret_code(cmd)
def status(name, sig=None):
"""
Return the status for a service.
If the name contains globbing, a dict mapping service name to True/False
values is returned.
.. versionchanged:: 2018.3.0
The service name can now be a glob (e.g. ``salt*``)
Args:
name (str): The name of the service to check
sig (str): Signature to use to find the service via ps
Returns:
bool: True if running, False otherwise
dict: Maps service name to True if running, False otherwise
CLI Example:
.. code-block:: bash
salt '*' service.status <service name> [service signature]
"""
if sig:
return bool(__salt__["status.pid"](sig))
contains_globbing = bool(re.search(r"\*|\?|\[.+\]", name))
if contains_globbing:
services = fnmatch.filter(get_all(), name)
else:
services = [name]
results = {}
for service in services:
cmd = _service_cmd(service, "status")
results[service] = not _ret_code(cmd, ignore_retcode=True)
if contains_globbing:
return results
return results[name]
def enable(name, **kwargs):
"""
Enable the named service to start at boot
CLI Example:
.. code-block:: bash
salt '*' service.enable <service name> <runlevels=single-runlevel>
salt '*' service.enable <service name> <runlevels=[runlevel1,runlevel2]>
"""
if "runlevels" in kwargs:
requested_levels = set(
kwargs["runlevels"]
if isinstance(kwargs["runlevels"], list)
else [kwargs["runlevels"]]
)
enabled_levels, disabled_levels = _enable_delta(name, requested_levels)
commands = []
if disabled_levels:
commands.append(_enable_disable_cmd(name, "delete", disabled_levels))
if enabled_levels:
commands.append(_enable_disable_cmd(name, "add", enabled_levels))
if not commands:
return True
else:
commands = [_enable_disable_cmd(name, "add")]
for cmd in commands:
if _ret_code(cmd):
return False
return True
def disable(name, **kwargs):
"""
Disable the named service to start at boot
CLI Example:
.. code-block:: bash
salt '*' service.disable <service name> <runlevels=single-runlevel>
salt '*' service.disable <service name> <runlevels=[runlevel1,runlevel2]>
"""
levels = []
if "runlevels" in kwargs:
requested_levels = set(
kwargs["runlevels"]
if isinstance(kwargs["runlevels"], list)
else [kwargs["runlevels"]]
)
levels = _disable_delta(name, requested_levels)
if not levels:
return True
cmd = _enable_disable_cmd(name, "delete", levels)
return not _ret_code(cmd)
def enabled(name, **kwargs):
"""
Return True if the named service is enabled, false otherwise
CLI Example:
.. code-block:: bash
salt '*' service.enabled <service name> <runlevels=single-runlevel>
salt '*' service.enabled <service name> <runlevels=[runlevel1,runlevel2]>
"""
enabled_services = get_enabled()
if name not in enabled_services:
return False
if "runlevels" not in kwargs:
return True
requested_levels = set(
kwargs["runlevels"]
if isinstance(kwargs["runlevels"], list)
else [kwargs["runlevels"]]
)
return len(requested_levels - set(enabled_services[name])) == 0
def disabled(name):
"""
Return True if the named service is enabled, false otherwise
CLI Example:
.. code-block:: bash
salt '*' service.disabled <service name> <runlevels=[runlevel]>
"""
return name in get_disabled()
Zerion Mini Shell 1.0