blob: 94c119629f8ca2a5d8b5890f124b6df2970193d5 [file] [log] [blame]
#!/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))