| #!/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="<access-url>", |
| help="URL of the messaging bus to connect to") |
| group1.add_option("-r", "--router", action="store", type="string", default=None, metavar="<router-id>", help="Router to be queried") |
| group1.add_option("-t", "--timeout", action="store", type="int", default=5, metavar="<secs>", |
| help="Maximum time to wait for connection (in seconds)") |
| group1.add_option("--sasl-mechanism", action="store", type="string", metavar="<mech>", |
| 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="<cert>", help="Client SSL certificate (PEM Format)") |
| group1.add_option("--ssl-key", action="store", type="string", metavar="<key>", 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()) |