コード例 #1
0
ファイル: iccp.py プロジェクト: FirebirdSQL/saturnin
    def from_zmsg(self, zmsg: TZMQMessage) -> None:
        """Populate message data from sequence of ZMQ data frames.

        Arguments:
            zmsg: Sequence of frames that should be deserialized.

        Raises:
            InvalidMessageError: If message is not a valid protocol message.
        """
        try:
            self.msg_type = MsgType(unpack('!H', zmsg[0])[0])
            if self.msg_type is MsgType.READY:
                proto = protobuf.create_message(PROTO_PEER, zmsg[1])
                self.peer = PeerDescriptor.from_proto(proto)
                proto = protobuf.create_message(protobuf.PROTO_STRUCT, zmsg[2])
                self.endpoints = {}
                for k, v in protobuf.struct2dict(proto).items():
                    for i in range(len(v)):
                        v[i] = ZMQAddress(v[i])
                    self.endpoints[k] = v
            elif self.msg_type is MsgType.ERROR:
                self.error = zmsg[1].decode('utf8')
            elif self.msg_type is MsgType.FINISHED:
                self.outcome = Outcome(zmsg[1].decode())
                self.details = [
                    v.decode('utf8', errors='replace') for v in zmsg[2:]
                ]
            elif self.msg_type is MsgType.REQUEST:
                self.request = Request(zmsg[1])
                if self.request is Request.CONFIGURE:
                    self.config = protobuf.create_message(
                        PROTO_CONFIG, zmsg[2])
        except Exception as exc:
            raise InvalidMessageError("Invalid message") from exc
コード例 #2
0
    def from_zmsg(self, zmsg: TZMQMessage) -> None:
        """Populate message data from sequence of ZMQ data frames.

        Arguments:
            zmsg: Sequence of frames that should be deserialized.

        Raises:
            InvalidMessageError: If message is not a valid protocol message.
        """
        try:
            control_byte, flags, self.type_data = unpack(
                HEADER_FMT, zmsg.pop(0))
            self.msg_type = MsgType(control_byte >> 3)
            self.flags = MsgFlag(flags)
            if self.msg_type is MsgType.OPEN:
                self.data_frame = create_message(PROTO_OPEN)
                self.data_frame.ParseFromString(zmsg.pop(0))
            elif self.msg_type is MsgType.DATA:
                self.data_frame = zmsg.pop(0) if zmsg else None
            elif self.msg_type is MsgType.CLOSE:
                self.type_data = ErrorCode(self.type_data)
                self.data_frame = []
                while zmsg:
                    err = create_message(PROTO_ERROR)
                    err.ParseFromString(zmsg.pop(0))
                    self.data_frame.append(err)
        except Exception as exc:
            raise InvalidMessageError("Invalid message") from exc
コード例 #3
0
ファイル: service.py プロジェクト: FirebirdSQL/saturnin-core
    def handle_input_accept_client(self, channel: Channel,
                                   session: FBDPSession) -> None:
        """Event handler executed when client connects to INPUT data pipe via OPEN message.

        Arguments:
            channel: Channel associated with data pipe.
            session: Session associated with client.

        The session attributes `data_pipe`, `pipe_socket`, `data_format` and `params`
        contain information sent by client, and the event handler validates the request.

        If request should be rejected, it raises the `StopError` exception with `code`
        attribute containing the `ErrorCode` to be returned in CLOSE message.
        """
        super().handle_input_accept_client(channel, session)
        fmt = cast(MIME, session.data_format)
        if fmt.mime_type != MIME_TYPE_PROTO:
            raise StopError(
                f"MIME type '{fmt.mime_type}' is not a valid input format",
                code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
        proto_class = fmt.params.get('type')
        if self.data:
            if self.data.DESCRIPTOR.full_name != proto_class:
                raise StopError(
                    f"Protobuf message type '{proto_class}' not allowed",
                    code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
        else:
            if not is_msg_registered(proto_class):
                raise StopError(
                    f"Unknown protobuf message type '{proto_class}'",
                    code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
            self.data = create_message(proto_class)
コード例 #4
0
ファイル: service.py プロジェクト: FirebirdSQL/saturnin-core
 def initialize(self, config: ProtoFilterConfig) -> None:
     """Verify configuration and assemble component structural parts.
     """
     super().initialize(config)
     self.log_context = 'main'
     #
     self.include_func: Callable = None
     self.exclude_func: Callable = None
     self.data: Any = None
     self.fmt: MIME = None
     #
     if config.include_expr.value is not None:
         self.include_func = config.include_expr.value.get_callable('data',
                                                                    {'datetime': datetime,})
     if config.include_func.value is not None:
         self.include_func = config.include_func.value
     if config.exclude_expr.value is not None:
         self.exclude_func = config.exclude_expr.value.get_callable('data',
                                                                    {'datetime': datetime,})
     if config.exclude_func.value is not None:
         self.exclude_func = config.exclude_func.value
     #
     self.fmt = config.input_pipe_format.value
     proto_class = self.fmt.params.get('type')
     if not is_msg_registered(proto_class):
         raise StopError(f"Unknown protobuf message type '{proto_class}'",
                         code = ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
     self.data = create_message(proto_class)
コード例 #5
0
 def test_messages(self):
     register_decriptor(DESCRIPTOR)
     #
     msg = create_message(STATE_MSG_TYPE_NAME)
     self.assertIsNotNone(msg)
     self.assertEqual(get_enum_field_type(msg, 'test'), ENUM_TYPE_NAME)
     #
     msg.name = 'State.NAME'
     msg.test = 1
     # Errors
     with self.assertRaises(KeyError) as cm:
         create_message('NOT_REGISTERED')
     self.assertEqual(cm.exception.args, ("Unregistered protobuf message 'NOT_REGISTERED'",))
     with self.assertRaises(KeyError) as cm:
         get_enum_field_type(msg, 'BAD_FIELD')
     self.assertEqual(cm.exception.args, ("Message does not have field 'BAD_FIELD'",))
コード例 #6
0
ファイル: service.py プロジェクト: FirebirdSQL/saturnin-core
 def initialize(self, config: ProtoPrinterConfig) -> None:
     """Verify configuration and assemble component structural parts.
     """
     super().initialize(config)
     self.log_context = 'main'
     #
     self.transform_func: Callable[[Any], str] = None
     self.fmt: str = None
     self.data: Any = None
     self.charset = 'ascii'
     self.errors = 'strict'
     self.utils = TransformationUtilities()
     #
     if config.input_pipe_format.value is not None:
         self.data = create_message(
             config.input_pipe_format.value.params.get('type'))
     #
     if config.template.value is not None:
         self.transform_func = self.__format_data
         self.fmt = 'f"""' + config.template.value + '"""'
     else:
         self.transform_func = config.func.value
     #
     if self.output_pipe_mode is SocketMode.CONNECT:
         self.output_protocol.on_init_session = self.handle_init_session
コード例 #7
0
 def initialize(self, config: FbTraceParserConfig) -> None:
     """Verify configuration and assemble component structural parts.
     """
     super().initialize(config)
     self.log_context = 'main'
     #
     self.proto = create_message(TRACE_PROTO)
     self.entry_buf: List[str] = []
     self.parser: TraceParser = TraceParser()
     self.input_lefover = None
     #
     self.data_map: Dict = {
         AttachmentInfo: self.store_att_info,
         TransactionInfo: self.store_tra_info,
         ServiceInfo: self.store_svc_info,
         SQLInfo: self.store_sql_info,
         ParamSet: self.store_param_set,
         EventTraceInit: self.store_trace_init,
         EventTraceSuspend: self.store_trace_suspend,
         EventTraceFinish: self.store_trace_finish,
         EventCreate: self.store_db_create,
         EventDrop: self.store_db_drop,
         EventAttach: self.store_db_attach,
         EventDetach: self.store_db_detach,
         EventTransactionStart: self.store_tra_start,
         EventCommit: self.store_commit,
         EventRollback: self.store_rollback,
         EventCommitRetaining: self.store_commit_retain,
         EventRollbackRetaining: self.store_rollback_retain,
         EventPrepareStatement: self.store_stm_prepare,
         EventStatementStart: self.store_stm_start,
         EventStatementFinish: self.store_smt_finish,
         EventFreeStatement: self.store_stm_free,
         EventCloseCursor: self.store_cursor_close,
         EventTriggerStart: self.store_trigger_start,
         EventTriggerFinish: self.store_trigger_finish,
         EventProcedureStart: self.store_proc_start,
         EventProcedureFinish: self.store_proc_finish,
         EventServiceAttach: self.store_svc_attach,
         EventServiceDetach: self.store_svc_detach,
         EventServiceStart: self.store_svc_start,
         EventServiceQuery: self.store_svc_query,
         EventSetContext: self.store_ctx_set,
         EventError: self.store_error,
         EventWarning: self.store_warning,
         EventServiceError: self.store_svc_error,
         EventServiceWarning: self.store_svc_warning,
         EventSweepStart: self.store_swp_start,
         EventSweepProgress: self.store_swp_progress,
         EventSweepFinish: self.store_swp_finish,
         EventSweepFailed: self.store_swp_fail,
         EventBLRCompile: self.store_blr_compile,
         EventBLRExecute: self.store_blr_exec,
         EventDYNExecute: self.store_dyn_exec,
         EventUnknown: self.store_unknown
     }
     #
     if self.input_pipe_mode is SocketMode.CONNECT:
         self.input_protocol.on_init_session = self.handle_init_session
コード例 #8
0
ファイル: iccp.py プロジェクト: FirebirdSQL/saturnin
    def validate(self, zmsg: TZMQMessage) -> None:
        """Verifies that sequence of ZMQ data frames is a valid protocol message.

        If this validation passes without exception, then `.parse()` of the same message
        must be successful as well.

        Arguments:
            zmsg:   ZeroMQ multipart message.

        Raises:
            InvalidMessageError: If ZMQ message is not a valid protocol message.
        """
        if not zmsg:
            raise InvalidMessageError("Empty message")
        try:
            msg_type = MsgType(unpack('!H', zmsg[0]))
        except Exception as exc:
            raise InvalidMessageError("Invalid message type") from exc
        if msg_type is MsgType.READY:
            try:
                PeerDescriptor.from_proto(
                    protobuf.create_message(PROTO_PEER, zmsg[1]))
            except Exception as exc:
                raise InvalidMessageError(
                    "Invalid data: peer descriptor") from exc
            try:
                protobuf.create_message(protobuf.PROTO_STRUCT, zmsg[2])
            except Exception as exc:
                raise InvalidMessageError("Invalid data: endpoints") from exc
        elif msg_type is MsgType.ERROR:
            try:
                zmsg[1].decode('utf8')
            except Exception as exc:
                raise InvalidMessageError(
                    "Invalid data: error message") from exc
        elif msg_type is MsgType.REQUEST:
            try:
                req = Request(zmsg[1])
            except Exception as exc:
                raise InvalidMessageError("Invalid request code") from exc
            if req is Request.CONFIGURE:
                try:
                    protobuf.create_message(PROTO_CONFIG, zmsg[2])
                except Exception as exc:
                    raise InvalidMessageError("Invalid data: config") from exc
コード例 #9
0
 def note_exception(self, exc: Exception):
     """Store information from exception into CLOSE Message.
     """
     assert self.msg_type is MsgType.CLOSE
     errdesc = create_message(PROTO_ERROR)
     if hasattr(exc, 'code'):
         errdesc.code = getattr(exc, 'code')
     errdesc.description = str(exc)
     self.data_frame.append(errdesc)
コード例 #10
0
ファイル: iccp.py プロジェクト: FirebirdSQL/saturnin
 def request_config_msg(self, config: Config = None) -> ICCPMessage:
     """Returns REQUEST/CONFIG control message.
     """
     msg: ICCPMessage = self.message_factory()
     msg.msg_type = MsgType.REQUEST
     msg.request = Request.CONFIGURE
     msg.config = protobuf.create_message(PROTO_CONFIG)
     if config:
         config.save_proto(msg.config)
     return msg
コード例 #11
0
 def copy(self) -> Message:
     """Returns copy of the message.
     """
     msg: FBDPMessage = self.__class__()
     msg.msg_type = self.msg_type
     msg.flags = self.flags
     msg.type_data = self.type_data
     if self.msg_type is MsgType.OPEN:
         msg.data_frame = create_message(PROTO_OPEN)
         msg.data_frame.CopyFrom(self.data_frame)
     elif self.msg_type is MsgType.CLOSE:
         msg.data_frame = []
         for frame in self.data_frame:
             err = create_message(PROTO_ERROR)
             err.CopyFrom(frame)
             msg.data_frame.append(err)
     else:
         msg.data_frame = self.data_frame
     return msg
コード例 #12
0
 def as_proto(self) -> Any:
     """Returns `firebird.butler.PeerIdentification` protobuf message initialized
     from instance data.
     """
     msg = create_message(PROTO_PEER)
     msg.uid = self.uid.bytes
     msg.pid = self.pid
     msg.host = self.host
     if self.supplement is not None:
         sup = msg.supplement.add()
         sup.Pack(dict2struct(self.supplement))
     return msg
コード例 #13
0
ファイル: service.py プロジェクト: FirebirdSQL/saturnin-core
 def initialize(self, config: FbLogParserConfig) -> None:
     """Verify configuration and assemble component structural parts.
     """
     super().initialize(config)
     self.log_context = 'main'
     #
     self.proto = create_message(LOG_PROTO)
     self.entry_buf: List[str] = []
     self.parser: LogParser = LogParser()
     self.input_lefover = None
     #
     if self.input_pipe_mode is SocketMode.CONNECT:
         self.input_protocol.on_init_session = self.handle_init_session
コード例 #14
0
 def handle_init_session(self, channel: Channel,
                         session: FBDPSession) -> None:
     """Event executed from `send_open()` to set additional information to newly
     created session instance.
     """
     # cache attributes
     if cast(MIME, session.data_format).mime_type == MIME_TYPE_TEXT:
         session.charset = cast(MIME, session.data_format).params.get(
             'charset', 'ascii')
         session.errors = cast(MIME, session.data_format).params.get(
             'errors', 'strict')
     elif cast(MIME, session.data_format).mime_type == MIME_TYPE_PROTO:
         session.proto = create_message(
             cast(MIME, session.data_format).params.get('type'))
コード例 #15
0
 def from_proto(cls, proto: Any) -> PeerDescriptor:
     """Creates new PeerDescriptor from `firebird.butler.PeerIdentification` protobuf
     message.
     """
     if proto.DESCRIPTOR.full_name != PROTO_PEER:
         raise ValueError("PeerIdentification protobuf message required")
     data = None
     if proto.supplement:
         for i in proto.supplement:
             if i.TypeName() == PROTO_STRUCT:
                 s = create_message(PROTO_STRUCT)
                 i.Unpack(s)
                 data = struct2dict(s)
                 break
     return cls(uuid.UUID(bytes=proto.uid), proto.pid, proto.host, data)
コード例 #16
0
ファイル: iccp.py プロジェクト: FirebirdSQL/saturnin
 def copy(self) -> Message:
     """Returns copy of the message.
     """
     msg = self.__class__()
     msg.msg_type = self.msg_type
     if self.msg_type is MsgType.READY:
         msg.peer = self.peer.copy()
         msg.endpoints = self.endpoints.copy()
     elif self.msg_type is MsgType.ERROR:
         msg.error = self.error
     elif self.msg_type is MsgType.REQUEST:
         msg.request = self.request
         if self.request is Request.CONFIGURE:
             msg.config = protobuf.create_message(PROTO_CONFIG)
             msg.config.CopyFrom(self.config)
     return msg
コード例 #17
0
    def handle_accept_client(self, channel: Channel,
                             session: FBDPSession) -> None:
        """Event handler executed when client connects to the data pipe via OPEN message.

        Arguments:
            channel: Channel associated with data pipe.
            session: Session associated with client.

        The session attributes `data_pipe`, `pipe_socket`, `data_format` and `params`
        contain information sent by client, and the event handler validates the request.

        If request should be rejected, it raises the `StopError` exception with `code`
        attribute containing the `ErrorCode` to be returned in CLOSE message.
        """
        super().handle_accept_client(channel, session)
        if cast(MIME, session.data_format).mime_type not in SUPPORTED_MIME:
            raise StopError(
                f"MIME type '{cast(MIME, session.data_format).mime_type}' is not a valid input format",
                code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
        if cast(MIME, session.data_format).mime_type == MIME_TYPE_TEXT:
            for param in cast(MIME, session.data_format).params.keys():
                if param not in ('charset', 'errors'):
                    raise StopError(f"Unknown MIME parameter '{param}'",
                                    code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
            # cache attributes
            session.charset = cast(MIME, session.data_format).params.get(
                'charset', 'ascii')
            session.errors = cast(MIME, session.data_format).params.get(
                'errors', 'strict')
        elif cast(MIME, session.data_format).mime_type == MIME_TYPE_PROTO:
            for param in cast(MIME, session.data_format).params.keys():
                if param != 'type':
                    raise StopError(f"Unknown MIME parameter '{param}'",
                                    code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
            proto_class = cast(MIME, session.data_format).params.get('type')
            if not is_msg_registered(proto_class):
                raise StopError(
                    f"Unknown protobuf message type '{proto_class}'",
                    code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
            # cache attributes
            session.proto = create_message(proto_class)
        # Client reqest is ok, we'll open the file we are configured to work with.
        self._open_file()
コード例 #18
0
ファイル: service.py プロジェクト: FirebirdSQL/saturnin-core
 def initialize(self, config: ProtoAggregatorConfig) -> None:
     """Verify configuration and assemble component structural parts.
     """
     super().initialize(config)
     self.log_context = 'main'
     #
     self.data: Any = None
     self.group_by: List[GroupByItem] = []
     self.agg_defs: List[str] = []
     self.aggregates: Dict[Tuple, AggregateItem] = {}
     #
     for item in config.group_by.value:
         self.group_by.append(GroupByItem(item))
     for item in config.aggregate.value:
         self.agg_defs.append(item)
     #
     proto_class = config.input_pipe_format.value.params.get('type')
     if not is_msg_registered(proto_class):
         raise StopError(f"Unknown protobuf message type '{proto_class}'",
                         code=ErrorCode.DATA_FORMAT_NOT_SUPPORTED)
     self.data = create_message(proto_class)
コード例 #19
0
    def create_message_for(self,
                           msg_type: MsgType,
                           type_data: int = 0,
                           flags: MsgFlag = None) -> FBDPMessage:
        """Returns message of particular FBDP message type.

        Arguments:
            msg_type:  Type of message to be created.
            type_data: Message control data.
            flags:     Message flags.
        """
        msg: FBDPMessage = self.message_factory()
        msg.msg_type = msg_type
        msg.type_data = type_data
        if flags is not None:
            msg.flags = flags
        if msg.msg_type is MsgType.OPEN:
            msg.data_frame = create_message(PROTO_OPEN)
        elif msg.msg_type is MsgType.CLOSE:
            msg.data_frame = []
        return msg
コード例 #20
0
ファイル: service.py プロジェクト: FirebirdSQL/saturnin-core
    def finish_input_processing(self, channel: Channel, session: FBDPSession,
                                code: ErrorCode) -> None:
        """Called when input pipe is closed while output pipe will remain open.

        When code is ErrorCode.OK, the input was closed normally. Otherwise it indicates
        the type of problem that caused the input to be closed.

        Arguments:
            channel: Channel associated with data pipe.
            session: Session associated with peer.
            code:    Input pipe closing ErrorCode.
        """
        output_data = create_message(AGGREGATE_PROTO)
        batch = []
        for key, items in self.aggregates.items():
            output_data.Clear()
            i = 0
            for grp in self.group_by:
                output_data.data[grp.name] = key[i]
                i += 1
            for item in items:
                output_data.data[item.name] = item.get_result()
            batch.append(output_data.SerializeToString())
        self.store_batch_output(batch)
コード例 #21
0
    def validate(self, zmsg: TZMQMessage) -> None:
        """Verifies that sequence of ZMQ data frames is a valid protocol message.

        If this validation passes without exception, then `.parse()` of the same message
        must be successful as well.

        Arguments:
            zmsg:   ZeroMQ multipart message.

        Raises:
            InvalidMessageError: If ZMQ message is not a valid protocol message.
        """
        if not zmsg:
            raise InvalidMessageError("Empty message")
        fbdp_header = zmsg[0]
        if len(fbdp_header) != 8:
            raise InvalidMessageError("Message header must be 8 bytes long")
        try:
            fourcc, control_byte, flags, _ = unpack(HEADER_FMT_FULL,
                                                    fbdp_header)
        except Exception as exp:
            raise InvalidMessageError("Invalid control frame") from exp
        if fourcc != FOURCC:
            raise InvalidMessageError("Invalid FourCC")
        if (control_byte & VERSION_MASK) != self.REVISION:
            raise InvalidMessageError("Invalid protocol version")
        if (flags | 3) > 3:
            raise InvalidMessageError("Invalid flags")
        try:
            message_type = MsgType(control_byte >> 3)
        except ValueError:
            raise InvalidMessageError(
                f"Illegal message type {control_byte >> 3}")
        if message_type is MsgType.OPEN:
            if len(zmsg) != 2:
                raise InvalidMessageError("OPEN message must have a dataframe")
            try:
                fpb = create_message(PROTO_OPEN)
                fpb.ParseFromString(zmsg[1])
                if not fpb.data_pipe:
                    raise ValueError("Missing 'data_pipe' specification")
                pipe_socket = PipeSocket(fpb.pipe_socket)
                if pipe_socket is PipeSocket.UNKNOWN_PIPE_SOCKET:
                    raise ValueError("Invalid 'pipe_socket'")
                if not fpb.data_format:
                    raise ValueError("Missing 'data_format' specification")
            except Exception as exc:
                raise InvalidMessageError(
                    "Invalid data frame for OPEN message") from exc
        elif (message_type is MsgType.CLOSE and len(zmsg) > 1):
            fpb = create_message(PROTO_ERROR)
            for frame in zmsg[1:]:
                fpb.ParseFromString(frame)
                if not fpb.description:
                    raise InvalidMessageError("Missing error description")
        elif (message_type is MsgType.DATA and len(zmsg) > 2):
            raise InvalidMessageError(
                "DATA message may have only one data frame")
        elif (message_type in (MsgType.READY, MsgType.NOOP) and len(zmsg) > 1):
            raise InvalidMessageError(
                "Data frames not allowed for READY and NOOP messages")