예제 #1
0
    def _shutdown_thread_func(self):
        """
        The thread function for the shutdown thread.

        It will signal the shutdown event and tell the Service Manager
        that it's state is stopped.
        """
        self._shutdown_event.release()
        self.current_state = (service_manager_messages.ServiceState(
            service_manager_messages.ServiceState.STOPPED))
예제 #2
0
 def _register_with_service_manager(self):
     """
     Perform registration with the Service Manager.
     """
     process_id = os.getpid()
     routed_message = \
         service_manager_messages.SvcMgrRegisterLocalServiceRoutedMessage(
             send_to='ServiceManager_' + self.node_name,
             service_guid_=self.service_guid,
             node_name_=self.node_name,
             service_name_=self.service_name,
             service_group_name_=self.service_group_name,
             reply_to_queue_=self.control_queue_name,
             process_id_=process_id
         )
     self.publish_routed_message(routed_message)
     self.current_state = (service_manager_messages.ServiceState(
         service_manager_messages.ServiceState.REGISTERED))
예제 #3
0
    def make_idle(self):
        """
        Notify the Service Manager that this service is idle.
        """
        LOGGER.debug('Managed Service Base: make idle!')
        process_id = os.getpid()

        log_message = ('Idled ' + str(process_id) + ' - ' +
                       self.instance_name + self.service_name +
                       ' ServiceGuid=')

        if self._standalone:
            log_message += '(Standalone)'
        if self.service_guid:
            log_message += self.service_guid

        self.trace_logger.log_info(log_message)
        self.publish_audit_entry('Idle')
        self._message_service.subscriber.stop_handling_messages()
        if self._work_subscriber:
            self._work_subscriber.stop_handling_messages()
        self.current_state = (service_manager_messages.ServiceState(
            service_manager_messages.ServiceState.IDLE))
예제 #4
0
    def go_live(self):
        """
        Notify the Service Manager that this service is live.
        """
        LOGGER.debug('Managed Service Base: go live!')
        process_id = os.getpid()

        log_message = 'Go Live ' + str(process_id) + ' - ' \
                      + self.instance_name \
                      + self.service_name \
                      + ' ServiceGuid='

        if self._standalone:
            log_message += '(Standalone)'
        if self.service_guid:
            log_message += self.service_guid

        self.trace_logger.log_info(log_message)
        self.publish_audit_entry('Live')
        self._message_service.subscriber.start_handling_messages()
        if self._work_subscriber:
            self._work_subscriber.start_handling_messages()
        self.current_state = (service_manager_messages.ServiceState(
            service_manager_messages.ServiceState.LIVE))
예제 #5
0
    def _control_message_callback(self, generic_message):  # pylint: disable=too-many-branches
        """
        The callback function invoked by the framework once a
        control message is received.

        :param generic_message: The response message.
        :type generic_message:
            systemlink.messagebus.generic_message.GenericMessage
        """
        message_name = generic_message.message_name
        LOGGER.debug('Received message: %s', message_name)

        if (message_name == service_manager_messages.
                SvcMgrSendServiceStatusRequestBroadcast.__name__):
            self._send_service_status_broadcast()  # pylint: disable=protected-access
        elif (message_name == configuration_messages.
              ConfigurationGetSectionKeyValuesResponse.__name__):
            LOGGER.debug('ConfigurationGetSectionKeyValuesResponse!')
            response = (
                configuration_messages.ConfigurationGetSectionKeyValuesResponse
                .from_message(generic_message))
            error = self._try_set_configuration(  # pylint: disable=protected-access
                response.key_values)
            if error.has_value():
                msg = str(error)
                LOGGER.error(msg)
                self.trace_logger.log_error(msg, skip_if_has_log_handler=True)
                self.current_state = (service_manager_messages.ServiceState(
                    service_manager_messages.ServiceState.ERROR))
            else:
                LOGGER.debug('No Error.')
                self._configured = True  # pylint: disable=protected-access
                if self._need_to_go_live:  # pylint: disable=protected-access
                    self.go_live()
        elif message_name == service_manager_messages.ServiceGoLiveRoutedMessage.__name__:
            LOGGER.debug('ServiceGoLiveRoutedMessage')
            service_go_live_routed_message = (
                service_manager_messages.ServiceGoLiveRoutedMessage.
                from_message(send_to='', message=generic_message))
            if not self.service_guid:
                self.service_guid = service_go_live_routed_message.service_guid
            elif (self.service_guid !=
                  service_go_live_routed_message.service_guid):
                log_message = 'Go live request with mis-matched GUID: '
                log_message += self.service_guid
                log_message += " "
                log_message += service_go_live_routed_message.service_guid

                LOGGER.error(log_message)
                self.trace_logger.log_error(log_message,
                                            skip_if_has_log_handler=True)
            if self.current_state.value \
                    != service_manager_messages.ServiceState.ERROR:
                if self._configured:  # pylint: disable=protected-access
                    self.go_live()
                else:
                    self._need_to_go_live = True  # pylint: disable=protected-access
        elif message_name == service_manager_messages.ServiceMakeIdleRoutedMessage.__name__:
            if (self.current_state !=
                    service_manager_messages.ServiceState.ERROR):
                self._need_to_go_live = False  # pylint: disable=protected-access
                self.make_idle()
        elif message_name == service_manager_messages.ServiceShutdownRoutedMessage.__name__:
            self._start_shutdown_thread()  # pylint: disable=protected-access
        else:
            log_message = 'Unhandled Control Message | '
            log_message += generic_message.message_name
            LOGGER.error(log_message)
            self.trace_logger.log_error(log_message,
                                        skip_if_has_log_handler=True)
예제 #6
0
    def __init__(self,
                 service_name,
                 shutdown_event,
                 managed_service_builder=None):  # pylint: disable=too-many-branches,too-many-statements
        """
        :param service_name: The name of the message service. Ignored
            if ``managed_service_builder`` is not ``None``. In this
             case, ``service_name`` may be ``None``.
        :type service_name: str or None
        :param shutdown_event: A :class`threading.Semaphore` instance
            that is released when the Skyline Service Manager requires
            the service to shut down.
        :type shutdown_event: threading.Semaphore
        :param message_service_builder: A
            :class:`systemlink.messagebus.managed_service_builder.ManagedServiceBuilder`
            object used in the construction of this object. May be
            ``None``, in which case ``service_name`` must be set.
        :type message_service_builder:
            systemlink.messagebus.managed_service_builder.ManagedServiceBuilder
            or None
        """
        LOGGER.debug('ManagedServiceBase constructor!')

        if managed_service_builder is None:
            managed_service_builder = ManagedServiceBuilder(service_name)

        if shutdown_event is None:
            error_info = 'Shutdown event cannot be None'
            raise SystemLinkException.from_name('Skyline.Exception',
                                                info=error_info)

        self._closing = False
        self._work_subscriber = None
        self._control_subscriber = None
        self._node_name = ''
        self._service_name = None
        self._instance_name = None
        self._shutdown_thread = None
        self._old_stdout = None
        self._old_stderr = None
        self._devnull_fp = None

        if (sys.stdout is None or sys.stderr is None
                or sys.stdout.encoding != 'utf-8'
                or sys.stderr.encoding != 'utf-8'):
            # We will hit this case when the stdout/stderr pipes
            # are closed before creating this process. This is the
            # current behavior of Service Manager. In Python 3.5.x,
            # this will result in `sys.stdout` and `sys.stderr` being
            # None. In Python 3.6.x, this will result in `sys.stdout`
            # and `sys.stderr` being created by Python, but imperfectly
            # such that the encoding is the system encoding (typically
            # 'cp1252') instead of 'utf-8' which will still cause
            # problems. This should be fixed in Python 3.7.x in which
            # case it should create pipes with an encoding of 'utf-8'.
            # Once Python 3.7.x is the minimum supported version, this
            # code may be removed.
            self._old_stdout = sys.stdout
            self._old_stderr = sys.stderr
            self._devnull_fp = open(os.devnull, 'w', encoding='utf-8')
            sys.stdout = self._devnull_fp
            sys.stderr = self._devnull_fp

        self._service_name = managed_service_builder.service_name
        self._status = service_manager_messages.ServiceState(
            service_manager_messages.ServiceState.STARTING)
        self._standalone = managed_service_builder.standalone_property

        if not managed_service_builder.instance_name:
            self._instance_name = self.get_unique_instance_name()
        else:
            self._instance_name = managed_service_builder.instance_name

        self._no_configuration_request = managed_service_builder.no_configuration_request

        self._service_guid = os.environ.get(SERVICE_GUID)
        if not self._service_guid:
            self._service_guid = ''

        self._service_group_name = os.environ.get(SERVICE_GROUP_NAME)
        if not self._service_group_name:
            self._service_group_name = DEFAULT_SERVICE_GROUP_NAME

        if not self._standalone:
            message_subscriber_builder = MessageSubscriberBuilder(
                self.control_queue_name)
            message_subscriber_builder.callback = self._control_message_callback
            message_subscriber_builder.register_default_binding = True
            message_subscriber_builder.auto_start_consumers = False
            self._control_subscriber = MessageSubscriber(
                message_subscriber_builder)
            self._control_subscriber.register_callback(
                service_manager_messages.
                SvcMgrSendServiceStatusRequestBroadcast,
                self._control_message_callback)
            self._control_subscriber.register_callback(
                configuration_messages.
                ConfigurationGetSectionKeyValuesResponse,
                self._control_message_callback)

        if not managed_service_builder.no_work_subscriber:
            if managed_service_builder.work_subscriber_builder:
                work_builder = managed_service_builder.work_subscriber_builder
            else:
                work_builder = MessageSubscriberBuilder(self._service_name)

            if work_builder.callback is None:
                work_builder.callback = self._receive_message
            work_builder.auto_start_consumers = False
            self._work_subscriber = MessageSubscriber(work_builder)

        if managed_service_builder.instance_subscriber_builder is not None:
            instance_builder = managed_service_builder.instance_subscriber_builder
        else:
            instance_builder = MessageSubscriberBuilder(self.get_full_name())

        instance_builder.register_default_binding = True
        instance_builder.auto_start_consumers = False

        message_service_builder = MessageServiceBuilder(self._service_name)
        message_service_builder.instance_name = self._instance_name
        message_service_builder.subscriber_builder = instance_builder

        self._message_service = MessageService(
            message_service_builder=message_service_builder)
        self._message_service.instance_name = self._instance_name

        self._process_logger = ProcessLogger(
            self.get_full_name(), None,
            self._message_service.publisher.publish_message_callback,
            self._message_service.register_callback)

        log_to_trace_logger = managed_service_builder.log_to_trace_logger
        self._message_service.trace_logger = (
            self._process_logger.make_trace_logger(
                self._service_name, log_to_trace_logger=log_to_trace_logger))

        if self._control_subscriber is not None:
            self._control_subscriber.trace_logger = (
                self._process_logger.make_trace_logger(
                    'Control', self._message_service.trace_logger))

        if self._work_subscriber is not None:
            self._work_subscriber.trace_logger = self._message_service.trace_logger

        self._trace_unhandled_message = self.trace_logger.make_trace_point(
            'UnhandledMessage')

        self._configured = False
        self._need_to_go_live = False
        self._trace_unhandled_message = None
        self._shutdown_event = shutdown_event
        self._shutdown_thread = None