#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os from optparse import OptionParser, OptionGroup import sys import locale import socket import re from proton import Messenger, Message, Timeout home = os.environ.get("QPID_DISPATCH_HOME", os.path.normpath("${QPID_DISPATCH_HOME_INSTALLED}")) sys.path.append(os.path.join(home, "python")) from qpid_dispatch_internal.tools import Display, Header, Sorter, YN, Commas, TimeLong class Config: def __init__(self): self._host = "0.0.0.0" self._connTimeout = 5 self._types = "" self._limit = 50 self._increasing = False self._sortcol = None config = Config() conn_options = {} def OptionsAndArguments(argv): """ Set global variables for options, return arguments """ global config global conn_options usage = \ """%prog -g [options] %prog -c [options] %prog -l [options] %prog -n [options] %prog -a [options] %prog -m [options]""" parser = OptionParser(usage=usage) group1 = OptionGroup(parser, "General Options") group1.add_option("-b", "--bus", action="store", type="string", default="0.0.0.0", metavar="", help="URL of the messaging bus to connect to") group1.add_option("-r", "--router", action="store", type="string", default=None, metavar="", help="Router to be queried") group1.add_option("-t", "--timeout", action="store", type="int", default=5, metavar="", help="Maximum time to wait for connection (in seconds)") group1.add_option("--sasl-mechanism", action="store", type="string", metavar="", help="SASL mechanism for authentication (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI). SASL automatically picks the most secure available mechanism - use this option to override.") group1.add_option("--ssl-certificate", action="store", type="string", metavar="", help="Client SSL certificate (PEM Format)") group1.add_option("--ssl-key", action="store", type="string", metavar="", help="Client SSL private key (PEM Format)") parser.add_option_group(group1) group2 = OptionGroup(parser, "Command Options") group2.add_option("-g", "--general", help="Show General Router Stats", action="store_const", const="g", dest="show") group2.add_option("-c", "--connections", help="Show Connections", action="store_const", const="c", dest="show") group2.add_option("-l", "--links", help="Show Router Links", action="store_const", const="l", dest="show") group2.add_option("-n", "--nodes", help="Show Router Nodes", action="store_const", const="n", dest="show") group2.add_option("-a", "--address", help="Show Router Addresses", action="store_const", const="a", dest="show") group2.add_option("-m", "--memory", help="Show Broker Memory Stats", action="store_const", const="m", dest="show") parser.add_option_group(group2) opts, args = parser.parse_args(args=argv) if not opts.show: parser.error("You must specify one of these options: -g, -c, -l, -n, -a, or -m. For details, try $ qdstat --help") config._types = opts.show config._host = opts.bus config._router = opts.router config._connTimeout = opts.timeout return args class BusManager: def __init__(self): pass def SetHost(self, host, router): self.M = Messenger() self.M.start() self.M.timeout = config._connTimeout self.M.route("amqp:/*", "amqp://%s/$1" % host) if router: self.address = "amqp:/_topo/0/%s/$management" % router else: self.address = "amqp:/_local/$management" self.subscription = self.M.subscribe("amqp:/#") self.reply = self.subscription.address def Disconnect(self): self.M.stop() def _get_object(self, cls): request = Message() response = Message() request.address = self.address request.reply_to = self.reply request.correlation_id = 1 request.properties = {u'operation':u'GET', u'type':cls} self.M.put(request) self.M.send() self.M.recv() self.M.get(response) return response.body def displayConnections(self): disp = Display(prefix=" ") heads = [] heads.append(Header("state")) heads.append(Header("host")) heads.append(Header("container")) heads.append(Header("sasl-mechanisms")) heads.append(Header("role")) heads.append(Header("dir")) rows = [] objects = self._get_object('org.apache.qpid.dispatch.connection') for conn in objects: row = [] row.append(conn['state']) row.append(conn['host']) row.append(conn['container']) row.append(conn['sasl']) row.append(conn['role']) row.append(conn['dir']) rows.append(row) title = "Connections" dispRows = rows disp.formattedTable(title, heads, dispRows) def _addr_class(self, addr): if not addr: return "-" if addr[0] == 'M' : return "mobile" if addr[0] == 'R' : return "router" if addr[0] == 'A' : return "area" if addr[0] == 'L' : return "local" return "unknown: %s" % addr[0] def _addr_text(self, addr): if not addr: return "-" return addr[1:] def displayGeneral(self): disp = Display(prefix=" ") heads = [] heads.append(Header("attr")) heads.append(Header("value")) rows = [] objects = self._get_object('org.apache.qpid.dispatch.router') router = objects[0] rows.append(('Mode', router['mode'])) rows.append(('Area', router['area'])) rows.append(('Router Id', router['router_id'])) rows.append(('Address Count', router['addr_count'])) rows.append(('Link Count', router['link_count'])) rows.append(('Node Count', router['node_count'])) title = "Router Statistics" dispRows = rows disp.formattedTable(title, heads, dispRows) def displayRouterLinks(self): disp = Display(prefix=" ") heads = [] heads.append(Header("type")) heads.append(Header("dir")) heads.append(Header("rindex")) heads.append(Header("class")) heads.append(Header("addr")) rows = [] objects = self._get_object('org.apache.qpid.dispatch.router.link') for link in objects: row = [] row.append(link['link-type']) row.append(link['link-dir']) if link['link-type'] == "inter-router": row.append(link['index']) else: row.append('-') row.append(self._addr_class(link['owning-addr'])) row.append(self._addr_text(link['owning-addr'])) rows.append(row) title = "Router Links" dispRows = rows disp.formattedTable(title, heads, dispRows) def displayRouterNodes(self): disp = Display(prefix=" ") heads = [] heads.append(Header("router-id")) heads.append(Header("next-hop")) heads.append(Header("link")) heads.append(Header("valid-origins")) rows = [] objects = self._get_object('org.apache.qpid.dispatch.router.node') attached = self._get_object('org.apache.qpid.dispatch.router')[0] nodes = {} for node in objects: nodes[node['index']] = node node['addr'] = self._addr_text(node['addr']) rows.append([attached['router_id'], '-', '(self)', '']) for node in objects: row = [] row.append(node['addr']) if node['next-hop'] != None: row.append(nodes[node['next-hop']]['addr']) else: row.append('-') if node['router-link'] != None: row.append(node['router-link']) else: row.append('-') vo = None for i in node['valid-origins']: if not vo: vo = "" else: vo += ", " vo += nodes[i]['addr'] row.append(vo) rows.append(row) title = "Router Nodes" sort = Sorter(heads, rows, 'router-id') dispRows = sort.getSorted() disp.formattedTable(title, heads, dispRows) def displayAddresses(self): disp = Display(prefix=" ") heads = [] heads.append(Header("class")) heads.append(Header("address")) heads.append(Header("in-proc", Header.Y)) heads.append(Header("local", Header.COMMAS)) heads.append(Header("remote", Header.COMMAS)) heads.append(Header("in", Header.COMMAS)) heads.append(Header("out", Header.COMMAS)) heads.append(Header("thru", Header.COMMAS)) heads.append(Header("to-proc", Header.COMMAS)) heads.append(Header("from-proc", Header.COMMAS)) rows = [] objects = self._get_object('org.apache.qpid.dispatch.router.address') for addr in objects: row = [] row.append(self._addr_class(addr['addr'])) row.append(self._addr_text(addr['addr'])) row.append(addr['in-process']) row.append(addr['subscriber-count']) row.append(addr['remote-count']) row.append(addr['deliveries-ingress']) row.append(addr['deliveries-egress']) row.append(addr['deliveries-transit']) row.append(addr['deliveries-to-container']) row.append(addr['deliveries-from-container']) rows.append(row) title = "Router Addresses" sorter = Sorter(heads, rows, 'address', 0, True) dispRows = sorter.getSorted() disp.formattedTable(title, heads, dispRows) def displayMemory(self): disp = Display(prefix=" ") heads = [] heads.append(Header("type")) heads.append(Header("size", Header.COMMAS)) heads.append(Header("batch")) heads.append(Header("thread-max", Header.COMMAS)) heads.append(Header("total", Header.COMMAS)) heads.append(Header("in-threads", Header.COMMAS)) heads.append(Header("rebal-in", Header.COMMAS)) heads.append(Header("rebal-out", Header.COMMAS)) rows = [] objects = self._get_object('org.apache.qpid.dispatch.allocator') for t in objects: row = [] row.append(t['name']) row.append(t['type_size']) row.append(t['transfer_batch_size']) row.append(t['local_free_list_max']) row.append(t['total_alloc_from_heap']) row.append(t['held_by_threads']) row.append(t['batches_rebalanced_to_threads']) row.append(t['batches_rebalanced_to_global']) rows.append(row) title = "Types" sorter = Sorter(heads, rows, 'type', 0, True) dispRows = sorter.getSorted() disp.formattedTable(title, heads, dispRows) def displayMain(self, names, main): if main == 'l': self.displayRouterLinks() elif main == 'n': self.displayRouterNodes() elif main == 'a': self.displayAddresses() elif main == 'm': self.displayMemory() elif main == 'g': self.displayGeneral() elif main == 'c': self.displayConnections() def display(self, names): self.displayMain(names, config._types) def main(argv=None): args = OptionsAndArguments(argv) bm = BusManager() try: bm.SetHost(config._host, config._router) bm.display(args) bm.Disconnect() return 0 except KeyboardInterrupt: print except Timeout: if config._router: print "No response from router %s after timeout" % config._router else: print "No response after timeout" except Exception,e: print "Failed: %s - %s" % (e.__class__.__name__, e) bm.Disconnect() return 1 if __name__ == "__main__": sys.exit(main())