def test_completes_op_with_error(self, mocker, stage, op, fake_exception, callback): op.error = fake_exception op.callback = callback pass_op_to_next_stage(stage, op) assert_callback_failed(op=op, error=fake_exception) assert stage.next.run_op.call_count == 0
def _execute_op(self, op): if isinstance(op, pipeline_ops_iothub.SetAuthProviderOperation): self.auth_provider = op.auth_provider self.auth_provider.on_sas_token_updated_handler = self.on_sas_token_updated operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_iothub.SetIoTHubConnectionArgsOperation( device_id=self.auth_provider.device_id, module_id=getattr(self.auth_provider, "module_id", None), hostname=self.auth_provider.hostname, gateway_hostname=getattr(self.auth_provider, "gateway_hostname", None), ca_cert=getattr(self.auth_provider, "ca_cert", None), sas_token=self.auth_provider.get_current_sas_token(), ), ) elif isinstance(op, pipeline_ops_iothub.SetX509AuthProviderOperation): self.auth_provider = op.auth_provider operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_iothub.SetIoTHubConnectionArgsOperation( device_id=self.auth_provider.device_id, module_id=getattr(self.auth_provider, "module_id", None), hostname=self.auth_provider.hostname, gateway_hostname=getattr(self.auth_provider, "gateway_hostname", None), ca_cert=getattr(self.auth_provider, "ca_cert", None), client_cert=self.auth_provider.get_x509_certificate(), ), ) else: operation_flow.pass_op_to_next_stage(self, op)
def _execute_op(self, op): if isinstance(op, pipeline_ops_provisioning.SetSymmetricKeySecurityClientOperation): security_client = op.security_client operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_provisioning.SetProvisioningClientConnectionArgsOperation( provisioning_host=security_client.provisioning_host, registration_id=security_client.registration_id, id_scope=security_client.id_scope, sas_token=security_client.get_current_sas_token(), ), ) elif isinstance(op, pipeline_ops_provisioning.SetX509SecurityClientOperation): security_client = op.security_client operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_provisioning.SetProvisioningClientConnectionArgsOperation( provisioning_host=security_client.provisioning_host, registration_id=security_client.registration_id, id_scope=security_client.id_scope, client_cert=security_client.get_x509_certificate(), ), ) else: operation_flow.pass_op_to_next_stage(self, op)
def on_sas_token_updated(self): logger.info( "{}: New sas token received. Passing down UpdateSasTokenOperation." .format(self.name)) @pipeline_thread.runs_on_pipeline_thread def on_token_update_complete(op): if op.error: logger.error( "{}({}): token update operation failed. Error={}".format( self.name, op.name, op.error)) unhandled_exceptions.exception_caught_in_background_thread( op.error) else: logger.debug( "{}({}): token update operation is complete".format( self.name, op.name)) operation_flow.pass_op_to_next_stage( stage=self, op=pipeline_ops_base.UpdateSasTokenOperation( sas_token=self.auth_provider.get_current_sas_token(), callback=on_token_update_complete, ), )
def on_token_update_complete(op): op.callback = old_callback if op.error: logger.error( "{}({}) token update failed. returning failure {}". format(self.name, op.name, op.error)) operation_flow.complete_op(stage=self, op=op) else: logger.debug( "{}({}) token update succeeded. reconnecting".format( self.name, op.name)) operation_flow.pass_op_to_next_stage( stage=self, op=pipeline_ops_base.ReconnectOperation( callback=on_reconnect_complete), ) logger.debug( "{}({}): passing to next stage with updated callback.". format(self.name, op.name))
def _execute_op(self, op): def map_twin_error(original_op, twin_op): if twin_op.error: original_op.error = twin_op.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)) original_op.error = Exception( "twin operation returned status {}".format( twin_op.status_code)) if isinstance(op, pipeline_ops_iothub.GetTwinOperation): def on_twin_response(twin_op): logger.info("{}({}): Got response for GetTwinOperation".format( self.name, op.name)) map_twin_error(original_op=op, twin_op=twin_op) if not twin_op.error: op.twin = json.loads(twin_op.response_body.decode("utf-8")) operation_flow.complete_op(self, op) operation_flow.pass_op_to_next_stage( self, pipeline_ops_base.SendIotRequestAndWaitForResponseOperation( 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): logger.info( "{}({}): Got response for PatchTwinReportedPropertiesOperation operation" .format(self.name, op.name)) map_twin_error(original_op=op, twin_op=twin_op) operation_flow.complete_op(self, op) logger.info("{}({}): Sending reported properties patch: {}".format( self.name, op.name, op.patch)) operation_flow.pass_op_to_next_stage( self, (pipeline_ops_base.SendIotRequestAndWaitForResponseOperation( request_type=constant.TWIN, method="PATCH", resource_location="/properties/reported/", request_body=json.dumps(op.patch), callback=on_twin_response, )), ) else: operation_flow.pass_op_to_next_stage(self, op)
def _run_op(self, op): def pipeline_ops_done(completed_op): op.error = completed_op.error op.callback(op) if isinstance(op, pipeline_ops_iothub.SetAuthProviderOperation): auth_provider = op.auth_provider operation_flow.run_ops_in_serial( self, pipeline_ops_iothub.SetAuthProviderArgsOperation( device_id=auth_provider.device_id, module_id=getattr(auth_provider, "module_id", None), hostname=auth_provider.hostname, gateway_hostname=getattr(auth_provider, "gateway_hostname", None), ca_cert=getattr(auth_provider, "ca_cert", None), ), pipeline_ops_base.SetSasTokenOperation( sas_token=auth_provider.get_current_sas_token() ), callback=pipeline_ops_done, ) elif isinstance(op, pipeline_ops_iothub.SetX509AuthProviderOperation): auth_provider = op.auth_provider operation_flow.run_ops_in_serial( self, pipeline_ops_iothub.SetAuthProviderArgsOperation( device_id=auth_provider.device_id, module_id=getattr(auth_provider, "module_id", None), hostname=auth_provider.hostname, gateway_hostname=getattr(auth_provider, "gateway_hostname", None), ca_cert=getattr(auth_provider, "ca_cert", None), ), pipeline_ops_base.SetClientAuthenticationCertificateOperation( certificate=auth_provider.get_x509_certificate() ), callback=pipeline_ops_done, ) else: operation_flow.pass_op_to_next_stage(self, op)
def _run_op(self, op): def pipeline_ops_done(completed_op): op.error = completed_op.error op.callback(op) if isinstance( op, pipeline_ops_provisioning. SetSymmetricKeySecurityClientOperation): security_client = op.security_client operation_flow.run_ops_in_serial( self, pipeline_ops_provisioning.SetSecurityClientArgsOperation( provisioning_host=security_client.provisioning_host, registration_id=security_client.registration_id, id_scope=security_client.id_scope, ), pipeline_ops_base.SetSasTokenOperation( sas_token=security_client.get_current_sas_token()), callback=pipeline_ops_done, ) elif isinstance( op, pipeline_ops_provisioning.SetX509SecurityClientOperation): security_client = op.security_client operation_flow.run_ops_in_serial( self, pipeline_ops_provisioning.SetSecurityClientArgsOperation( provisioning_host=security_client.provisioning_host, registration_id=security_client.registration_id, id_scope=security_client.id_scope, ), pipeline_ops_base.SetClientAuthenticationCertificateOperation( certificate=security_client.get_x509_certificate()), callback=pipeline_ops_done, ) else: operation_flow.pass_op_to_next_stage(self, op)
def _run_op(self, op): operation_flow.pass_op_to_next_stage(self, op)
def test_fails_op_when_no_next_stage(self, stage, op, callback): op.callback = callback stage.next = None pass_op_to_next_stage(stage, op) assert_callback_failed(op=op) pass
def test_passes_op_to_next_stage(self, mocker, stage, op, callback): pass_op_to_next_stage(stage, op) assert stage.next.run_op.call_count == 1 assert stage.next.run_op.call_args == mocker.call(op)
def _execute_op(self, op): if isinstance(op, pipeline_ops_iothub.SetIoTHubConnectionArgsOperation): self.device_id = op.device_id self.module_id = op.module_id # if we get auth provider args from above, we save some, use some to build topic names, # and always pass it down because we know that the MQTT protocol stage will also want # to receive these args. self._set_topic_names(device_id=op.device_id, module_id=op.module_id) if op.module_id: client_id = "{}/{}".format(op.device_id, op.module_id) else: client_id = op.device_id query_param_seq = [ ("api-version", pkg_constant.IOTHUB_API_VERSION), ("DeviceClientType", pkg_constant.USER_AGENT), ] username = "******".format( hostname=op.hostname, client_id=client_id, query_params=urllib.parse.urlencode(query_param_seq), ) if op.gateway_hostname: hostname = op.gateway_hostname else: hostname = op.hostname # TODO: test to make sure client_cert and sas_token travel down correctly operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.SetMQTTConnectionArgsOperation( client_id=client_id, hostname=hostname, username=username, ca_cert=op.ca_cert, client_cert=op.client_cert, sas_token=op.sas_token, ), ) elif (isinstance(op, pipeline_ops_base.UpdateSasTokenOperation) and self.pipeline_root.connected): logger.debug( "{}({}): Connected. Passing op down and reconnecting after token is updated." .format(self.name, op.name)) # make a callback that can call the user's callback after the reconnect is complete def on_reconnect_complete(reconnect_op): if reconnect_op.error: op.error = reconnect_op.error logger.error( "{}({}) reconnection failed. returning error {}". format(self.name, op.name, op.error)) operation_flow.complete_op(stage=self, op=op) else: logger.debug( "{}({}) reconnection succeeded. returning success.". format(self.name, op.name)) operation_flow.complete_op(stage=self, op=op) # save the old user callback so we can call it later. old_callback = op.callback # make a callback that either fails the UpdateSasTokenOperation (if the lower level failed it), # or issues a ReconnectOperation (if the lower level returned success for the UpdateSasTokenOperation) def on_token_update_complete(op): op.callback = old_callback if op.error: logger.error( "{}({}) token update failed. returning failure {}". format(self.name, op.name, op.error)) operation_flow.complete_op(stage=self, op=op) else: logger.debug( "{}({}) token update succeeded. reconnecting".format( self.name, op.name)) operation_flow.pass_op_to_next_stage( stage=self, op=pipeline_ops_base.ReconnectOperation( callback=on_reconnect_complete), ) logger.debug( "{}({}): passing to next stage with updated callback.". format(self.name, op.name)) # now, pass the UpdateSasTokenOperation down with our new callback. op.callback = on_token_update_complete operation_flow.pass_op_to_next_stage(stage=self, op=op) elif isinstance( op, pipeline_ops_iothub.SendD2CMessageOperation) or isinstance( op, pipeline_ops_iothub.SendOutputEventOperation): # Convert SendTelementry and SendOutputEventOperation operations into MQTT Publish operations topic = mqtt_topic_iothub.encode_properties( op.message, self.telemetry_topic) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation( topic=topic, payload=op.message.data), ) elif isinstance(op, pipeline_ops_iothub.SendMethodResponseOperation): # Sending a Method Response gets translated into an MQTT Publish operation topic = mqtt_topic_iothub.get_method_topic_for_publish( op.method_response.request_id, str(op.method_response.status)) payload = json.dumps(op.method_response.payload) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation(topic=topic, payload=payload), ) elif isinstance(op, pipeline_ops_base.EnableFeatureOperation): # Enabling a feature gets translated into an MQTT subscribe operation topic = self.feature_to_topic[op.feature_name] operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTSubscribeOperation(topic=topic), ) elif isinstance(op, pipeline_ops_base.DisableFeatureOperation): # Disabling a feature gets turned into an MQTT unsubscribe operation topic = self.feature_to_topic[op.feature_name] operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTUnsubscribeOperation(topic=topic), ) elif isinstance(op, pipeline_ops_base.SendIotRequestOperation): if op.request_type == pipeline_constant.TWIN: topic = mqtt_topic_iothub.get_twin_topic_for_publish( method=op.method, resource_location=op.resource_location, request_id=op.request_id, ) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation( topic=topic, payload=op.request_body), ) else: raise NotImplementedError( "SendIotRequestOperation request_type {} not supported". format(op.request_type)) else: # All other operations get passed down operation_flow.pass_op_to_next_stage(self, op)
def _execute_op(self, op): operation_flow.pass_op_to_next_stage(self, op)
def _run_op(self, op): if isinstance(op, pipeline_ops_iothub.SetAuthProviderArgsOperation): self.device_id = op.device_id self.module_id = op.module_id # if we get auth provider args from above, we save some, use some to build topic names, # and always pass it down because we know that the MQTT protocol stage will also want # to receive these args. self._set_topic_names(device_id=op.device_id, module_id=op.module_id) if op.module_id: client_id = "{}/{}".format(op.device_id, op.module_id) else: client_id = op.device_id username = "******".format( hostname=op.hostname, client_id=client_id) if op.gateway_hostname: hostname = op.gateway_hostname else: hostname = op.hostname operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.SetMQTTConnectionArgsOperation( client_id=client_id, hostname=hostname, username=username, ca_cert=op.ca_cert), ) elif isinstance( op, pipeline_ops_iothub.SendD2CMessageOperation) or isinstance( op, pipeline_ops_iothub.SendOutputEventOperation): # Convert SendTelementry and SendOutputEventOperation operations into MQTT Publish operations topic = mqtt_topic_iothub.encode_properties( op.message, self.telemetry_topic) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation( topic=topic, payload=op.message.data), ) elif isinstance(op, pipeline_ops_iothub.SendMethodResponseOperation): # Sending a Method Response gets translated into an MQTT Publish operation topic = mqtt_topic_iothub.get_method_topic_for_publish( op.method_response.request_id, str(op.method_response.status)) payload = json.dumps(op.method_response.payload) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation(topic=topic, payload=payload), ) elif isinstance(op, pipeline_ops_base.EnableFeatureOperation): # Enabling a feature gets translated into an MQTT subscribe operation topic = self.feature_to_topic[op.feature_name] operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTSubscribeOperation(topic=topic), ) elif isinstance(op, pipeline_ops_base.DisableFeatureOperation): # Disabling a feature gets turned into an MQTT unsubscribe operation topic = self.feature_to_topic[op.feature_name] operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTUnsubscribeOperation(topic=topic), ) elif isinstance(op, pipeline_ops_base.SendIotRequestOperation): if op.request_type == constant.TWIN: topic = mqtt_topic_iothub.get_twin_topic_for_publish( method=op.method, resource_location=op.resource_location, request_id=op.request_id, ) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation( topic=topic, payload=op.request_body), ) else: raise NotImplementedError( "SendIotRequestOperation request_type {} not supported". format(op.request_type)) else: # All other operations get passed down operation_flow.pass_op_to_next_stage(self, op)
def _execute_op(self, op): pass_op_to_next_stage(self, op)
def _execute_op(self, op): if isinstance( op, pipeline_ops_provisioning. SetProvisioningClientConnectionArgsOperation): # get security client args from above, save some, use some to build topic names, # always pass it down because MQTT protocol stage will also want to receive these args. client_id = op.registration_id query_param_seq = [ ("api-version", pkg_constant.PROVISIONING_API_VERSION), ("ClientVersion", pkg_constant.USER_AGENT), ] username = "******".format( id_scope=op.id_scope, registration_id=op.registration_id, query_params=urllib.parse.urlencode(query_param_seq), ) hostname = op.provisioning_host operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.SetMQTTConnectionArgsOperation( client_id=client_id, hostname=hostname, username=username, client_cert=op.client_cert, sas_token=op.sas_token, ), ) elif isinstance( op, pipeline_ops_provisioning.SendRegistrationRequestOperation): # Convert Sending the request into MQTT Publish operations topic = mqtt_topic.get_topic_for_register(op.request_id) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation( topic=topic, payload=op.request_payload), ) elif isinstance(op, pipeline_ops_provisioning.SendQueryRequestOperation): # Convert Sending the request into MQTT Publish operations topic = mqtt_topic.get_topic_for_query(op.request_id, op.operation_id) operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTPublishOperation( topic=topic, payload=op.request_payload), ) elif isinstance(op, pipeline_ops_base.EnableFeatureOperation): # Enabling for register gets translated into an MQTT subscribe operation topic = mqtt_topic.get_topic_for_subscribe() operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTSubscribeOperation(topic=topic), ) elif isinstance(op, pipeline_ops_base.DisableFeatureOperation): # Disabling a register response gets turned into an MQTT unsubscribe operation topic = mqtt_topic.get_topic_for_subscribe() operation_flow.delegate_to_different_op( stage=self, original_op=op, new_op=pipeline_ops_mqtt.MQTTUnsubscribeOperation(topic=topic), ) else: # All other operations get passed down operation_flow.pass_op_to_next_stage(self, op)
def _run_op(self, op): pass_op_to_next_stage(self, op)