Beispiel #1
0
    def __init__(self, router_host, router_port, cert_dir):
        self.router_host = router_host
        self.router_port = router_port
        self.cert_dir = cert_dir
        ssl_domain = None
        allowed_mechs = []
        sasl_enabled = False

        if self.cert_dir != None:
            ssl_domain = SSLDomain(SSLDomain.MODE_CLIENT)
            ssl_domain.set_trusted_ca_db(
                str(os.path.join(self.cert_dir, 'ca.crt')))
            ssl_domain.set_credentials(
                str(os.path.join(self.cert_dir, "tls.crt")),
                str(os.path.join(self.cert_dir, "tls.key")), None)
            ssl_domain.set_peer_authentication(SSLDomain.VERIFY_PEER)
            allowed_mechs = str("EXTERNAL")
            sasl_enabled = True

        self.client = SyncRequestResponse(
            BlockingConnection("amqps://" + self.router_host + ":" +
                               str(self.router_port),
                               30,
                               None,
                               ssl_domain,
                               allowed_mechs=allowed_mechs,
                               sasl_enabled=sasl_enabled), "$management")
    def test_verify_vhost_maximum_connections(self):
        addr = "%s/$management" % self.address()
        timeout = 5

        # two connections should be ok
        denied = False
        try:
            bc1 = SyncRequestResponse(BlockingConnection(addr,
                                                         timeout=timeout))
            bc2 = SyncRequestResponse(BlockingConnection(addr,
                                                         timeout=timeout))
        except ConnectionException:
            denied = True
        except Timeout:
            denied = True

        self.assertFalse(denied)  # assert connections were opened

        # third connection should be denied
        denied = False
        try:
            bc3 = SyncRequestResponse(BlockingConnection(addr,
                                                         timeout=timeout))
        except ConnectionException:
            denied = True
        except Timeout:
            denied = True

        self.assertTrue(
            denied)  # assert if connection that should not open did open

        bc1.connection.close()
        bc2.connection.close()
Beispiel #3
0
 def __init__(self, connection):
     """
     Create a management client proxy using the given connection.
     """
     self.name = self.identity = u'self'
     self.type = u'org.amqp.management' # AMQP management node type
     self.url = connection.url
     self.client = SyncRequestResponse(connection, self.url.path)
    def test_link_route_lookup_not_found(self):
        """
        verify correct handling of lookup misses
        """
        bc = BlockingConnection(self.INT_A.edge_listener, timeout=TIMEOUT)
        srr = SyncRequestResponse(bc, self.QD_TERMINUS_ADDRESS_LOOKUP)

        rsp = self._check_response(srr.call(self._lookup_request("not.found.address", True)))
        self.assertEqual(self.QCM_ADDR_LOOKUP_NOT_FOUND, rsp[0])
Beispiel #5
0
 def _invalid_request_test(self, msg, disposition=Disposition.REJECTED):
     bc = BlockingConnection(self.INT_A.edge_listener, timeout=TIMEOUT)
     srr = SyncRequestResponse(bc, self.QD_TERMINUS_ADDRESS_LOOKUP)
     # @TODO(kgiusti) - self.assertRaises does not work here:
     try:
         srr.call(msg)
         self.assertTrue(False)
     except SendException as exc:
         self.assertEqual(disposition, exc.state)
     bc.close()
Beispiel #6
0
    def query(
        self,
        entity_type: str = 'org.apache.qpid.dispatch.router.node'
    ) -> NamedTuple:
        """
        Queries the related router instance, retrieving information for
        the provided Entity Type. The result is an array of a named tuple,
        whose fields are the attribute names returned by the router.
        In example, if querying entity type: org.apache.qpid.dispatch.allocator,
        the results can be accessed as: result.typeName, result.typeSize, ...
        same names returned by the router.
        :param entity_type:
        :return:
        """
        # Scheme to use
        scheme = 'amqp'
        if self._connection_options['ssl_domain']:
            scheme = 'amqps'

        # URL to test
        url = Url("%s://%s:%s/$management" % (scheme, self.host, self.port))
        self._logger.info("Querying router at: %s://%s:%s/$management" %
                          (scheme, self.host, self.port))

        # Proton connection
        self._logger.debug("Connection options: %s" % self._connection_options)
        connection = BlockingConnection(url, **self._connection_options)

        # Proton sync client
        client = SyncRequestResponse(connection, url.path)

        # Request message object
        request = proton.Message()
        request.properties = {
            u'operation': u'QUERY',
            u'entityType': u'%s' % entity_type
        }
        request.body = {u'attributeNames': []}

        # Sending the request
        response = client.call(request)

        # Closing connection
        client.connection.close()

        # Namedtuple that represents the query response from the router
        # so fields can be read based on their attribute names.
        RouterQueryResults = namedtuple('RouterQueryResults',
                                        response.body["attributeNames"])
        records = []

        for record in response.body["results"]:
            records.append(RouterQueryResults(*record))

        return records
 def test_link_route_lookup_no_dest(self):
     """
     verify correct handling of matches to mobile addresses
     """
     bc = BlockingConnection(self.INT_A.edge_listener, timeout=TIMEOUT)
     srr = SyncRequestResponse(bc, self.QD_TERMINUS_ADDRESS_LOOKUP)
     rsp = self._check_response(srr.call(self._lookup_request("org.apache.A.nope", True)))
     self.assertEqual(self.QCM_ADDR_LOOKUP_OK, rsp[0])
     self.assertEqual(True, rsp[1])
     self.assertEqual(False, rsp[2])
     bc.close()
Beispiel #8
0
    def __init__(self, connection, locales=None):
        """
        Create a management node proxy using the given connection.
        @param locales: Default list of locales for management operations.
        @param connection: a L{BlockingConnection} to the management agent.
        """
        self.name = self.identity = u'self'
        self.type = u'org.amqp.management'  # AMQP management node type
        self.locales = locales

        self.locales = locales
        self.url = connection.url
        self.client = SyncRequestResponse(connection, self.url.path)
        self.reply_to = self.client.reply_to
Beispiel #9
0
    def test_link_route_lookup_not_link_route(self):
        """
        verify correct handling of matches to mobile addresses
        """
        addr = "not.a.linkroute"
        client = AsyncTestReceiver(self.INT_A.listener, addr)
        self.INT_A.wait_address(addr)

        bc = BlockingConnection(self.INT_A.edge_listener, timeout=TIMEOUT)
        srr = SyncRequestResponse(bc, self.QD_TERMINUS_ADDRESS_LOOKUP)

        rsp = self._check_response(srr.call(self._lookup_request(addr, True)))
        # self.assertEqual(self.QCM_ADDR_LOOKUP_OK, rsp[0])
        self.assertEqual(False, rsp[1])
        bc.close()
        client.stop()
    def test_sync_request_response_blocking_connection_no_object_leaks(self):
        with test_broker() as tb:
            sockname = tb.get_acceptor_sockname()
            url = "{0}:{1}".format(*sockname)
            opts = namedtuple('Opts', ['address', 'timeout'])(address=url, timeout=3)

            with no_fd_leaks(self):
                client = SyncRequestResponse(
                    BlockingConnection(url, opts.timeout, allowed_mechs="ANONYMOUS"), "somequeue")
                try:
                    request = "One Two Three Four"
                    response = client.call(Message(body=request))
                finally:
                    client.connection.close()

        gc.collect()
Beispiel #11
0
 def get_metrics(self):
     client = SyncRequestResponse(BlockingConnection("127.0.0.1:5672", 30),
                                  "$management")
     try:
         properties = {}
         properties["entityType"] = "org.apache.qpid.dispatch.connection"
         properties["operation"] = "QUERY"
         properties["name"] = "self"
         message = Message(body=None, properties=properties)
         response = client.call(message)
         return response
     except:
         e = sys.exc_info()[0]
         print("Error querying router for metrics: %s" % e)
         return None
     finally:
         client.connection.close()
Beispiel #12
0
    def test_link_route_lookup_ok(self):
        """
        verify a link route address can be looked up successfully for both
        locally attached and remotely attached containers
        """

        # fire up a fake broker attached to the router local to the edge router
        # wait until both in and out addresses are ready
        fb = FakeBroker(self.INT_A.broker_connector,
                        container_id='FakeBrokerA')
        self.INT_A.wait_address("org.apache.A", containers=1, count=2)

        # create a fake edge and lookup the target address
        bc = BlockingConnection(self.INT_A.edge_listener, timeout=TIMEOUT)
        srr = SyncRequestResponse(bc, self.QD_TERMINUS_ADDRESS_LOOKUP)

        for direction in [True, False]:
            # True = direction inbound (receiver) False = direction outbound (sender)
            rsp = self._check_response(
                srr.call(self._lookup_request("org.apache.A.foo", direction)))
            self.assertEqual(self.QCM_ADDR_LOOKUP_OK, rsp[0])
            self.assertTrue(rsp[1])
            self.assertTrue(rsp[2])

        # shutdown fake router
        fb.join()

        # now fire up a fake broker attached to the remote router
        fb = FakeBroker(self.INT_B.broker_connector,
                        container_id='FakeBrokerB')
        self.INT_A.wait_address("org.apache.B", remotes=1, count=2)

        for direction in [True, False]:
            rsp = self._check_response(
                srr.call(self._lookup_request("org.apache.B.foo", direction)))
            self.assertEqual(self.QCM_ADDR_LOOKUP_OK, rsp[0])
            self.assertTrue(rsp[1])
            self.assertTrue(rsp[2])

        fb.join()
        bc.close()
Beispiel #13
0
    def __init__(self, router_address, timeout, router_id=None, edge_id=None):
        """
        @param router_address: the network address of the router to manage.
        @param timeout: raise an error if a management operation blocks longer
        than timeout seconds.
        @param router_id: identity of remote router.  Use this if the router to
        be managed is not the router at router_address.  This can be used to
        access a remote router using a local router as a proxy.
        @param edge_id: like router_id except remote is an edge router.

        Note that router_id and edge_id are mutually exclusive
        """
        assert (not (edge_id and router_id))
        self._conn = BlockingConnection(router_address, timeout=timeout)
        if router_id:
            self._mgmt_address = u'_topo/0/%s/$management' % router_id
        elif edge_id:
            self._mgmt_address = u'_edge/%s/$management' % edge_id
        else:
            self._mgmt_address = u'$management'
        self._client = SyncRequestResponse(self._conn, self._mgmt_address)
 def collect_metric(self, entityType):
     try:
         client = SyncRequestResponse(
             BlockingConnection("127.0.0.1:5672", 30), "$management")
         try:
             properties = {}
             properties["entityType"] = entityType
             properties["operation"] = "QUERY"
             properties["name"] = "self"
             message = Message(body=None, properties=properties)
             response = client.call(message)
             if response == None:
                 return response
             else:
                 return RouterResponse(response)
         finally:
             client.connection.close()
     except:
         e = sys.exc_info()[0]
         print("Error querying router for metrics: %s" % e)
         return None
Beispiel #15
0
 def test_connection_properties(self):
     ensureCanTestExtendedSASL()
     server = ConnPropertiesServer(Url(host="127.0.0.1", port=free_tcp_port()), timeout=self.timeout)
     server.start()
     server.wait()
     connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES)
     client = SyncRequestResponse(connection)
     client.connection.close()
     server.join(timeout=self.timeout)
     self.assertEquals(server.properties_received, True)
     self.assertEquals(server.offered_capabilities_received, True)
     self.assertEquals(server.desired_capabilities_received, True)
Beispiel #16
0
 def test_allowed_mechs_anonymous(self):
     # All this test does it make sure that if we pass allowed_mechs to BlockingConnection, it is actually used.
     server = ConnPropertiesServer(Url(host="127.0.0.1", port=free_tcp_port()), timeout=self.timeout)
     server.start()
     server.wait()
     # An ANONYMOUS allowed_mechs will work, anonymous connections are allowed by ConnPropertiesServer
     connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES, allowed_mechs=ANONYMOUS)
     client = SyncRequestResponse(connection)
     client.connection.close()
     server.join(timeout=self.timeout)
     self.assertEquals(server.properties_received, True)
     self.assertEquals(server.offered_capabilities_received, True)
     self.assertEquals(server.desired_capabilities_received, True)
    def test_connection_properties(self):
        connection = BlockingConnection(self.router.addresses[0],
                                        timeout=60,
                                        properties=CONNECTION_PROPERTIES)
        client = SyncRequestResponse(connection)

        node = Node.connect(self.router.addresses[0])

        results = node.query(type='org.apache.qpid.dispatch.connection', attribute_names=[u'properties']).results

        self.assertEqual(results[0][0][u'connection'], u'properties')
        self.assertEqual(results[0][0][u'int_property'], 6451)

        client.connection.close()
Beispiel #18
0
    def __init__(self, connection, locales=None):
        """
        Create a management node proxy using the given connection.
        @param locales: Default list of locales for management operations.
        @param connection: a L{BlockingConnection} to the management agent.
        """
        self.name = self.identity = u'self'
        self.type = u'org.amqp.management' # AMQP management node type
        self.locales = locales

        self.locales = locales
        self.url = connection.url
        self.client = SyncRequestResponse(connection, self.url.path)
        self.reply_to = self.client.reply_to
Beispiel #19
0
    def test_request_response(self):
        ensureCanTestExtendedSASL()
        def test(name, address="x"):
            for i in range(5):
                body="%s%s" % (name, i)
                response = client.call(Message(address=address, body=body))
                self.assertEquals(response.address, client.reply_to)
                self.assertEquals(response.body, body)

        server = EchoServer(Url(host="127.0.0.1", port=free_tcp_port()), self.timeout)
        server.start()
        server.wait()
        connection = BlockingConnection(server.url, timeout=self.timeout)
        client = SyncRequestResponse(connection)
        try:
            test("foo")         # Simple request/resposne
        finally:
            client.connection.close()
        server.join(timeout=self.timeout)
Beispiel #20
0
    def collect(self):
        collector_map = self.create_collector_map()
        fetcher_map = self.create_entity_map(collector_map)
        connection = None
        print("Collecting metrics")

        try:
            connection = BlockingConnection("amqps://" + self.router_host +
                                            ":" + str(self.router_port),
                                            30,
                                            None,
                                            self.ssl_domain,
                                            allowed_mechs=self.allowed_mechs,
                                            sasl_enabled=self.sasl_enabled,
                                            container_id="router-metrics")
            client = SyncRequestResponse(connection, "$management")
            for fetcher in fetcher_map:
                response = fetcher(client)
                if response != None:
                    for collector in fetcher_map[fetcher]:
                        for entity in response.get_results():
                            if response.contains(entity, collector.filter):
                                labels = []
                                for l in collector.labels:
                                    label_idx = response.get_index(l)
                                    if label_idx != None and entity[
                                            label_idx] != None:
                                        labels.append(entity[label_idx])
                                    else:
                                        labels.append("")
                                value = entity[response.get_index(
                                    collector.name)]
                                collector.add(labels, int(value))
        finally:
            if connection != None:
                connection.close()

        for collector in collector_map.itervalues():
            yield collector.metric()
Beispiel #21
0
class Node(object):
    """Client proxy for an AMQP management node"""
    @staticmethod
    def connection(url=None,
                   router=None,
                   timeout=10,
                   ssl_domain=None,
                   sasl=None):
        """Return a BlockingConnection suitable for connecting to a management node
        @param url: URL of the management node.
        @param router: If address does not contain a path, use the management node for this router ID.
            If not specified and address does not contain a path, use the default management node.
        """
        url = Url(url)  # Convert string to Url class.

        if url.path is None:
            if router:
                url.path = u'_topo/0/%s/$management' % router
            else:
                url.path = u'$management'

        if ssl_domain:
            sasl_enabled = True
        else:
            sasl_enabled = True if sasl else False

        # if sasl_mechanism is unicode, convert it to python string
        return BlockingConnection(
            url,
            timeout=timeout,
            ssl_domain=ssl_domain,
            sasl_enabled=sasl_enabled,
            allowed_mechs=str(sasl.mechs)
            if sasl and sasl.mechs != None else None,
            user=str(sasl.user) if sasl and sasl.user != None else None,
            password=str(sasl.password)
            if sasl and sasl.password != None else None)

    @staticmethod
    def connect(url=None, router=None, timeout=10, ssl_domain=None, sasl=None):
        """Return a Node connected with the given parameters, see L{connection}"""
        return Node(Node.connection(url, router, timeout, ssl_domain, sasl))

    def __init__(self, connection, locales=None):
        """
        Create a management node proxy using the given connection.
        @param locales: Default list of locales for management operations.
        @param connection: a L{BlockingConnection} to the management agent.
        """
        self.name = self.identity = u'self'
        self.type = u'org.amqp.management'  # AMQP management node type
        self.locales = locales

        self.locales = locales
        self.url = connection.url
        self.client = SyncRequestResponse(connection, self.url.path)
        self.reply_to = self.client.reply_to

    def close(self):
        """Shut down the node"""
        if self.client:
            self.client.connection.close()
            self.client = None

    def __repr__(self):
        return "%s(%s)" % (self.__class__.__name__, self.url)

    @staticmethod
    def check_response(response, expect=OK):
        """
        Check a management response message for errors and correlation ID.
        """
        code = response.properties.get(u'statusCode')
        if code != expect:
            if 200 <= code <= 299:
                raise ValueError(
                    "Response was %s(%s) but expected %s(%s): %s" %
                    (code, STATUS_TEXT[code], expect, STATUS_TEXT[expect],
                     response.properties.get(u'statusDescription')))
            else:
                raise ManagementError.create(
                    code, response.properties.get(u'statusDescription'))

    def request(self, body=None, **properties):
        """
        Make a L{proton.Message} containining a management request.
        @param body: The request body, a dict or list.
        @param properties: Keyword arguments for application-properties of the request.
        @return: L{proton.Message} containining the management request.
        """
        if self.locales: properties.setdefault(u'locales', self.locales)
        request = proton.Message()
        request.properties = clean_dict(properties)
        request.body = body or {}
        return request

    def node_request(self, body=None, **properties):
        """Construct a request for the managment node itself"""
        return self.request(body, name=self.name, type=self.type, **properties)

    def call(self, request, expect=OK):
        """
        Send a management request message, wait for a response.
        @return: Response message.
        """
        response = self.client.call(request)
        self.check_response(response, expect=expect)
        return response

    class QueryResponse(object):
        """
        Result returned by L{query}.
        @ivar attribute_names: List of attribute names for the results.
        @ivar results: list of lists of attribute values in same order as attribute_names
        """
        def __init__(self, node, attribute_names, results):
            """
            @param response: the respose message to a query.
            """
            self.node = node
            self.attribute_names = attribute_names
            self.results = results

        def iter_dicts(self, clean=False):
            """
            Return an iterator that yields a dictionary for each result.
            @param clean: if True remove any None values from returned dictionaries.
            """
            for r in self.results:
                if clean: yield clean_dict(zip(self.attribute_names, r))
                else: yield dict(zip(self.attribute_names, r))

        def iter_entities(self, clean=False):
            """
            Return an iterator that yields an L{Entity} for each result.
            @param clean: if True remove any None values from returned dictionaries.
            """
            for d in self.iter_dicts(clean=clean):
                yield Entity(self.node, d)

        def get_dicts(self, clean=False):
            """Results as list of dicts."""
            return [d for d in self.iter_dicts(clean=clean)]

        def get_entities(self, clean=False):
            """Results as list of entities."""
            return [d for d in self.iter_entities(clean=clean)]

        def __repr__(self):
            return "QueryResponse(attribute_names=%r, results=%r" % (
                self.attribute_names, self.results)

    def query(self, type=None, attribute_names=None, offset=None, count=None):
        """
        Send an AMQP management query message and return the response.
        At least one of type, attribute_names must be specified.
        @keyword type: The type of entity to query.
        @keyword attribute_names: A list of attribute names to query.
        @keyword offset: An integer offset into the list of results to return.
        @keyword count: A count of the maximum number of results to return.
        @return: A L{QueryResponse}
        """

        # There is a bug in proton (PROTON-1846) wherein we cannot ask for
        # too many rows. So, as a safety we are going to ask only for
        # MAX_ALLOWED_COUNT_PER_REQUEST. Since this is used by both qdstat
        # and qdmanage, we have determined that the optimal value for
        # MAX_ALLOWED_COUNT_PER_REQUEST is 700
        MAX_ALLOWED_COUNT_PER_REQUEST = 700

        response_results = []
        response_attr_names = []
        if offset is None:
            offset = 0

        if count is None:
            # count has not been specified. For each request the
            # maximum number of rows we can get without proton
            # failing is MAX_ALLOWED_COUNT_PER_REQUEST
            request_count = MAX_ALLOWED_COUNT_PER_REQUEST
        else:
            request_count = min(MAX_ALLOWED_COUNT_PER_REQUEST, count)

        while True:
            request = self.node_request(
                {u'attributeNames': attribute_names or []},
                operation=u'QUERY',
                entityType=type,
                offset=offset,
                count=request_count)

            response = self.call(request)

            if not response_attr_names:
                response_attr_names += response.body[u'attributeNames']

            response_results += response.body[u'results']

            if len(response.body[u'results']) < request_count:
                break

            if count:
                len_response_results = len(response_results)
                if count == len_response_results:
                    break

                if count - len_response_results < request_count:
                    request_count = count - len_response_results

            offset += request_count

        query_reponse = Node.QueryResponse(self, response_attr_names,
                                           response_results)
        return query_reponse

    def create(self, attributes=None, type=None, name=None):
        """
        Create an entity.
        type and name can be specified in the attributes.

        @param attributes: Attributes for the new entity.
        @param type: Type of entity to create.
        @param name: Name for the new entity.
        @return: Entity proxy for the new entity.
        """
        attributes = attributes or {}
        type = type or attributes.get(u'type')
        name = name or attributes.get(u'name')
        request = self.request(operation=u'CREATE',
                               type=type,
                               name=name,
                               body=attributes)
        return Entity(self, self.call(request, expect=CREATED).body)

    def read(self, type=None, name=None, identity=None):
        """
        Read an AMQP entity.
        If both name and identity are specified, only identity is used.

        @param type: Entity type.
        @param name: Entity name.
        @param identity: Entity identity.
        @return: An L{Entity}
        """
        if name and identity: name = None  # Only specify one
        request = self.request(operation=u'READ',
                               type=type,
                               name=name,
                               identity=identity)
        return Entity(self, self.call(request).body)

    def update(self, attributes, type=None, name=None, identity=None):
        """
        Update an entity with attributes.
        type, name and identity can be specified in the attributes.
        If both name and identity are specified, only identity is used.

        @param attributes: Attributes for the new entity.
        @param type: Entity type.
        @param name: Entity name.
        @param identity: Entity identity.
        @return: L{Entity} for the updated entity.

        """
        attributes = attributes or {}
        type = type or attributes.get(u'type')
        name = name or attributes.get(u'name')
        identity = identity or attributes.get(u'identity')
        if name and identity: name = None  # Only send one
        request = self.request(operation=U'UPDATE',
                               type=type,
                               name=name,
                               identity=identity,
                               body=attributes)
        return Entity(self, self.call(request).body)

    def delete(self, type=None, name=None, identity=None):
        """
        Delete the remote entity.
        If both name and identity are specified, only identity is used.

        @param type: Entity type.
        @param name: Entity name.
        @param identity: Entity identity.
        """
        if name and identity: name = None  # Only specify one
        request = self.request(operation=U'DELETE',
                               type=type,
                               name=name,
                               identity=identity)
        self.call(request, expect=NO_CONTENT)

    def get_types(self, type=None):
        return self.call(
            self.node_request(operation=u"GET-TYPES", entityType=type)).body

    def get_annotations(self, type=None):
        return self.call(
            self.node_request(operation=u"GET-ANNOTATIONS",
                              entityType=type)).body

    def get_attributes(self, type=None):
        return self.call(
            self.node_request(operation=u"GET-ATTRIBUTES",
                              entityType=type)).body

    def get_operations(self, type=None):
        return self.call(
            self.node_request(operation=u"GET-OPERATIONS",
                              entityType=type)).body

    def get_mgmt_nodes(self, type=None):
        return self.call(
            self.node_request(operation=u"GET-MGMT-NODES",
                              entityType=type)).body

    def get_log(self, limit=None, type=None):
        return self.call(
            self.node_request(operation=u"GET-LOG",
                              entityType=type,
                              limit=limit)).body
Beispiel #22
0
class RouterCollector(object):
    def __init__(self, router_host, router_port, cert_dir):
        self.router_host = router_host
        self.router_port = router_port
        self.cert_dir = cert_dir
        ssl_domain = None
        allowed_mechs = []
        sasl_enabled = False

        if self.cert_dir != None:
            ssl_domain = SSLDomain(SSLDomain.MODE_CLIENT)
            ssl_domain.set_trusted_ca_db(
                str(os.path.join(self.cert_dir, 'ca.crt')))
            ssl_domain.set_credentials(
                str(os.path.join(self.cert_dir, "tls.crt")),
                str(os.path.join(self.cert_dir, "tls.key")), None)
            ssl_domain.set_peer_authentication(SSLDomain.VERIFY_PEER)
            allowed_mechs = str("EXTERNAL")
            sasl_enabled = True

        self.client = SyncRequestResponse(
            BlockingConnection("amqps://" + self.router_host + ":" +
                               str(self.router_port),
                               30,
                               None,
                               ssl_domain,
                               allowed_mechs=allowed_mechs,
                               sasl_enabled=sasl_enabled), "$management")

    def create_collector_map(self):
        metrics = [
            MetricCollector('connectionCount',
                            'Number of connections to router', ['container']),
            MetricCollector('connectionCount',
                            'Total number of connections to router',
                            ['routerId'],
                            id="totalConnectionCount"),
            MetricCollector('linkCount', 'Number of links to router',
                            ['address']),
            MetricCollector('linkCount',
                            'Number of consumers to router', ['address'],
                            id="consumerCount",
                            filter={"linkDir": "out"}),
            MetricCollector('linkCount',
                            'Number of producers to router', ['address'],
                            id="producerCount",
                            filter={"linkDir": "in"}),
            MetricCollector('linkCount',
                            'Total number of links to router', ['routerId'],
                            id="totalLinkCount"),
            MetricCollector('addrCount',
                            'Number of addresses defined in router',
                            ['routerId']),
            MetricCollector('autoLinkCount',
                            'Number of auto links defined in router',
                            ['routerId']),
            MetricCollector('linkRouteCount',
                            'Number of link routers defined in router',
                            ['routerId']),
            MetricCollector('unsettledCount', 'Number of unsettled messages',
                            ['address']),
            MetricCollector('deliveryCount', 'Number of delivered messages',
                            ['address'], "COUNTER"),
            MetricCollector('releasedCount', 'Number of released messages',
                            ['address'], "COUNTER"),
            MetricCollector('rejectedCount', 'Number of rejected messages',
                            ['address'], "COUNTER"),
            MetricCollector('acceptedCount', 'Number of accepted messages',
                            ['address'], "COUNTER"),
            MetricCollector('undeliveredCount',
                            'Number of undelivered messages', ['address']),
            MetricCollector('capacity', 'Capacity of link', ['address'])
        ]
        m = {}
        for metric in metrics:
            m[metric.id] = metric
        return m

    def create_entity_map(self, collector_map):
        return {
            self.get_router: [
                collector_map['totalConnectionCount'],
                collector_map['totalLinkCount'], collector_map['addrCount'],
                collector_map['autoLinkCount'], collector_map['linkRouteCount']
            ],
            self.get_connections: [collector_map['connectionCount']],
            self.get_links: [
                collector_map['linkCount'], collector_map['unsettledCount'],
                collector_map['deliveryCount'], collector_map['releasedCount'],
                collector_map['rejectedCount'], collector_map['acceptedCount'],
                collector_map['undeliveredCount'], collector_map['capacity'],
                collector_map['consumerCount'], collector_map['producerCount']
            ]
        }

    def get_router(self):
        return self.collect_metric('org.apache.qpid.dispatch.router')

    def get_links(self):
        links = self.collect_metric('org.apache.qpid.dispatch.router.link')
        if links == None:
            return links

        connections = self.get_connections()
        if connections == None:
            return connections

        links.add_field_from("address", "owningAddr", clean_address)
        links.add_field("linkCount", 1)
        links.add_field_from(
            "container", "connectionId",
            lambda connection_id: get_container_from_connections(
                connection_id, connections))

        return links

    def get_connections(self):
        response = self.collect_metric('org.apache.qpid.dispatch.connection')
        if response == None:
            return response

        response.add_field("connectionCount", 1)
        return response

    def collect(self):
        collector_map = self.create_collector_map()
        fetcher_map = self.create_entity_map(collector_map)

        for fetcher in fetcher_map:
            response = fetcher()
            if response != None:
                for collector in fetcher_map[fetcher]:
                    for entity in response.get_results():
                        if response.contains(entity, collector.filter):
                            labels = []
                            for l in collector.labels:
                                label_idx = response.get_index(l)
                                if label_idx != None and entity[
                                        label_idx] != None:
                                    labels.append(entity[label_idx])
                                else:
                                    labels.append("")
                            value = entity[response.get_index(collector.name)]
                            collector.add(labels, int(value))

        for collector in collector_map.itervalues():
            yield collector.metric()

    def collect_metric(self, entityType):
        try:
            properties = {}
            properties["entityType"] = entityType
            properties["operation"] = "QUERY"
            properties["name"] = "self"
            message = Message(body=None, properties=properties)
            response = self.client.call(message)
            if response == None:
                return response
            else:
                return RouterResponse(response)
        except NameError as e:
            print("Error querying router for metrics: %s" % e)
            return None
Beispiel #23
0
from __future__ import print_function, unicode_literals

import optparse
from proton import Message, Url, ConnectionException, Timeout
from proton.utils import SyncRequestResponse, BlockingConnection
from proton.handlers import IncomingMessageHandler
import sys

parser = optparse.OptionParser(usage="usage: %prog [options]",
                               description="Send requests to the supplied address and print responses.")
parser.add_option("-a", "--address", default="localhost:5672/examples",
                  help="address to which messages are sent (default %default)")
parser.add_option("-t", "--timeout", type="float", default=5,
                  help="Give up after this time out (default %default)")
opts, args = parser.parse_args()

url = Url(opts.address)
client = SyncRequestResponse(BlockingConnection(url, timeout=opts.timeout), url.path)

try:
    REQUESTS= ["Twas brillig, and the slithy toves",
               "Did gire and gymble in the wabe.",
               "All mimsy were the borogroves,",
               "And the mome raths outgrabe."]
    for request in REQUESTS:
        response = client.call(Message(body=request))
        print("%s => %s" % (request, response.body))
finally:
    client.connection.close()

Beispiel #24
0
class QdrouterdClient(object):
    """
    Class to interface with the Qdrouterd AMQP 1.0 API
    """
    @staticmethod
    def connection(url=None, timeout=10, ssl_domain=None, sasl=None):
        """
        Return a BlockingConnection for connection to a managemenet node
        """
        url = Url(url)

        url.path = u'$management'

        if ssl_domain:
            sasl_enabled = True
        else:
            sasl_enabled = True if sasl else False

        return BlockingConnection(url,
                                  timeout=timeout,
                                  ssl_domain=ssl_domain,
                                  sasl_enabled=sasl_enabled,
                                  allowed_mechs=str(sasl.mechs) if sasl and sasl.mechs != None else None,
                                  user=str(sasl.user) if sasl else None,
                                  password=str(sasl.password) if sasl else None)

    @staticmethod
    def connect(url=None, timeout=10, ssl_domain=None, sasl=None):
        """
        Return a Node connected with the given parameters, see L{connection}
        """
        return QdrouterdClient(QdrouterdClient.connection(url, timeout, ssl_domain, sasl))      
        
    def __init__(self, connection):
        """
        Create a management client proxy using the given connection.
        """
        self.name = self.identity = u'self'
        self.type = u'org.amqp.management' # AMQP management node type
        self.url = connection.url
        self.client = SyncRequestResponse(connection, self.url.path)
        self.reply_to = self.client.reply_to

    def close(self):
        """
        Shut down the client
        """
        if self.client:
            self.client.connection.close()
            self.client = None

    def __repr__(self):
        return "%s(%s)"%(self.__class__.__name__, self.url)

    def request(self, body=None, **properties):
        """
        Make a L{proton.Message} containining a management request.
        """
        request = proton.Message()
        request.properties = properties
        request.body = body or {}
        return request

    def client_request(self, body=None, **properties):
        """
        Construct a request 
        """
        return self.request(body, name=self.name, type=self.type, **properties)

    def call(self, request):
        """
        Send a management request message, wait for a response.
        """
        response = self.client.call(request)
        return response

    class QueryResponse(object):
        """
        Result returned by L{query}.
        """
        def __init__(self, qdrouterd_client, attribute_names, results):
            """
            @param response: the respose message to a query.
            """
            self.qdrouterd_client = qdrouterd_client
            self.attribute_names = attribute_names
            self.results = results

        def iter_dicts(self, clean=False):
            """
            Return an iterator that yields a dictionary for each result.
            """
            for r in self.results:
                if clean: yield clean_dict(zip(self.attribute_names, r))
                else: yield dict(zip(self.attribute_names, r))

        def iter_entities(self, clean=False):
            """
            Return an iterator that yields an L{Entity} for each result.
            """
            for d in self.iter_dicts(clean=clean): yield Entity(d)
            
        def get_dicts(self, clean=False):
            """
            Results as list of dicts.
            """
            return [d for d in self.iter_dicts(clean=clean)]

        def get_entities(self, clean=False):
            """
            Results as list of entities.
            """
            return [d for d in self.iter_entities(clean=clean)]

        def __repr__(self):
            return "QueryResponse(attribute_names=%r, results=%r"%(self.attribute_names, self.results)

    def query(self, type=None, attribute_names=None, offset=None, count=None):
        """
        Send an AMQP management query message and return the response.
        At least one of type, attribute_names must be specified.
        """
        request = self.client_request(
            {u'attributeNames': attribute_names or []},
            operation=u'QUERY', entityType=type, offset=offset, count=count)

        response = self.call(request)
        return QdrouterdClient.QueryResponse(self, response.body[u'attributeNames'], response.body[u'results'])
Beispiel #25
0
class Node(object):
    """Client proxy for an AMQP management node"""

    @staticmethod
    def connection(url=None, router=None, timeout=10, ssl_domain=None):
        """Return a BlockingConnection suitable for connecting to a management node
        @param url: URL of the management node.
        @param router: If address does not contain a path, use the management node for this router ID.
            If not specified and address does not contain a path, use the default management node.
        """
        url = Url(url)          # Convert string to Url class.

        if url.path is None:
            if router:
                url.path = u'_topo/0/%s/$management' % router
            else:
                url.path = u'$management'

        return BlockingConnection(url, timeout=timeout, ssl_domain=ssl_domain)

    @staticmethod
    def connect(url=None, router=None, timeout=10, ssl_domain=None):
        """Return a Node connected with the given parameters, see L{connection}"""
        return Node(Node.connection(url, router, timeout, ssl_domain))

    def __init__(self, connection, locales=None):
        """
        Create a management node proxy using the given connection.
        @param locales: Default list of locales for management operations.
        @param connection: a L{BlockingConnection} to the management agent.
        """
        self.name = self.identity = u'self'
        self.type = u'org.amqp.management' # AMQP management node type
        self.locales = locales

        self.locales = locales
        self.url = connection.url
        self.client = SyncRequestResponse(connection, self.url.path)
        self.reply_to = self.client.reply_to

    def close(self):
        """Shut down the node"""
        if self.client:
            self.client.connection.close()
            self.client = None

    def __repr__(self):
        return "%s(%s)"%(self.__class__.__name__, self.url)

    @staticmethod
    def check_response(response, expect=OK):
        """
        Check a management response message for errors and correlation ID.
        """
        code = response.properties.get(u'statusCode')
        if code != expect:
            if 200 <= code <= 299:
                raise ValueError("Response was %s(%s) but expected %s(%s): %s" % (
                    code, STATUS_TEXT[code], expect, STATUS_TEXT[expect],
                    response.properties.get(u'statusDescription')))
            else:
                raise ManagementError.create(code, response.properties.get(u'statusDescription'))

    def request(self, body=None, **properties):
        """
        Make a L{proton.Message} containining a management request.
        @param body: The request body, a dict or list.
        @param properties: Keyword arguments for application-properties of the request.
        @return: L{proton.Message} containining the management request.
        """
        if self.locales: properties.setdefault(u'locales', self.locales)
        request = proton.Message()
        request.properties = clean_dict(properties)
        request.body = body or {}
        return request

    def node_request(self, body=None, **properties):
        """Construct a request for the managment node itself"""
        return self.request(body, name=self.name, type=self.type, **properties)

    def call(self, request, expect=OK):
        """
        Send a management request message, wait for a response.
        @return: Response message.
        """
        response = self.client.call(request)
        self.check_response(response, expect=expect)
        return response

    class QueryResponse(object):
        """
        Result returned by L{query}.
        @ivar attribute_names: List of attribute names for the results.
        @ivar results: list of lists of attribute values in same order as attribute_names
        """
        def __init__(self, node, attribute_names, results):
            """
            @param response: the respose message to a query.
            """
            self.node = node
            self.attribute_names = attribute_names
            self.results = results

        def iter_dicts(self, clean=False):
            """
            Return an iterator that yields a dictionary for each result.
            @param clean: if True remove any None values from returned dictionaries.
            """
            for r in self.results:
                if clean: yield clean_dict(zip(self.attribute_names, r))
                else: yield dict(zip(self.attribute_names, r))

        def iter_entities(self, clean=False):
            """
            Return an iterator that yields an L{Entity} for each result.
            @param clean: if True remove any None values from returned dictionaries.
            """
            for d in self.iter_dicts(clean=clean): yield Entity(self.node, d)

        def get_dicts(self, clean=False):
            """Results as list of dicts."""
            return [d for d in self.iter_dicts(clean=clean)]

        def get_entities(self, clean=False):
            """Results as list of entities."""
            return [d for d in self.iter_entities(clean=clean)]

        def __repr__(self):
            return "QueryResponse(attribute_names=%r, results=%r"%(self.attribute_names, self.results)

    def query(self, type=None, attribute_names=None, offset=None, count=None):
        """
        Send an AMQP management query message and return the response.
        At least one of type, attribute_names must be specified.
        @keyword type: The type of entity to query.
        @keyword attribute_names: A list of attribute names to query.
        @keyword offset: An integer offset into the list of results to return.
        @keyword count: A count of the maximum number of results to return.
        @return: A L{QueryResponse}
        """
        request = self.node_request(
            {u'attributeNames': attribute_names or []},
            operation=u'QUERY', entityType=type, offset=offset, count=count)

        response = self.call(request)
        return Node.QueryResponse(self, response.body[u'attributeNames'], response.body[u'results'])

    def create(self, attributes=None, type=None, name=None):
        """
        Create an entity.
        type and name can be specified in the attributes.

        @param attributes: Attributes for the new entity.
        @param type: Type of entity to create.
        @param name: Name for the new entity.
        @return: Entity proxy for the new entity.
        """
        attributes = attributes or {}
        type = type or attributes.get(u'type')
        name = name or attributes.get(u'name')
        request = self.request(operation=u'CREATE', type=type, name=name, body=attributes)
        return Entity(self, self.call(request, expect=CREATED).body)

    def read(self, type=None, name=None, identity=None):
        """
        Read an AMQP entity.
        If both name and identity are specified, only identity is used.

        @param type: Entity type.
        @param name: Entity name.
        @param identity: Entity identity.
        @return: An L{Entity}
        """
        if name and identity: name = None # Only specify one
        request = self.request(operation=u'READ', type=type, name=name, identity=identity)
        return Entity(self, self.call(request).body)

    def update(self, attributes, type=None, name=None, identity=None):
        """
        Update an entity with attributes.
        type, name and identity can be specified in the attributes.
        If both name and identity are specified, only identity is used.

        @param attributes: Attributes for the new entity.
        @param type: Entity type.
        @param name: Entity name.
        @param identity: Entity identity.
        @return: L{Entity} for the updated entity.

        """
        attributes = attributes or {}
        type = type or attributes.get(u'type')
        name = name or attributes.get(u'name')
        identity = identity or attributes.get(u'identity')
        if name and identity: name = None # Only send one
        request = self.request(operation=U'UPDATE', type=type, name=name,
                               identity=identity, body=attributes)
        return Entity(self, self.call(request).body)

    def delete(self, type=None, name=None, identity=None):
        """
        Delete the remote entity.
        If both name and identity are specified, only identity is used.

        @param type: Entity type.
        @param name: Entity name.
        @param identity: Entity identity.
        """
        if name and identity: name = None # Only specify one
        request = self.request(operation=U'DELETE', type=type, name=name,
                               identity=identity)
        self.call(request, expect=NO_CONTENT)

    def get_types(self, type=None):
        return self.call(self.node_request(operation=u"GET-TYPES", entityType=type)).body

    def get_annotations(self, type=None):
        return self.call(self.node_request(operation=u"GET-ANNOTATIONS", entityType=type)).body

    def get_attributes(self, type=None):
        return self.call(self.node_request(operation=u"GET-ATTRIBUTES", entityType=type)).body

    def get_operations(self, type=None):
        return self.call(self.node_request(operation=u"GET-OPERATIONS", entityType=type)).body

    def get_mgmt_nodes(self, type=None):
        return self.call(self.node_request(operation=u"GET-MGMT-NODES", entityType=type)).body

    def get_log(self, limit=None, type=None):
        return self.call(self.node_request(operation=u"GET-LOG", entityType=type, limit=limit)).body
Beispiel #26
0
 def set_client(self, url_path):
     if url_path:
         self.url.path = u'%s' % url_path
         self.client = SyncRequestResponse(self.connection, self.url.path)
Beispiel #27
0
parser = optparse.OptionParser(
    usage="usage: %prog [options]",
    description="Send requests to the supplied address and print responses.")
parser.add_option("-a",
                  "--address",
                  default="localhost:5672/examples",
                  help="address to which messages are sent (default %default)")
parser.add_option("-t",
                  "--timeout",
                  type="float",
                  default=5,
                  help="Give up after this time out (default %default)")
opts, args = parser.parse_args()

url = Url(opts.address)
client = SyncRequestResponse(BlockingConnection(url, timeout=opts.timeout),
                             url.path)

try:
    REQUESTS = [
        "Twas brillig, and the slithy toves",
        "Did gire and gymble in the wabe.", "All mimsy were the borogroves,",
        "And the mome raths outgrabe."
    ]
    for request in REQUESTS:
        response = client.call(Message(body=request))
        print "%s => %s" % (request, response.body)
finally:
    client.connection.close()
Beispiel #28
0
class MgmtClient(object):
    """
    Provides a synchronous API for management operations on a router.
    """
    def __init__(self, router_address, timeout, router_id=None, edge_id=None):
        """
        @param router_address: the network address of the router to manage.
        @param timeout: raise an error if a management operation blocks longer
        than timeout seconds.
        @param router_id: identity of remote router.  Use this if the router to
        be managed is not the router at router_address.  This can be used to
        access a remote router using a local router as a proxy.
        @param edge_id: like router_id except remote is an edge router.

        Note that router_id and edge_id are mutually exclusive
        """
        assert (not (edge_id and router_id))
        self._conn = BlockingConnection(router_address, timeout=timeout)
        if router_id:
            self._mgmt_address = u'_topo/0/%s/$management' % router_id
        elif edge_id:
            self._mgmt_address = u'_edge/%s/$management' % edge_id
        else:
            self._mgmt_address = u'$management'
        self._client = SyncRequestResponse(self._conn, self._mgmt_address)

    def close(self):
        if self._conn:
            try:
                self._conn.close()
            except Exception:
                pass
            self._conn = None

    def _request_msg(self, properties, body=None):
        """
        Create a management request message
        """
        req = Message()
        req.properties = properties
        req.body = body or {}
        return req

    def read(self, type, identity):
        """
        Return the entity of type 'type' with identity 'identity' as a map
        """
        request = self._request_msg(properties={
            u'operation': u'READ',
            u'type': type,
            u'identity': identity
        })
        try:
            response = self._client.call(request)
        except ProtonException:
            LOG.error("Read error - connection to router failed.")
            return None

        if response.properties.get(u'statusDescription') != 'OK':
            LOG.warning("Management read of type %s id %s failed: %s" % type,
                        identity, response.properties)
            return None

        return response.body

    def delete(self, type, identity):
        """
        Delete the configuration entry of type 'type' with identity 'identity'
        """
        request = self._request_msg(properties={
            u'operation': u'DELETE',
            u'type': type,
            u'identity': identity
        })
        try:
            response = self._client.call(request)
        except ProtonException:
            LOG.error("Delete error - connection to router failed.")
            return None

        status = response.properties.get(u'statusCode')
        if status != 204:  # delete failed
            LOG.warning("Management delete of type %s id %s failed: %s", type,
                        identity, response.properties)
            return status
        return None

    def query(self, type, attribute_names):
        """
        Query the router for all entities of type 'type'.  For each entity only
        return the values for the given attributes
        """
        class QueryIterator(object):
            """
            Helper object that provides an iterator over the results returned
            by the QUERY operation.

            Each iteration returns a single entity represented by a map of
            values keyed by the attribute name

            @param attribute_names: ordered list of attribute names returned by
            QUERY
            @param values: a list of ordered lists of values that correspond to
            a single entity.  The values are in the same order as attributes
            """
            def __init__(self, attribute_names, values):
                self._attribute_names = attribute_names
                self._values = values

            def __iter__(self):
                return self

            # for 2.x capatibility
            def next(self):
                return self.__next__()

            def __next__(self):
                try:
                    v = self._values.pop()
                except IndexError:
                    raise StopIteration
                return dict(zip(self._attribute_names, v))

        MAX_BATCH = 500  # limit per request message (see bug PROTON-1846)
        response_results = []
        response_attr_names = []
        offset = 0

        while True:
            request = self._request_msg(
                properties={
                    u'operation': u'QUERY',
                    u'entityType': type,
                    u'offset': offset,
                    u'count': MAX_BATCH
                },
                body={u'attributeNames': attribute_names})
            try:
                response = self._client.call(request)
            except ProtonException:
                LOG.error("Query error - connection to router failed.")
                return None

            if response.properties.get(u'statusDescription') != 'OK':
                LOG.warning("Management query for type %s failed: %s" % type,
                            response.properties)
                return None

            if not response_attr_names:
                response_attr_names.extend(response.body[u'attributeNames'])

            response_results.extend(response.body[u'results'])

            if len(response.body[u'results']) < MAX_BATCH:
                break

            offset += MAX_BATCH

        return QueryIterator(response_attr_names, response_results)