| #!/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 OptionGroup |
| import sys |
| import locale |
| import socket |
| import re |
| from time import ctime |
| import qpid_dispatch_site |
| from qpid_dispatch.management.client import Url, Node, Entity |
| from qpid_dispatch_internal.management.qdrouter import QdSchema |
| from qpid_dispatch_internal.tools import Display, Header, Sorter, YN, Commas, TimeLong |
| from qpid_dispatch_internal.tools.command import connection_options, main, OptionParser, opts_ssl_domain, opts_url |
| |
| def parse_args(argv): |
| """ Set global variables for options, return arguments """ |
| |
| usage = "%prog [options]" |
| |
| parser = OptionParser(usage=usage) |
| |
| parser.add_option_group(connection_options(parser)) |
| |
| parser.add_option("-g", "--general", help="Show General Router Stats", action="store_const", const="g", dest="show") |
| parser.add_option("-c", "--connections", help="Show Connections", action="store_const", const="c", dest="show") |
| parser.add_option("-l", "--links", help="Show Router Links", action="store_const", const="l", dest="show") |
| parser.add_option("-n", "--nodes", help="Show Router Nodes", action="store_const", const="n", dest="show") |
| parser.add_option("-a", "--address", help="Show Router Addresses", action="store_const", const="a", dest="show") |
| parser.add_option("-m", "--memory", help="Show Router Memory Stats", action="store_const", const="m", dest="show") |
| parser.add_option("--autolinks", help="Show Auto Links", action="store_const", const="autolinks", dest="show") |
| parser.add_option("--linkroutes", help="Show Link Routes", action="store_const", const="linkroutes", dest="show") |
| parser.add_option("-v", "--verbose", help="Show maximum detail", action="store_true", dest="verbose") |
| parser.add_option("--log", help="Show recent log entries", action="store_const", const="log", dest="show") |
| parser.add_option("--limit", help="Limit number of log entries", type="int") |
| |
| 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, -m, -h, --autolinks, --linkroutes, or --log.") |
| |
| return opts, args |
| |
| |
| class BusManager(Node): |
| |
| schema = QdSchema() |
| |
| def __init__(self, opts): |
| self.opts = opts |
| super(BusManager, self).__init__( |
| Node.connection(opts_url(opts), opts.router, timeout=opts.timeout, |
| ssl_domain=opts_ssl_domain(opts))) |
| |
| def query(self, entity_type): |
| return super(BusManager, self).query(entity_type).get_entities() |
| |
| def connAuth(self, conn): |
| ## |
| ## Summarize the authentication for a connection: |
| ## no-auth |
| ## anonymous-user |
| ## <user>(PLAIN) |
| ## <user>(kerberos) |
| ## <user>(x.509) |
| ## |
| if not conn.isAuthenticated: |
| return "no-auth" |
| sasl = conn.sasl |
| if sasl == "GSSAPI": sasl = "Kerberos" |
| if sasl == "EXTERNAL": sasl = "x.509" |
| if sasl == "ANONYMOUS": |
| return "anonymous-user" |
| return "%s(%s)" % (conn.user, sasl) |
| |
| def connSecurity(self, conn): |
| ## |
| ## Summarize the security of a connection: |
| ## no-security |
| ## SSLv3 (cipher) |
| ## TLS (cipher) |
| ## Kerberos |
| ## |
| if not conn.isEncrypted: |
| return "no-security" |
| if conn.sasl == "GSSAPI": |
| return "Kerberos" |
| return "%s(%s)" % (conn.sslProto, conn.sslCipher) |
| |
| def displayConnections(self): |
| disp = Display(prefix=" ") |
| heads = [] |
| heads.append(Header("host")) |
| heads.append(Header("container")) |
| heads.append(Header("role")) |
| heads.append(Header("dir")) |
| heads.append(Header("security")) |
| heads.append(Header("authentication")) |
| |
| rows = [] |
| |
| objects = self.query('org.apache.qpid.dispatch.connection') |
| |
| for conn in objects: |
| row = [] |
| row.append(conn.host) |
| row.append(conn.container) |
| row.append(conn.role) |
| row.append(conn.dir) |
| row.append(self.connSecurity(conn)) |
| row.append(self.connAuth(conn)) |
| rows.append(row) |
| title = "Connections" |
| dispRows = rows |
| disp.formattedTable(title, heads, dispRows) |
| |
| def _addr_summary(self, addr): |
| cls = self._addr_class(addr) |
| phase = self._addr_phase(addr) |
| text = self._addr_text(addr) |
| if cls == '-': |
| return "-" |
| if cls == 'M': |
| if phase == '0': |
| return text |
| else: |
| return "%s:%s" % (phase, text) |
| return "%s:%s" % (cls, text) |
| |
| |
| 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" |
| if addr[0] == 'T' : return "topo" |
| if addr[0] == 'C' : return "link-in" |
| if addr[0] == 'D' : return "link-out" |
| return "unknown: %s" % addr[0] |
| |
| def _addr_text(self, addr): |
| if not addr: |
| return "" |
| if addr[0] == 'M': |
| return addr[2:] |
| else: |
| return addr[1:] |
| |
| def _addr_phase(self, addr): |
| if not addr: |
| return "" |
| if addr[0] == 'M': |
| return addr[1] |
| return '' |
| |
| def _identity_clean(self, identity): |
| if not identity: |
| return "-" |
| pos = identity.find('/') |
| if pos >= 0: |
| return identity[pos + 1:] |
| return identity |
| |
| def _list_clean(self, inlist): |
| outlist = [] |
| for i in inlist: |
| outlist.append(str(i)) |
| return outlist |
| |
| def displayGeneral(self): |
| disp = Display(prefix=" ") |
| heads = [] |
| heads.append(Header("attr")) |
| heads.append(Header("value")) |
| rows = [] |
| |
| objects = self.query('org.apache.qpid.dispatch.router') |
| |
| router = objects[0] |
| rows.append(('Mode', router.mode)) |
| rows.append(('Area', router.area)) |
| rows.append(('Router Id', self._identity_clean(router.identity))) |
| rows.append(('Address Count', router.addrCount)) |
| rows.append(('Link Count', router.linkCount)) |
| rows.append(('Node Count', router.nodeCount)) |
| |
| 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("id")) |
| heads.append(Header("peer")) |
| heads.append(Header("class")) |
| heads.append(Header("addr")) |
| heads.append(Header("phs")) |
| heads.append(Header("cap")) |
| heads.append(Header("undel")) |
| heads.append(Header("unsettled")) |
| heads.append(Header("deliveries")) |
| heads.append(Header("admin")) |
| heads.append(Header("oper")) |
| if self.opts.verbose: |
| heads.append(Header("name")) |
| rows = [] |
| |
| objects = self.query('org.apache.qpid.dispatch.router.link') |
| |
| for link in objects: |
| row = [] |
| row.append(link.linkType) |
| row.append(link.linkDir) |
| row.append(link.identity) |
| row.append(link.peer) |
| row.append(self._addr_class(link.owningAddr)) |
| row.append(self._addr_text(link.owningAddr)) |
| row.append(self._addr_phase(link.owningAddr)) |
| row.append(link.capacity) |
| row.append(link.undeliveredCount) |
| row.append(link.unsettledCount) |
| row.append(link.deliveryCount) |
| row.append(link.adminStatus) |
| row.append(link.operStatus) |
| if self.opts.verbose: |
| row.append(link.linkName) |
| 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")) |
| if self.opts.verbose: |
| heads.append(Header("neighbors")) |
| heads.append(Header("valid-origins")) |
| rows = [] |
| |
| objects = self.query('org.apache.qpid.dispatch.router.node') |
| |
| for node in objects: |
| row = [] |
| row.append(node.routerId) |
| if node.nextHop != None: |
| row.append(node.nextHop) |
| row.append('-') |
| else: |
| row.append('-') |
| row.append(node.routerLink) |
| |
| if self.opts.verbose: |
| row.append('%r' % self._list_clean(node.linkState)) |
| row.append('%r' % self._list_clean(node.validOrigins)) |
| rows.append(row) |
| if len(rows) > 0: |
| title = "Routers in the Network" |
| sort = Sorter(heads, rows, 'router-id') |
| dispRows = sort.getSorted() |
| disp.formattedTable(title, heads, dispRows) |
| else: |
| print "Router is Standalone - No Router List" |
| |
| def displayAddresses(self): |
| disp = Display(prefix=" ") |
| heads = [] |
| heads.append(Header("class")) |
| heads.append(Header("addr")) |
| heads.append(Header("phs")) |
| heads.append(Header("distrib")) |
| heads.append(Header("in-proc", Header.COMMAS)) |
| heads.append(Header("local", Header.COMMAS)) |
| heads.append(Header("remote", Header.COMMAS)) |
| heads.append(Header("cntnr", 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.query('org.apache.qpid.dispatch.router.address') |
| |
| for addr in objects: |
| row = [] |
| row.append(self._addr_class(addr.name)) |
| row.append(self._addr_text(addr.name)) |
| row.append(self._addr_phase(addr.name)) |
| row.append(addr.distribution) |
| row.append(addr.inProcess) |
| row.append(addr.subscriberCount) |
| row.append(addr.remoteCount) |
| row.append(addr.containerCount) |
| row.append(addr.deliveriesIngress) |
| row.append(addr.deliveriesEgress) |
| row.append(addr.deliveriesTransit) |
| row.append(addr.deliveriesToContainer) |
| row.append(addr.deliveriesFromContainer) |
| rows.append(row) |
| title = "Router Addresses" |
| sorter = Sorter(heads, rows, 'addr', 0, True) |
| dispRows = sorter.getSorted() |
| disp.formattedTable(title, heads, dispRows) |
| |
| def displayAutolinks(self): |
| disp = Display(prefix=" ") |
| heads = [] |
| heads.append(Header("addr")) |
| heads.append(Header("dir")) |
| heads.append(Header("phase")) |
| heads.append(Header("link")) |
| heads.append(Header("status")) |
| heads.append(Header("lastErr")) |
| rows = [] |
| |
| objects = self.query('org.apache.qpid.dispatch.router.config.autoLink') |
| |
| for al in objects: |
| row = [] |
| row.append(al.addr) |
| row.append(al.dir) |
| row.append(al.phase) |
| row.append(al.linkRef) |
| row.append(al.operStatus) |
| row.append(al.lastError) |
| rows.append(row) |
| title = "AutoLinks" |
| sorter = Sorter(heads, rows, 'addr', 0, True) |
| dispRows = sorter.getSorted() |
| disp.formattedTable(title, heads, dispRows) |
| |
| def displayLinkRoutes(self): |
| disp = Display(prefix=" ") |
| heads = [] |
| heads.append(Header("prefix")) |
| heads.append(Header("dir")) |
| heads.append(Header("distrib")) |
| rows = [] |
| |
| link_routes = self.query('org.apache.qpid.dispatch.router.config.linkRoute') |
| |
| for link_route in link_routes: |
| row = [] |
| row.append(link_route.prefix) |
| row.append(link_route.dir) |
| row.append(link_route.distribution) |
| rows.append(row) |
| title = "Link Routes" |
| sorter = Sorter(heads, rows, 'prefix', 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.query('org.apache.qpid.dispatch.allocator') |
| |
| for t in objects: |
| row = [] |
| row.append(self._identity_clean(t.identity)) |
| row.append(t.typeSize) |
| row.append(t.transferBatchSize) |
| row.append(t.localFreeListMax) |
| row.append(t.totalAllocFromHeap) |
| row.append(t.heldByThreads) |
| row.append(t.batchesRebalancedToThreads) |
| row.append(t.batchesRebalancedToGlobal) |
| rows.append(row) |
| if not rows: |
| # router built w/o memory pools: |
| print "No memory statistics available" |
| return |
| title = "Types" |
| sorter = Sorter(heads, rows, 'type', 0, True) |
| dispRows = sorter.getSorted() |
| disp.formattedTable(title, heads, dispRows) |
| |
| def displayLog(self): |
| log = self.get_log(limit=self.opts.limit) |
| for line in log: |
| print "%s %s (%s) %s" % (ctime(line[5]), line[0], line[1], line[2]) |
| |
| def displayMain(self, identitys, 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() |
| elif main == 'autolinks': self.displayAutolinks() |
| elif main == 'linkroutes': self.displayLinkRoutes() |
| elif main == 'log': self.displayLog() |
| |
| def display(self, identitys): |
| self.displayMain(identitys, self.opts.show) |
| |
| def run(argv): |
| opts, args = parse_args(argv) |
| if args[1:]: |
| raise Exception("Unexpected arguments: %s" % " ".join(args[1:])) |
| bm = BusManager(opts) |
| try: |
| bm.display(args) |
| finally: |
| bm.close() |
| |
| if __name__ == "__main__": |
| sys.exit(main(run, sys.argv)) |