Exemplo n.º 1
0
    def _execute_op(self, op):
        def map_twin_error(error, twin_op):
            if error:
                return error
            elif twin_op.status_code >= 300:
                # TODO map error codes to correct exceptions
                logger.error("Error {} received from twin operation".format(twin_op.status_code))
                logger.error("response body: {}".format(twin_op.response_body))
                return exceptions.ServiceError(
                    "twin operation returned status {}".format(twin_op.status_code)
                )

        if isinstance(op, pipeline_ops_iothub.GetTwinOperation):

            def on_twin_response(twin_op, error):
                logger.debug("{}({}): Got response for GetTwinOperation".format(self.name, op.name))
                error = map_twin_error(error=error, twin_op=twin_op)
                if not error:
                    op.twin = json.loads(twin_op.response_body.decode("utf-8"))
                self.complete_op(op, error=error)

            self.send_op_down(
                pipeline_ops_base.RequestAndResponseOperation(
                    request_type=constant.TWIN,
                    method="GET",
                    resource_location="/",
                    request_body=" ",
                    callback=on_twin_response,
                )
            )

        elif isinstance(op, pipeline_ops_iothub.PatchTwinReportedPropertiesOperation):

            def on_twin_response(twin_op, error):
                logger.debug(
                    "{}({}): Got response for PatchTwinReportedPropertiesOperation operation".format(
                        self.name, op.name
                    )
                )
                error = map_twin_error(error=error, twin_op=twin_op)
                self.complete_op(op, error=error)

            logger.debug(
                "{}({}): Sending reported properties patch: {}".format(self.name, op.name, op.patch)
            )

            self.send_op_down(
                pipeline_ops_base.RequestAndResponseOperation(
                    request_type=constant.TWIN,
                    method="PATCH",
                    resource_location="/properties/reported/",
                    request_body=json.dumps(op.patch),
                    callback=on_twin_response,
                )
            )

        else:
            self.send_op_down(op)
def make_fake_request_and_response(mocker):
    return pipeline_ops_base.RequestAndResponseOperation(
        request_type=fake_request_type,
        method=fake_method,
        resource_location=fake_resource_location,
        request_body=fake_request_body,
        callback=mocker.MagicMock(),
    )
Exemplo n.º 3
0
    def _run_op(self, op):
        if isinstance(op, pipeline_ops_provisioning.RegisterOperation):
            initial_register_op = op
            self_weakref = weakref.ref(self)

            @pipeline_thread.invoke_on_pipeline_thread_nowait
            def register_timeout():
                this = self_weakref()
                logger.info(
                    "{stage_name}({op_name}): returning timeout error".format(
                        stage_name=this.name, op_name=op.name))
                initial_register_op.complete(error=(exceptions.ServiceError(
                    "Operation timed out before provisioning service could respond for {op_type} operation"
                    .format(op_type=constant.REGISTER))))

            logger.debug("{}({}): Creating provisioning timeout timer".format(
                self.name, op.name))
            initial_register_op.provisioning_timeout_timer = Timer(
                constant.DEFAULT_TIMEOUT_INTERVAL, register_timeout)
            initial_register_op.provisioning_timeout_timer.start()

            def on_registration_response(op, error):
                self._clear_timeout_timer(initial_register_op, error)
                logger.debug(
                    "{stage_name}({op_name}): Received response with status code {status_code} for RegisterOperation"
                    .format(stage_name=self.name,
                            op_name=op.name,
                            status_code=op.status_code))
                if error:
                    logger.error(
                        "{stage_name}({op_name}): Received error for {prov_op_name} operation"
                        .format(stage_name=self.name,
                                op_name=op.name,
                                prov_op_name=op.request_type))
                    initial_register_op.complete(error=error)

                else:

                    if 300 <= op.status_code < 429:
                        self._process_service_error_status_code(
                            initial_register_op, op)

                    elif op.status_code >= 429:
                        self._process_retry_status_code(
                            error, initial_register_op, op)

                    else:
                        decoded_response = self._decode_response(op)
                        operation_id = decoded_response.get(
                            "operationId", None)
                        registration_status = decoded_response.get(
                            "status", None)

                        if registration_status == "assigning":
                            self_weakref = weakref.ref(self)

                            def copy_result_to_original_op(op, error):
                                logger.debug(
                                    "Copying registration result from Query Status Op to Registration Op"
                                )
                                initial_register_op.registration_result = op.registration_result
                                initial_register_op.error = error

                            @pipeline_thread.invoke_on_pipeline_thread_nowait
                            def do_query_after_interval():
                                this = self_weakref()
                                initial_register_op.polling_timer.cancel()
                                initial_register_op.polling_timer = None

                                logger.info(
                                    "{stage_name}({op_name}): polling".format(
                                        stage_name=this.name, op_name=op.name))

                                query_worker_op = initial_register_op.spawn_worker_op(
                                    worker_op_type=pipeline_ops_provisioning.
                                    PollStatusOperation,
                                    request_payload=" ",
                                    operation_id=operation_id,
                                    callback=copy_result_to_original_op,
                                )

                                self.send_op_down(query_worker_op)

                            logger.warning(
                                "{stage_name}({op_name}): Op will transition into polling after interval {interval}.  Setting timer."
                                .format(
                                    stage_name=self.name,
                                    op_name=op.name,
                                    interval=constant.DEFAULT_POLLING_INTERVAL,
                                ))

                            logger.debug(
                                "{}({}): Creating polling timer".format(
                                    self.name, op.name))
                            initial_register_op.polling_timer = Timer(
                                constant.DEFAULT_POLLING_INTERVAL,
                                do_query_after_interval)
                            initial_register_op.polling_timer.start()

                        elif registration_status == "failed" or registration_status == "assigned":
                            self._process_failed_and_assigned_registration_status(
                                error=error,
                                operation_id=operation_id,
                                decoded_response=decoded_response,
                                registration_status=registration_status,
                                original_provisioning_op=initial_register_op,
                                request_response_op=op,
                            )

                        else:
                            self._process_unknown_registration_status(
                                registration_status=registration_status,
                                original_provisioning_op=initial_register_op,
                                request_response_op=op,
                            )

            registration_payload = DeviceRegistrationPayload(
                registration_id=initial_register_op.registration_id,
                custom_payload=initial_register_op.request_payload,
            )
            self.send_op_down(
                pipeline_ops_base.RequestAndResponseOperation(
                    request_type=constant.REGISTER,
                    method="PUT",
                    resource_location="/",
                    request_body=registration_payload.get_json_string(),
                    callback=on_registration_response,
                ))

        else:
            super(RegistrationStage, self)._run_op(op)
Exemplo n.º 4
0
    def _run_op(self, op):
        if isinstance(op, pipeline_ops_provisioning.PollStatusOperation):
            query_status_op = op
            self_weakref = weakref.ref(self)

            @pipeline_thread.invoke_on_pipeline_thread_nowait
            def query_timeout():
                this = self_weakref()
                logger.info(
                    "{stage_name}({op_name}): returning timeout error".format(
                        stage_name=this.name, op_name=op.name))
                query_status_op.complete(error=(exceptions.ServiceError(
                    "Operation timed out before provisioning service could respond for {op_type} operation"
                    .format(op_type=constant.QUERY))))

            logger.debug("{}({}): Creating provisioning timeout timer".format(
                self.name, op.name))
            query_status_op.provisioning_timeout_timer = Timer(
                constant.DEFAULT_TIMEOUT_INTERVAL, query_timeout)
            query_status_op.provisioning_timeout_timer.start()

            def on_query_response(op, error):
                self._clear_timeout_timer(query_status_op, error)
                logger.debug(
                    "{stage_name}({op_name}): Received response with status code {status_code} for PollStatusOperation with operation id {oper_id}"
                    .format(
                        stage_name=self.name,
                        op_name=op.name,
                        status_code=op.status_code,
                        oper_id=op.query_params["operation_id"],
                    ))

                if error:
                    logger.error(
                        "{stage_name}({op_name}): Received error for {prov_op_name} operation"
                        .format(stage_name=self.name,
                                op_name=op.name,
                                prov_op_name=op.request_type))
                    query_status_op.complete(error=error)

                else:
                    if 300 <= op.status_code < 429:
                        self._process_service_error_status_code(
                            query_status_op, op)

                    elif op.status_code >= 429:
                        self._process_retry_status_code(
                            error, query_status_op, op)

                    else:
                        decoded_response = self._decode_response(op)
                        operation_id = decoded_response.get(
                            "operationId", None)
                        registration_status = decoded_response.get(
                            "status", None)
                        if registration_status == "assigning":
                            polling_interval = (
                                int(op.retry_after, 10)
                                if op.retry_after is not None else
                                constant.DEFAULT_POLLING_INTERVAL)
                            self_weakref = weakref.ref(self)

                            @pipeline_thread.invoke_on_pipeline_thread_nowait
                            def do_polling():
                                this = self_weakref()
                                logger.info(
                                    "{stage_name}({op_name}): retrying".format(
                                        stage_name=this.name, op_name=op.name))
                                query_status_op.polling_timer.cancel()
                                query_status_op.polling_timer = None
                                query_status_op.completed = False
                                this.run_op(query_status_op)

                            logger.info(
                                "{stage_name}({op_name}): Op needs retry with interval {interval} because of {error}. Setting timer."
                                .format(
                                    stage_name=self.name,
                                    op_name=op.name,
                                    interval=polling_interval,
                                    error=error,
                                ))

                            logger.debug(
                                "{}({}): Creating polling timer".format(
                                    self.name, op.name))
                            query_status_op.polling_timer = Timer(
                                polling_interval, do_polling)
                            query_status_op.polling_timer.start()

                        elif registration_status == "assigned" or registration_status == "failed":
                            self._process_failed_and_assigned_registration_status(
                                error=error,
                                operation_id=operation_id,
                                decoded_response=decoded_response,
                                registration_status=registration_status,
                                original_provisioning_op=query_status_op,
                                request_response_op=op,
                            )

                        else:
                            self._process_unknown_registration_status(
                                registration_status=registration_status,
                                original_provisioning_op=query_status_op,
                                request_response_op=op,
                            )

            self.send_op_down(
                pipeline_ops_base.RequestAndResponseOperation(
                    request_type=constant.QUERY,
                    method="GET",
                    resource_location="/",
                    query_params={
                        "operation_id": query_status_op.operation_id
                    },
                    request_body=query_status_op.request_payload,
                    callback=on_query_response,
                ))

        else:
            super(PollingStatusStage, self)._run_op(op)
    def _run_op(self, op):
        def map_twin_error(error, twin_op):
            if error:
                return error
            elif twin_op.status_code >= 300:
                # TODO map error codes to correct exceptions
                logger.error("Error {} received from twin operation".format(
                    twin_op.status_code))
                logger.error("response body: {}".format(twin_op.response_body))
                return exceptions.ServiceError(
                    "twin operation returned status {}".format(
                        twin_op.status_code))

        if isinstance(op, pipeline_ops_iothub.GetTwinOperation):

            # Alias to avoid overload within the callback below
            # CT-TODO: remove the need for this with better callback semantics
            op_waiting_for_response = op

            def on_twin_response(op, error):
                logger.debug(
                    "{}({}): Got response for GetTwinOperation".format(
                        self.name, op.name))
                error = map_twin_error(error=error, twin_op=op)
                if not error:
                    op_waiting_for_response.twin = json.loads(
                        op.response_body.decode("utf-8"))
                op_waiting_for_response.complete(error=error)

            self.send_op_down(
                pipeline_ops_base.RequestAndResponseOperation(
                    request_type=constant.TWIN,
                    method="GET",
                    resource_location="/",
                    request_body=" ",
                    callback=on_twin_response,
                ))

        elif isinstance(
                op, pipeline_ops_iothub.PatchTwinReportedPropertiesOperation):

            # Alias to avoid overload within the callback below
            # CT-TODO: remove the need for this with better callback semantics
            op_waiting_for_response = op

            def on_twin_response(op, error):
                logger.debug(
                    "{}({}): Got response for PatchTwinReportedPropertiesOperation operation"
                    .format(self.name, op.name))
                error = map_twin_error(error=error, twin_op=op)
                op_waiting_for_response.complete(error=error)

            logger.debug(
                "{}({}): Sending reported properties patch: {}".format(
                    self.name, op.name, op.patch))

            self.send_op_down(
                pipeline_ops_base.RequestAndResponseOperation(
                    request_type=constant.TWIN,
                    method="PATCH",
                    resource_location="/properties/reported/",
                    request_body=json.dumps(op.patch),
                    callback=on_twin_response,
                ))

        else:
            super(TwinRequestResponseStage, self)._run_op(op)