blob: a4c70db91f4a0d2e4eca8de6e61ee859cb48a21d [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 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())