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')
Esempio n. 3
0
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)