Add OpenRC support to the service module.

This commit is contained in:
Yap Sok Ann 2013-06-17 11:29:48 +08:00
parent f8f9e7167d
commit ec265a98e0

View file

@ -54,6 +54,12 @@ options:
- Whether the service should start on boot. At least one of state and - Whether the service should start on boot. At least one of state and
enabled are required. enabled are required.
runlevel:
required: false
description:
- The runlevel that this service belongs to. Needed by OpenRC system
(e.g. Gentoo), and default to "default" if not set.
arguments: arguments:
description: description:
- Additional arguments provided on the command line - Additional arguments provided on the command line
@ -77,6 +83,7 @@ examples:
import platform import platform
import os import os
import re
import tempfile import tempfile
import shlex import shlex
import select import select
@ -107,8 +114,10 @@ class Service(object):
self.state = module.params['state'] self.state = module.params['state']
self.pattern = module.params['pattern'] self.pattern = module.params['pattern']
self.enable = module.params['enabled'] self.enable = module.params['enabled']
self.runlevel = module.params['runlevel']
self.changed = False self.changed = False
self.running = None self.running = None
self.crashed = None
self.action = None self.action = None
self.svc_cmd = None self.svc_cmd = None
self.svc_initscript = None self.svc_initscript = None
@ -352,7 +361,7 @@ class LinuxService(Service):
def get_service_tools(self): def get_service_tools(self):
paths = [ '/sbin', '/usr/sbin', '/bin', '/usr/bin' ] paths = [ '/sbin', '/usr/sbin', '/bin', '/usr/bin' ]
binaries = [ 'service', 'chkconfig', 'update-rc.d', 'initctl', 'systemctl', 'start', 'stop', 'restart' ] binaries = [ 'service', 'chkconfig', 'update-rc.d', 'rc-service', 'rc-update', 'initctl', 'systemctl', 'start', 'stop', 'restart' ]
initpaths = [ '/etc/init.d' ] initpaths = [ '/etc/init.d' ]
location = dict() location = dict()
@ -371,6 +380,11 @@ class LinuxService(Service):
elif location.get('update-rc.d', None) and os.path.exists("/etc/init.d/%s" % self.name): elif location.get('update-rc.d', None) and os.path.exists("/etc/init.d/%s" % self.name):
# service is managed by with SysV init scripts, but with update-rc.d # service is managed by with SysV init scripts, but with update-rc.d
self.enable_cmd = location['update-rc.d'] self.enable_cmd = location['update-rc.d']
elif location.get('rc-service', None) and not location.get('systemctl', None):
# service is managed by OpenRC
self.svc_cmd = location['rc-service']
self.enable_cmd = location['rc-update']
return
elif location.get('systemctl', None): elif location.get('systemctl', None):
# verify service is managed by systemd # verify service is managed by systemd
@ -427,6 +441,11 @@ class LinuxService(Service):
elif initctl_status_stdout.find("start/running") != -1: elif initctl_status_stdout.find("start/running") != -1:
self.running = True self.running = True
if self.svc_cmd.endswith("rc-service") and self.running is None:
openrc_rc, openrc_status_stdout, openrc_status_stderr = self.execute_command("%s %s status" % (self.svc_cmd, self.name))
self.running = "started" in openrc_status_stdout
self.crashed = "crashed" in openrc_status_stderr
# if the job status is still not known check it by response code # if the job status is still not known check it by response code
# For reference, see: # For reference, see:
# http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html # http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
@ -501,19 +520,44 @@ class LinuxService(Service):
elif not self.enable: elif not self.enable:
return return
# we change argument depending on real binary used if self.enable_cmd.endswith("rc-update"):
# update-rc.d wants enable/disable while (rc, out, err) = self.execute_command("%s show" % self.enable_cmd)
# chkconfig wants on/off for line in out.splitlines():
# also, systemctl needs the argument order reversed service_name, runlevels = line.split('|')
service_name = service_name.strip()
if service_name != self.name:
continue
runlevels = re.split(r'\s+', runlevels)
# service already enabled for the runlevel
if self.enable and self.runlevel in runlevels:
return
# service already disabled for the runlevel
elif not self.enable and self.runlevel not in runlevels:
return
break
else:
# service already disabled altogether
if not self.enable:
return
# we change argument depending on real binary used:
# - update-rc.d and systemctl wants enable/disable
# - chkconfig wants on/off
# - rc-update wants add/delete
# also, rc-update and systemctl needs the argument order reversed
if self.enable: if self.enable:
on_off = "on" on_off = "on"
enable_disable = "enable" enable_disable = "enable"
add_delete = "add"
else: else:
on_off = "off" on_off = "off"
enable_disable = "disable" enable_disable = "disable"
add_delete = "delete"
if self.enable_cmd.endswith("update-rc.d"): if self.enable_cmd.endswith("update-rc.d"):
args = (self.enable_cmd, self.name, enable_disable) args = (self.enable_cmd, self.name, enable_disable)
elif self.enable_cmd.endswith("rc-update"):
args = (self.enable_cmd, add_delete, self.name + " " + self.runlevel)
elif self.enable_cmd.endswith("systemctl"): elif self.enable_cmd.endswith("systemctl"):
args = (self.enable_cmd, enable_disable, self.name + ".service") args = (self.enable_cmd, enable_disable, self.name + ".service")
else: else:
@ -534,7 +578,7 @@ class LinuxService(Service):
arguments = self.arguments arguments = self.arguments
if self.svc_cmd: if self.svc_cmd:
if not self.svc_cmd.endswith("systemctl"): if not self.svc_cmd.endswith("systemctl"):
# SysV take the form <cmd> <name> <action> # SysV and OpenRC take the form <cmd> <name> <action>
svc_cmd = "%s %s" % (self.svc_cmd, self.name) svc_cmd = "%s %s" % (self.svc_cmd, self.name)
else: else:
# systemd commands take the form <cmd> <action> <name> # systemd commands take the form <cmd> <action> <name>
@ -544,15 +588,23 @@ class LinuxService(Service):
# upstart # upstart
svc_cmd = "%s" % self.svc_initscript svc_cmd = "%s" % self.svc_initscript
# In OpenRC, if a service crashed, we need to reset its status to
# stopped with the zap command, before we can start it back.
if self.svc_cmd.endswith('rc-service') and self.action == 'start' and self.crashed:
self.execute_command("%s zap" % svc_cmd, daemonize=True)
if self.action is not "restart": if self.action is not "restart":
if svc_cmd != '': if svc_cmd != '':
# upstart or systemd # upstart or systemd or OpenRC
rc_state, stdout, stderr = self.execute_command("%s %s %s" % (svc_cmd, self.action, arguments), daemonize=True) rc_state, stdout, stderr = self.execute_command("%s %s %s" % (svc_cmd, self.action, arguments), daemonize=True)
else: else:
# SysV # SysV
rc_state, stdout, stderr = self.execute_command("%s %s %s" % (self.action, self.name, arguments), daemonize=True) rc_state, stdout, stderr = self.execute_command("%s %s %s" % (self.action, self.name, arguments), daemonize=True)
elif self.svc_cmd.endswith('rc-service'):
# All services in OpenRC support restart.
rc_state, stdout, stderr = self.execute_command("%s %s %s" % (svc_cmd, self.action, arguments), daemonize=True)
else: else:
# not all services support restart. Do it the hard way. # In other systems, not all services support restart. Do it the hard way.
if svc_cmd != '': if svc_cmd != '':
# upstart or systemd # upstart or systemd
rc1, stdout1, stderr1 = self.execute_command("%s %s %s" % (svc_cmd, 'stop', arguments), daemonize=True) rc1, stdout1, stderr1 = self.execute_command("%s %s %s" % (svc_cmd, 'stop', arguments), daemonize=True)
@ -930,6 +982,7 @@ def main():
state = dict(choices=['running', 'started', 'stopped', 'restarted', 'reloaded']), state = dict(choices=['running', 'started', 'stopped', 'restarted', 'reloaded']),
pattern = dict(required=False, default=None), pattern = dict(required=False, default=None),
enabled = dict(choices=BOOLEANS, type='bool'), enabled = dict(choices=BOOLEANS, type='bool'),
runlevel = dict(required=False, default='default'),
arguments = dict(aliases=['args'], default=''), arguments = dict(aliases=['args'], default=''),
), ),
supports_check_mode=True supports_check_mode=True