Commit b68a751b authored by Devaev Maxim's avatar Devaev Maxim

Dynamic add and remove system services by inotify events on /etc/rc.d/init.d

parent cd3faee5
......@@ -2,7 +2,9 @@
import os
import stat
import re
import pyinotify
from settingsd import config
from settingsd import service
......@@ -16,8 +18,13 @@ from settingsd import validators
##### Private constants #####
SERVICE_NAME = "system_services"
SYSTEM_SERVICES_SHARED_NAME = "system_services"
SYSTEM_SERVICES_OBJECT_NAME = "system_services"
SYSTEM_SERVICE_METHODS_NAMESPACE = "systemService"
RUNLEVELS = "0123456"
......@@ -75,8 +82,8 @@ class SystemService(service.FunctionObject) :
@service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, out_signature="i")
def stop(self) :
return tools.execProcess("%s stop" % (os.path.join(config.value(SERVICE_NAME, "initd_dir_path"), self.systemServiceName())))[2]
logger.verbose("{mod}: Request to stop service \"%s\"" % (self.systemServiceName()))
return tools.execProcess("%s stop" % (os.path.join(config.value(SERVICE_NAME, "initd_dir_path"), self.systemServiceName())))[2]
@service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, out_signature="i")
def status(self) :
......@@ -91,7 +98,7 @@ class SystemService(service.FunctionObject) :
###
def setLevels(self, levels, enabled_flag) :
levels = self.validateLevels(levels)
levels = self.validLevels(levels)
logger.verbose("Request to %s service \"%s\" on runlevels \"%s\"" % ( ( "enable" if enabled_flag else "disable" ),
self.systemServiceName(), ( levels if levels != None else "default" ) ))
......@@ -108,7 +115,7 @@ class SystemService(service.FunctionObject) :
###
def validateLevels(self, levels) :
def validLevels(self, levels) :
if type(levels).__name__ in ("str", "String") :
if len(levels) == 0 :
levels = None
......@@ -122,34 +129,57 @@ class SystemService(service.FunctionObject) :
return levels
class SystemServices(service.FunctionObject) :
@service.functionSignal(SYSTEM_SERVICE_METHODS_NAMESPACE)
def servicesChanged(self) :
pass
##### Public classes #####
class Service(service.Service) :
class Service(service.Service, pyinotify.ThreadedNotifier) :
def __init__(self) :
service.Service.__init__(self)
self.__watch_manager = pyinotify.WatchManager()
pyinotify.ThreadedNotifier.__init__(self, self.__watch_manager, type("EventsHandler", (pyinotify.ProcessEvent,),
{ "process_IN_CREATE" : self.inotifyEvent, "process_IN_DELETE" : self.inotifyEvent })())
#####
self.__system_services = SystemServices(SYSTEM_SERVICES_OBJECT_NAME, self)
### Public ###
def initService(self) :
proc_args = "%s --list" % (config.value(SERVICE_NAME, "chkconfig_prog_path"))
(proc_stdout, proc_sterr, proc_returncode) = tools.execProcess(proc_args)
shared.Functions.addShared(SYSTEM_SERVICES_SHARED_NAME)
if proc_returncode != 0 :
raise tools.SubprocessFailure("Error while execute \"%s\"\nStdout: %s\nStderr: %s\nReturn code: %d" % (
proc_args, proc_stdout.strip(), proc_stderr.strip(), proc_returncode ))
initd_dir_path = config.value(SERVICE_NAME, "initd_dir_path")
logger.verbose("{mod}: First services requset...")
system_services_shared = shared.Functions.shared(SYSTEM_SERVICES_SHARED_NAME)
system_service_count = 0
shared.Functions.addShared(SERVICE_NAME)
for system_service_record in proc_stdout.split("\n") :
system_service_record_list = re.split(r"\s+", system_service_record)
if len(system_service_record_list) != len(RUNLEVELS) + 1 :
continue
system_service_name = system_service_record_list[0]
dbus_system_service_name = re.sub(r"-|\.", "_", system_service_name)
shared.Functions.shared(SERVICE_NAME).addSharedObject(dbus_system_service_name, SystemService(system_service_name,
dbus_tools.joinPath(SERVICE_NAME, dbus_system_service_name), self))
system_service_count += 1
for system_service_name in os.listdir(initd_dir_path) :
st_mode = os.stat(os.path.join(initd_dir_path, system_service_name)).st_mode
if st_mode & stat.S_IEXEC and st_mode & stat.S_IFREG :
dbus_system_service_name = re.sub(r"-|\.", "_", system_service_name)
system_services_shared.addSharedObject(dbus_system_service_name, SystemService(system_service_name,
dbus_tools.joinPath(SERVICE_NAME, dbus_system_service_name), self))
system_service_count += 1
logger.verbose("{mod}: Added %d system services" % (system_service_count))
###
self.__watch_manager.add_watch(initd_dir_path, pyinotify.IN_DELETE|pyinotify.IN_CREATE, rec=True)
self.start()
logger.verbose("{mod}: Start polling inotify events for \"%s\"" % (initd_dir_path))
def closeService(self) :
initd_dir_path = config.value(SERVICE_NAME, "initd_dir_path")
self.__watch_manager.rm_watch(self.__watch_manager.get_wd(initd_dir_path))
self.stop()
logger.verbose("{mod}: Stop polling inotify events for \"%s\"" % (initd_dir_path))
###
@classmethod
......@@ -163,3 +193,23 @@ class Service(service.Service) :
(SERVICE_NAME, "chkconfig_prog_path", "/sbin/chkconfig", str)
]
### Private ###
def inotifyEvent(self, event) :
if event.dir :
return
dbus_system_service_name = re.sub(r"-|\.", "_", event.name)
system_services_shared = shared.Functions.shared(SERVICE_NAME)
if event.maskname == "IN_CREATE" :
system_services_shared.addSharedObject(dbus_system_service_name, SystemService(event.name,
dbus_tools.joinPath(SERVICE_NAME, dbus_system_service_name), self))
logger.verbose("{mod}: Added system service \"%s\"" % (dbus_system_service_name))
elif event.maskname == "IN_DELETE" :
system_services_shared.sharedObject(dbus_system_service_name).removeFromConnection()
system_services_shared.removeSharedObject(dbus_system_service_name)
logger.verbose("{mod}: Removed system service \"%s\"" % (dbus_system_service_name))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment