class SystemServices(service.FunctionObject) : def __init__(self, object_path, service_object = None) : super().__init__(object_path, service_object) self._bus = SystemBus() self._systemd_manager = DBusInterface(self._bus.get_object( 'org.freedesktop.systemd1', '/org/freedesktop/systemd1' ), 'org.freedesktop.systemd1.Manager') @service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, in_signature="s") def enable(self, name): logger.verbose("{mod}: Request to enable service \"%s\"" % name) self._systemd_manager.EnableUnitFiles([name + '.service'], False, True) @service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, in_signature="s") def disable(self, name): logger.verbose("{mod}: Request to disable service \"%s\"" % name) self._systemd_manager.DisableUnitFiles([name + '.service'], False, True) ### @service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, in_signature="s") def reload(self, name) : logger.verbose("{mod}: Request to reload service \"%s\"" % name) self._systemd_manager.ReloadUnit(name + '.service', 'replace') @service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, in_signature="s") def start(self, name) : logger.verbose("{mod}: Request to start service \"%s\"" % name) self._systemd_manager.StartUnit(name + '.service', 'replace') @service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, in_signature="s") def stop(self, name) : logger.verbose("{mod}: Request to stop service \"%s\"" % name) self._systemd_manager.StopUnit(name + '.service', 'replace') @service.functionMethod(SYSTEM_SERVICE_METHODS_NAMESPACE, in_signature="s", out_signature="s") def getActiveState(self, name) : unit = DBusInterface( self._bus.get_object( 'org.freedesktop.systemd1', str(self._systemd_manager.LoadUnit(name + '.service')) ), 'org.freedesktop.systemd1.Unit' ) active_state = unit.Get( 'org.freedesktop.systemd1.Unit', 'ActiveState', dbus_interface='org.freedesktop.DBus.Properties' ) return active_state
class SystemdService(Debug): """Handles service request messages to systemd""" ACTUATOR_NAME = "SystemdService" @staticmethod def name(): """ @return: name of the module.""" return SystemdService.ACTUATOR_NAME def __init__(self): super(SystemdService, self).__init__() # Use d-bus to communicate with systemd # Described at: http://www.freedesktop.org/wiki/Software/systemd/dbus/ # Obtain an instance of d-bus to communicate with systemd self._bus = SystemBus() # Obtain a manager interface to d-bus for communications with systemd systemd = self._bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1') self._manager = Interface(systemd, dbus_interface='org.freedesktop.systemd1.Manager') # Subscribe to signal changes self._manager.Subscribe() def perform_request(self, jsonMsg): """Performs the service request""" self._check_debug(jsonMsg) # Parse out the service name and request to perform on it if jsonMsg.get("actuator_request_type").get("service_controller") is not None: self._service_name = jsonMsg.get("actuator_request_type").get("service_controller").get("service_name") self._service_request = jsonMsg.get("actuator_request_type").get("service_controller").get("service_request") else: self._service_name = jsonMsg.get("actuator_request_type").get("service_watchdog_controller").get("service_name") self._service_request = jsonMsg.get("actuator_request_type").get("service_watchdog_controller").get("service_request") self._log_debug("perform_request, service_name: %s, service_request: %s" % \ (self._service_name, self._service_request)) try: # Load the systemd unit for the service systemd_unit = self._manager.LoadUnit(self._service_name) # Get a proxy to systemd for accessing properties of units self._proxy = self._bus.get_object("org.freedesktop.systemd1", str(systemd_unit)) # The returned result of the desired action result = None if self._service_request == "restart": self._manager.RestartUnit(self._service_name, 'replace') # Ensure we get an "active" status and not "activating" max_wait = 0 while self._get_activestate() != "active": self._log_debug("status is still activating, pausing") time.sleep(1) max_wait += 1 if max_wait > 20: self._log_debug("maximum wait for service restart reached") break elif self._service_request == "start": self._manager.StartUnit(self._service_name, 'replace') elif self._service_request == "stop": self._manager.StopUnit(self._service_name, 'replace') elif self._service_request == "status": # Return the status below state = self._get_activestate() substate = self._get_active_substate() self._log_debug("perform_request, state: %s, substate: %s" % (str(state), str(substate))) return (self._service_name, state, substate) elif self._service_request == "enable": service_list = [] service_list.append(self._service_name) """EnableUnitFiles() function takes second argument as boolean. True will enable a service for runtime only(creates symlink in /run/.. directory) False will enable a service persistently(creates symlink in /etc/.. directory)""" bool_res, result = self._manager.EnableUnitFiles(service_list, False, True) self._log_debug("perform_request, bool: %s, result: %s" % (bool_res, result)) elif self._service_request == "disable": service_list = [] service_list.append(self._service_name) """DisableUnitFiles() function takes second argument as boolean. True will disable a service for runtime only(removes symlink from /run/.. directory) False will disable a service persistently(removes symlink from /etc/.. directory)""" result = self._manager.DisableUnitFiles(service_list, False) self._log_debug("perform_request, result: %s" % result) else: self._log_debug("perform_request, Unknown service request") return (self._service_name, "Unknown service request", None) except debus_exceptions.DBusException as error: logger.exception("DBus Exception: %r" % error) return (self._service_name, str(error), None) except Exception as ae: logger.exception("Exception: %r" % ae) return (self._service_name, str(ae), None) # Give the unit some time to finish starting/stopping to get final status time.sleep(5) # Get the current status of the process and return it back if no result if result is None: state = self._get_activestate() substate = self._get_active_substate() self._log_debug("perform_request, state: %s, substate: %s" % (str(state), str(substate))) return (self._service_name, state, substate) return (self._service_name, str(result), None) def _get_activestate(self): """"Returns the active state of the unit""" return self._proxy.Get('org.freedesktop.systemd1.Unit', 'ActiveState', dbus_interface='org.freedesktop.DBus.Properties') def _get_active_substate(self): """"Returns the active state of the unit""" return self._proxy.Get('org.freedesktop.systemd1.Unit', 'SubState', dbus_interface='org.freedesktop.DBus.Properties')
class SystemdService(Debug): """Handles service request messages to systemd""" ACTUATOR_NAME = "SystemdService" @staticmethod def name(): """ @return: name of the module.""" return SystemdService.ACTUATOR_NAME def __init__(self): super(SystemdService, self).__init__() # Use d-bus to communicate with systemd # Described at: http://www.freedesktop.org/wiki/Software/systemd/dbus/ # Obtain an instance of d-bus to communicate with systemd self._bus = SystemBus() # Obtain a manager interface to d-bus for communications with systemd systemd = self._bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1') self._manager = Interface( systemd, dbus_interface='org.freedesktop.systemd1.Manager') # Subscribe to signal changes self._manager.Subscribe() # create service cls obj. self._service = DbusServiceHandler() def perform_request(self, jsonMsg): """Performs the service request""" self._check_debug(jsonMsg) # Parse out the service name and request to perform on it if jsonMsg.get("actuator_request_type").get("service_controller") \ is not None: self._service_name = jsonMsg.get("actuator_request_type").\ get("service_controller").get("service_name") self._service_request = jsonMsg.get("actuator_request_type").\ get("service_controller").get("service_request") else: self._service_name = jsonMsg.get("actuator_request_type").\ get("service_watchdog_controller").get("service_name") self._service_request = jsonMsg.get("actuator_request_type").\ get("service_watchdog_controller").get("service_request") logger.debug("perform_request, service_name: %s, service_request: %s" % \ (self._service_name, self._service_request)) try: # Load the systemd unit for the service systemd_unit = self._manager.LoadUnit(self._service_name) # Get a proxy to systemd for accessing properties of units self._proxy = self._bus.get_object("org.freedesktop.systemd1", \ str(systemd_unit)) # The returned result of the desired action result = {} is_err_response = False if self._service_request in ['restart', 'start']: # Before restart/start the service, check service state. # If it is not active or activating then only process # restart/start request. service_state = self._service.get_state(self._service_name) state = service_state.state if state not in ['active', 'activating']: if self._service_request == "restart": self._service.restart(self._service_name) elif self._service_request == "start": self._service.start(self._service_name) # Ensure we get an "active" state and not "activating" service_state = self._service.get_state(self._service_name) state = service_state.state max_wait = 0 while state != "active": logger.debug( "%s status is activating, needs 'active' " "state after %s request has been processed, retrying" % (self._service_name, self._service_request)) time.sleep(1) max_wait += 1 if max_wait > 20: logger.debug("maximum wait - %s seconds, for " "service restart reached." % max_wait) break service_state = self._service.get_state( self._service_name) state = service_state.state else: is_err_response = True err_msg = ( "Can not process %s request, for %s, as service " "is already in %s state." % (self._service_request, self._service_name, state)) logger.error(err_msg) return (self._service_name, err_msg, is_err_response) elif self._service_request == "stop": self._service.stop(self._service_name) elif self._service_request == "status": # Return the status below service_status = self._service.get_state(self._service_name) # TODO: Use cortx.utils Service class methods for # enable/disable services. elif self._service_request == "enable": service_list = [] service_list.append(self._service_name) # EnableUnitFiles() function takes second argument as boolean. # 'True' will enable a service for runtime only(creates symlink # in /run/.. directory) 'False' will enable a service # persistently (creates symlink in /etc/.. directory) _, dbus_result = self._manager.EnableUnitFiles( service_list, False, True) res = parse_enable_disable_dbus_result(dbus_result) result.update(res) logger.debug("perform_request, result for enable request: " "result: %s" % (result)) elif self._service_request == "disable": service_list = [] service_list.append(self._service_name) # DisableUnitFiles() function takes second argument as boolean. # 'True' will disable a service for runtime only(removes symlink # from /run/.. directory) 'False' will disable a service # persistently(removes symlink from /etc/.. directory) dbus_result = self._manager.DisableUnitFiles( service_list, False) res = parse_enable_disable_dbus_result(dbus_result) result.update(res) logger.debug( "perform_request, result for disable request: %s" % result) else: logger.error("perform_request, Unknown service request - %s " "for service - %s" % (self._service_request, self._service_name)) is_err_response = True return (self._service_name, "Unknown service request", is_err_response) except debus_exceptions.DBusException as error: is_err_response = True logger.exception("DBus Exception: %r" % error) return (self._service_name, str(error), is_err_response) except Exception as ae: logger.exception("SystemD Exception: %r" % ae) is_err_response = True return (self._service_name, str(ae), is_err_response) # Give the unit some time to finish starting/stopping to get final status time.sleep(5) # Get the current status of the process and return it back: service_status = self._service.get_state(self._service_name) pid = service_status.pid state = service_status.state substate = service_status.substate status = self._service.is_enabled(self._service_name) uptime = get_service_uptime(self._service_name) # Parse dbus output to fetch command line path with args. command_line = service_status.command_line_path command_line_path_with_args = [] for field in list(command_line[0][1]): command_line_path_with_args.append(str(field)) result["pid"] = pid result["state"] = state result["substate"] = substate result["status"] = status result["uptime"] = uptime result["command_line_path"] = command_line_path_with_args logger.debug("perform_request, state: %s, substate: %s" % (str(state), str(substate))) return (self._service_name, result, is_err_response)