def create_authenticator(self, connection, debug=False, **kwargs): """Create the AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.connection.Connection :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :rtype: uamqp.c_uamqp.CBSTokenAuth """ self._connection = connection self._session = Session(connection, **kwargs) try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout, self._connection.container_id) self._cbs_auth.set_trace(debug) except ValueError: self._session.destroy() raise errors.AMQPConnectionError( "Unable to open authentication session on connection {}.\n" "Please confirm target hostname exists: {}".format( connection.container_id, connection.hostname)) return self._cbs_auth
async def mgmt_request_async(self, message, operation, op_type=None, node=None, **kwargs): """Asynchronously run a request/response operation. These are frequently used for management tasks against a $management node, however any node name can be specified and the available options will depend on the target service. :param message: The message to send in the management request. :type message: ~uamqp.message.Message :param operation: The type of operation to be performed. This value will be service-specific, but common values include READ, CREATE and UPDATE. This value will be added as an application property on the message. :type operation: bytes or str :param op_type: The type on which to carry out the operation. This will be specific to the entities of the service. This value will be added as an application property on the message. :type op_type: bytes or str :param node: The target node. Default is `b"$management"`. :type node: bytes or str :param timeout: Provide an optional timeout in milliseconds within which a response to the management request must be received. :type timeout: int :param status_code_field: Provide an alternate name for the status code in the response body which can vary between services due to the spec still being in draft. The default is `b"statusCode"`. :type status_code_field: bytes or str :param description_fields: Provide an alternate name for the description in the response body which can vary between services due to the spec still being in draft. The default is `b"statusDescription"`. :type description_fields: bytes or str :param encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' :type encoding: str :rtype: ~uamqp.message.Message """ timeout = kwargs.pop('timeout', None) or 0 try: mgmt_link = self._mgmt_links[node] except KeyError: mgmt_link = MgmtOperationAsync(self, target=node, loop=self.loop, **kwargs) self._mgmt_links[node] = mgmt_link while not mgmt_link.open and not mgmt_link.mgmt_error: await self._connection.work_async() if mgmt_link.mgmt_error: raise mgmt_link.mgmt_error elif mgmt_link.open != constants.MgmtOpenStatus.Ok: raise errors.AMQPConnectionError( "Failed to open mgmt link: {}".format(mgmt_link.open)) op_type = op_type or b'empty' response = await mgmt_link.execute_async(operation, op_type, message, timeout=timeout) return response
def __init__(self, session, target=None, debug=False, status_code_field=b'statusCode', description_fields=b'statusDescription', encoding='UTF-8'): self._encoding = encoding self.connection = session._connection # pylint: disable=protected-access # self.session = Session( # connection, # incoming_window=constants.MAX_FRAME_SIZE_BYTES, # outgoing_window=constants.MAX_FRAME_SIZE_BYTES) self.target = self._encode(target or constants.MGMT_TARGET) status_code_field = self._encode(status_code_field) description_fields = self._encode(description_fields) self._responses = {} self._counter = c_uamqp.TickCounter() self._mgmt_op = c_uamqp.create_management_operation( session._session, self.target) # pylint: disable=protected-access self._mgmt_op.set_response_field_names(status_code_field, description_fields) self._mgmt_op.set_trace(debug) self.open = None try: self._mgmt_op.open(self) except ValueError: self.mgmt_error = errors.AMQPConnectionError( "Unable to open management session. " "Please confirm URI namespace exists.") else: self.mgmt_error = None
def _client_ready(self): """Determine whether the client is ready to start receiving messages. To be ready, the connection must be open and authentication complete, The Session, Link and MessageReceiver must be open and in non-errored states. :returns: bool :raises: ~uamqp.errors.AMQPConnectionError if the MessageReceiver goes into an error state. """ # pylint: disable=protected-access if not self._message_receiver: self._message_receiver = self.receiver_type( self._session, self._remote_address, self._name, on_message_received=self, name='receiver-link-{}'.format(uuid.uuid4()), debug=self._debug_trace, receive_settle_mode=self._receive_settle_mode, prefetch=self._prefetch, max_message_size=self._max_message_size, properties=self._link_properties, encoding=self._encoding) self._message_receiver.open() return False elif self._message_receiver._state == constants.MessageReceiverState.Error: raise errors.AMQPConnectionError( "Message Receiver Client was unable to open. " "Please confirm credentials and access permissions." "\nSee debug trace for more details.") elif self._message_receiver._state != constants.MessageReceiverState.Open: self._last_activity_timestamp = self._counter.get_current_ms() return False return True
async def _client_ready(self): """Determine whether the client is ready to start sending messages. To be ready, the connection must be open and authentication complete, The Session, Link and MessageSender must be open and in non-errored states. :returns: bool :raises: ~uamqp.errors.AMQPConnectionError if the MessageSender goes into an error state. """ # pylint: disable=protected-access if not self._message_sender: self._message_sender = self.sender_type( self._session, self._name, self._remote_address, name='sender-link-{}'.format(uuid.uuid4()), debug=self._debug_trace, send_settle_mode=self._send_settle_mode, max_message_size=self._max_message_size, properties=self._link_properties, encoding=self._encoding, loop=self.loop) await self._message_sender.open_async() return False elif self._message_sender._state == constants.MessageSenderState.Error: raise errors.AMQPConnectionError( "Message Sender Client was unable to open. " "Please confirm credentials and access permissions." "\nSee debug trace for more details.") elif self._message_sender._state != constants.MessageSenderState.Open: return False return True
def create_authenticator(self, connection, debug=False): """Create the AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.Connection :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :returns: ~uamqp.c_uamqp.CBSTokenAuth """ self._lock = threading.Lock() self._session = Session( connection, incoming_window=constants.MAX_FRAME_SIZE_BYTES, outgoing_window=constants.MAX_FRAME_SIZE_BYTES) try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout) self._cbs_auth.set_trace(debug) except ValueError: raise errors.AMQPConnectionError( "Unable to open authentication session. " "Please confirm target URI exists.") return self._cbs_auth
def _attach_received(self, source, target, properties, error=None): if error: self._link_error = errors.AMQPConnectionError(error) if self._on_attach: if source and target: source = Source.from_c_obj(source) target = Target.from_c_obj(target) if properties: properties = properties.value self._on_attach(source, target, properties, self._link_error)
async def _management_request_async(self, mgmt_msg: Message, op_type: bytes) -> Any: retried_times = 0 last_exception = None while retried_times <= self._config.max_retries: mgmt_auth = await self._create_auth_async() mgmt_client = AMQPClientAsync(self._mgmt_target, auth=mgmt_auth, debug=self._config.network_tracing) try: conn = await self._conn_manager_async.get_connection( self._address.hostname, mgmt_auth) mgmt_msg.application_properties[ "security_token"] = mgmt_auth.token await mgmt_client.open_async(connection=conn) response = await mgmt_client.mgmt_request_async( mgmt_msg, constants.READ_OPERATION, op_type=op_type, status_code_field=MGMT_STATUS_CODE, description_fields=MGMT_STATUS_DESC, ) status_code = int( response.application_properties[MGMT_STATUS_CODE]) description = response.application_properties.get( MGMT_STATUS_DESC) # type: Optional[Union[str, bytes]] if description and isinstance(description, six.binary_type): description = description.decode('utf-8') if status_code < 400: return response if status_code in [401]: raise errors.AuthenticationException( "Management authentication failed. Status code: {}, Description: {!r}" .format(status_code, description)) if status_code in [404]: raise ConnectError( "Management connection failed. Status code: {}, Description: {!r}" .format(status_code, description)) raise errors.AMQPConnectionError( "Management request error. Status code: {}, Description: {!r}" .format(status_code, description)) except asyncio.CancelledError: # pylint: disable=try-except-raise raise except Exception as exception: # pylint:disable=broad-except last_exception = await _handle_exception(exception, self) await self._backoff_async(retried_times=retried_times, last_exception=last_exception) retried_times += 1 if retried_times > self._config.max_retries: _LOGGER.info("%r returns an exception %r", self._container_id, last_exception) raise last_exception finally: await mgmt_client.close_async()
def open(self): """Open the MessageSender in order to start processing messages. :raises: ~uamqp.errors.AMQPConnectionError if the Sender raises an error on opening. This can happen if the target URI is invalid or the credentials are rejected. """ try: self._sender.open() except ValueError: raise errors.AMQPConnectionError( "Failed to open Message Sender. " "Please confirm credentials and target URI.")
async def open_async(self): """Asynchronously open the MessageReceiver in order to start processing messages. :raises: ~uamqp.errors.AMQPConnectionError if the Receiver raises an error on opening. This can happen if the source URI is invalid or the credentials are rejected. """ try: self._receiver.open(self) except ValueError: raise errors.AMQPConnectionError( "Failed to open Message Receiver. " "Please confirm credentials and target URI.")
def test_unknown_connection_error(): logger = logging.getLogger("testlogger") amqp_error = AMQPErrors.AMQPConnectionError(AMQPConstants.ErrorCodes.UnknownError) sb_error = _create_servicebus_exception(logger, amqp_error) assert isinstance(sb_error,ServiceBusConnectionError) assert sb_error._retryable assert sb_error._shutdown_handler amqp_error = AMQPErrors.AMQPError(AMQPConstants.ErrorCodes.UnknownError) sb_error = _create_servicebus_exception(logger, amqp_error) assert not isinstance(sb_error,ServiceBusConnectionError) assert isinstance(sb_error,ServiceBusError) assert not sb_error._retryable assert sb_error._shutdown_handler
async def open_async(self): """Asynchronously open the MessageSender in order to start processing messages. :raises: ~uamqp.errors.AMQPConnectionError if the Sender raises an error on opening. This can happen if the target URI is invalid or the credentials are rejected. """ try: await self.loop.run_in_executor( None, functools.partial(self._sender.open)) except ValueError: raise errors.AMQPConnectionError( "Failed to open Message Sender. " "Please confirm credentials and target URI.")
async def create_authenticator_async(self, connection, debug=False, loop=None, **kwargs): """Create the async AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.async_ops.connection_async.ConnectionAsync :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :param loop: A user specified event loop. :type loop: ~asycnio.AbstractEventLoop :rtype: uamqp.c_uamqp.CBSTokenAuth """ self.loop = loop or get_running_loop() self._connection = connection self._session = SessionAsync(connection, loop=self.loop, **kwargs) if self.token_type == b'jwt': # Async initialize the jwt token await self.update_token() try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout, self._connection.container_id) self._cbs_auth.set_trace(debug) except ValueError: await self._session.destroy_async() raise errors.AMQPConnectionError( "Unable to open authentication session on connection {}.\n" "Please confirm target hostname exists: {}".format( connection.container_id, connection.hostname)) from None return self._cbs_auth
async def create_authenticator_async(self, connection, debug=False, loop=None, **kwargs): """Create the async AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.async_ops.connection_async.ConnectionAsync :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :rtype: uamqp.c_uamqp.CBSTokenAuth """ self._internal_kwargs = get_dict_with_loop_if_needed(loop) self._connection = connection kwargs.update(self._internal_kwargs) self._session = SessionAsync(connection, **kwargs) try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout, self._connection.container_id, self._refresh_window) self._cbs_auth.set_trace(debug) except ValueError: await self._session.destroy_async() raise errors.AMQPConnectionError( "Unable to open authentication session on connection {}.\n" "Please confirm target hostname exists: {}".format( connection.container_id, connection.hostname)) from None return self._cbs_auth
async def create_authenticator_async(self, connection, debug=False, loop=None): """Create the async AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.async.ConnectionAsync :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :param loop: A user specified event loop. :type loop: ~asycnio.AbstractEventLoop :returns: ~uamqp.c_uamqp.CBSTokenAuth """ self.loop = loop or asyncio.get_event_loop() self._lock = asyncio.Lock(loop=self.loop) self._session = SessionAsync( connection, incoming_window=constants.MAX_FRAME_SIZE_BYTES, outgoing_window=constants.MAX_FRAME_SIZE_BYTES, loop=self.loop) try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout) self._cbs_auth.set_trace(debug) except ValueError: raise errors.AMQPConnectionError( "Unable to open authentication session. " "Please confirm target URI exists.") from None return self._cbs_auth