|
#!/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. |
|
# |
|
|
|
from optparse import OptionParser, OptionGroup, IndentedHelpFormatter |
|
import sys |
|
import os |
|
import locale |
|
from qmf.console import Session, BrokerURL |
|
from time import sleep |
|
|
|
usage = """ |
|
Usage: qpid-route [OPTIONS] dynamic add <dest-broker> <src-broker> <exchange> [tag] [exclude-list] [mechanism] |
|
qpid-route [OPTIONS] dynamic del <dest-broker> <src-broker> <exchange> |
|
|
|
qpid-route [OPTIONS] route add <dest-broker> <src-broker> <exchange> <routing-key> [tag] [exclude-list] [mechanism] |
|
qpid-route [OPTIONS] route del <dest-broker> <src-broker> <exchange> <routing-key> |
|
qpid-route [OPTIONS] queue add <dest-broker> <src-broker> <exchange> <queue> [mechanism] |
|
qpid-route [OPTIONS] queue del <dest-broker> <src-broker> <exchange> <queue> |
|
qpid-route [OPTIONS] route list [<dest-broker>] |
|
qpid-route [OPTIONS] route flush [<dest-broker>] |
|
qpid-route [OPTIONS] route map [<broker>] |
|
|
|
qpid-route [OPTIONS] link add <dest-broker> <src-broker> [mechanism] |
|
qpid-route [OPTIONS] link del <dest-broker> <src-broker> |
|
qpid-route [OPTIONS] link list [<dest-broker>]""" |
|
|
|
description = """ |
|
ADDRESS syntax: |
|
|
|
[username/password@] hostname |
|
ip-address [:<port>]""" |
|
|
|
def Usage(): |
|
print usage |
|
|
|
class Config: |
|
def __init__(self): |
|
self._verbose = False |
|
self._quiet = False |
|
self._durable = False |
|
self._dellink = False |
|
self._srclocal = False |
|
self._transport = "tcp" |
|
self._ack = 0 |
|
self._credit = 0xFFFFFFFF # unlimited |
|
self._connTimeout = 10 |
|
self._conn_options = {} |
|
|
|
config = Config() |
|
|
|
class JHelpFormatter(IndentedHelpFormatter): |
|
"""Format usage and description without stripping newlines from usage strings |
|
""" |
|
|
|
def format_usage(self, usage): |
|
return usage |
|
|
|
|
|
def format_description(self, description): |
|
if description: |
|
return description + "\n" |
|
else: |
|
return "" |
|
|
|
def OptionsAndArguments(argv): |
|
parser = OptionParser(usage=usage, |
|
description=description, |
|
formatter=JHelpFormatter()) |
|
|
|
parser.add_option("--timeout", action="store", type="int", default=10, metavar="<secs>", help="Maximum time to wait for broker connection (in seconds)") |
|
parser.add_option("-v", "--verbose", action="store_true", help="Verbose output") |
|
parser.add_option("-q", "--quiet", action="store_true", help="Quiet output, don't print duplicate warnings") |
|
parser.add_option("-d", "--durable", action="store_true", help="Added configuration shall be durable") |
|
|
|
parser.add_option("-e", "--del-empty-link", action="store_true", help="Delete link after deleting last route on the link") |
|
parser.add_option("-s", "--src-local", action="store_true", help="Make connection to source broker (push route)") |
|
|
|
parser.add_option("--ack", action="store", type="int", metavar="<n>", help="Acknowledge transfers over the bridge in batches of N") |
|
parser.add_option("--credit", action="store", type="int", default=0xFFFFFFFF, metavar="<msgs>", |
|
help="Maximum number of messages a sender can have outstanding (0=unlimited)") |
|
parser.add_option("-t", "--transport", action="store", type="string", default="tcp", metavar="<transport>", help="Transport to use for links, defaults to tcp") |
|
|
|
parser.add_option("--client-sasl-mechanism", action="store", type="string", metavar="<mech>", help="SASL mechanism for authentication (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI). Used when the client connects to the destination broker (not for authentication between the source and destination brokers - that is specified using the [mechanisms] argument to 'add route'). SASL automatically picks the most secure available mechanism - use this option to override.") |
|
parser.add_option("--sasl-service-name", action="store", type="string", help="SASL service name to use") |
|
parser.add_option("--ssl-certificate", action="store", type="string", metavar="<cert>", help="Client SSL certificate (PEM Format)") |
|
parser.add_option("--ssl-key", action="store", type="string", metavar="<key>", help="Client SSL private key (PEM Format)") |
|
parser.add_option("--ha-admin", action="store_true", help="Allow connection to a HA backup broker.") |
|
opts, encArgs = parser.parse_args(args=argv) |
|
|
|
try: |
|
encoding = locale.getpreferredencoding() |
|
args = [a.decode(encoding) for a in encArgs] |
|
except: |
|
args = encArgs |
|
|
|
if opts.timeout: |
|
config._connTimeout = opts.timeout |
|
if config._connTimeout == 0: |
|
config._connTimeout = None |
|
|
|
if opts.verbose: |
|
config._verbose = True |
|
|
|
if opts.quiet: |
|
config._quiet = True |
|
|
|
if opts.durable: |
|
config._durable = True |
|
|
|
if opts.del_empty_link: |
|
config._dellink = True |
|
|
|
if opts.src_local: |
|
config._srclocal = True |
|
|
|
if opts.transport: |
|
config._transport = opts.transport |
|
|
|
if opts.ha_admin: |
|
config._conn_options['client_properties'] = {'qpid.ha-admin' : 1} |
|
|
|
if opts.ack: |
|
config._ack = opts.ack |
|
|
|
config._credit = opts.credit |
|
|
|
if opts.client_sasl_mechanism: |
|
config._conn_options['mechanisms'] = opts.client_sasl_mechanism |
|
if opts.sasl_service_name: |
|
config._conn_options['service'] = opts.sasl_service_name |
|
|
|
if opts.ssl_certificate: |
|
config._conn_options['ssl_certfile'] = opts.ssl_certificate |
|
|
|
if opts.ssl_key: |
|
if not opts.ssl_certificate: |
|
parser.error("missing '--ssl-certificate' (required by '--ssl-key')") |
|
config._conn_options['ssl_keyfile'] = opts.ssl_key |
|
|
|
return args |
|
|
|
|
|
class RouteManager: |
|
def __init__(self, localBroker): |
|
self.brokerList = {} |
|
self.local = BrokerURL(localBroker) |
|
self.remote = None |
|
self.qmf = Session() |
|
self.broker = self.qmf.addBroker(localBroker, config._connTimeout, **config._conn_options) |
|
self.broker._waitForStable() |
|
self.agent = self.broker.getBrokerAgent() |
|
|
|
def disconnect(self): |
|
try: |
|
if self.broker: |
|
self.qmf.delBroker(self.broker) |
|
self.broker = None |
|
while len(self.brokerList): |
|
b = self.brokerList.popitem() |
|
if b[0] != self.local.name(): |
|
self.qmf.delBroker(b[1]) |
|
except: |
|
pass # ignore errors while shutting down |
|
|
|
def getLink(self): |
|
links = self.agent.getObjects(_class="link") |
|
for link in links: |
|
if self.remote.match(link.host, link.port): |
|
return link |
|
return None |
|
|
|
def getLinkName(self, link): |
|
for prop, value in link.getProperties(): |
|
if prop.name == "name": |
|
return value |
|
return None |
|
|
|
def checkLink(self, link): |
|
if not config._quiet: |
|
retry = 3 |
|
while link is None or (link.state in ("Waiting", "Connecting", "Closing") and retry > 0): |
|
sleep(1) |
|
link = self.getLink() |
|
retry -= 1 |
|
|
|
if link == None: |
|
raise Exception("Link failed to create") |
|
|
|
if link.state == "Failed": |
|
raise Exception("Link failed to create %s" % (link.lastError or "")) |
|
elif config._verbose: |
|
print "Link state is", link.state |
|
|
|
def addLink(self, remoteBroker, interbroker_mechanism=""): |
|
self.remote = BrokerURL(remoteBroker) |
|
if self.local.match(self.remote.host, self.remote.port): |
|
raise Exception("Linking broker to itself is not permitted") |
|
|
|
brokers = self.agent.getObjects(_class="broker") |
|
broker = brokers[0] |
|
link = self.getLink() |
|
if link == None: |
|
res = broker.connect(self.remote.host, self.remote.port, config._durable, |
|
interbroker_mechanism, self.remote.authName or "", self.remote.authPass or "", |
|
config._transport) |
|
|
|
def delLink(self, remoteBroker): |
|
self.remote = BrokerURL(remoteBroker) |
|
brokers = self.agent.getObjects(_class="broker") |
|
broker = brokers[0] |
|
link = self.getLink() |
|
if link == None: |
|
raise Exception("Link not found") |
|
|
|
res = link.close() |
|
if config._verbose: |
|
print "Close method returned:", res.status, res.text |
|
|
|
def listLinks(self): |
|
links = self.agent.getObjects(_class="link") |
|
if len(links) == 0: |
|
print "No Links Found" |
|
else: |
|
print |
|
print "Host Port Transport Durable State Last Error" |
|
print "=============================================================================" |
|
for link in links: |
|
print "%-16s%-8d%-13s%c %-18s%s" % \ |
|
(link.host, link.port, link.transport, YN(link.durable), link.state, link.lastError) |
|
|
|
def mapRoutes(self): |
|
print |
|
print "Finding Linked Brokers:" |
|
|
|
self.brokerList[self.local.name()] = self.broker |
|
print " %s:%s... Ok" % (self.local.host, self.local.port) |
|
|
|
added = True |
|
while added: |
|
added = False |
|
links = self.qmf.getObjects(_class="link") |
|
for link in links: |
|
url = BrokerURL(host=link.host, port=link.port, user=self.broker.authUser, password=self.broker.authPass) |
|
if url.name() not in self.brokerList: |
|
print " %s:%s..." % (link.host, link.port) |
|
try: |
|
url.authName = self.local.authName |
|
url.authPass = self.local.authPass |
|
b = self.qmf.addBroker(url, config._connTimeout, **config._conn_options) |
|
self.brokerList[url.name()] = b |
|
added = True |
|
print "Ok" |
|
except Exception, e: |
|
print e |
|
|
|
print |
|
print "Dynamic Routes:" |
|
bridges = self.qmf.getObjects(_class="bridge", dynamic=True) |
|
fedExchanges = [] |
|
for bridge in bridges: |
|
if bridge.src not in fedExchanges: |
|
fedExchanges.append(bridge.src) |
|
if len(fedExchanges) == 0: |
|
print " none found" |
|
print |
|
|
|
for ex in fedExchanges: |
|
print " Exchange %s:" % ex |
|
pairs = [] |
|
for bridge in bridges: |
|
if bridge.src == ex: |
|
link = bridge._linkRef_ |
|
fromUrl = BrokerURL(host=link.host, port=link.port) |
|
toUrl = bridge.getBroker().getUrl() |
|
found = False |
|
for pair in pairs: |
|
if pair.matches(fromUrl, toUrl): |
|
found = True |
|
if not found: |
|
pairs.append(RoutePair(fromUrl, toUrl)) |
|
for pair in pairs: |
|
print " %s" % pair |
|
print |
|
|
|
print "Static Routes:" |
|
bridges = self.qmf.getObjects(_class="bridge", dynamic=False) |
|
if len(bridges) == 0: |
|
print " none found" |
|
print |
|
|
|
for bridge in bridges: |
|
link = bridge._linkRef_ |
|
fromUrl = "%s:%s" % (link.host, link.port) |
|
toUrl = bridge.getBroker().getUrl() |
|
leftType = "ex" |
|
rightType = "ex" |
|
if bridge.srcIsLocal: |
|
arrow = "=>" |
|
left = bridge.src |
|
right = bridge.dest |
|
if bridge.srcIsQueue: |
|
leftType = "queue" |
|
else: |
|
arrow = "<=" |
|
left = bridge.dest |
|
right = bridge.src |
|
if bridge.srcIsQueue: |
|
rightType = "queue" |
|
|
|
if bridge.srcIsQueue: |
|
print " %s(%s=%s) %s %s(%s=%s)" % \ |
|
(toUrl, leftType, left, arrow, fromUrl, rightType, right) |
|
else: |
|
print " %s(%s=%s) %s %s(%s=%s) key=%s" % \ |
|
(toUrl, leftType, left, arrow, fromUrl, rightType, right, bridge.key) |
|
print |
|
|
|
while len(self.brokerList): |
|
b = self.brokerList.popitem() |
|
if b[0] != self.local.name(): |
|
self.qmf.delBroker(b[1]) |
|
|
|
def addBridge(self, link, src, dest, key, tag, excludes, srcIsQueue, srcIsLocal, |
|
durable, dynamic, sync, credit): |
|
bridges = self.agent.getObjects(_class="bridge") |
|
for bridge in bridges: |
|
if bridge.linkRef == link.getObjectId() and \ |
|
bridge.dest == dest and bridge.src == src and bridge.srcIsQueue == srcIsQueue and \ |
|
bridge.key == key and bridge.srcIsLocal == srcIsLocal and bridge.dynamic == dynamic: |
|
if not config._quiet: |
|
raise Exception("Duplicate Route - ignoring: %s(%s)" % (dest, key or src)) |
|
sys.exit(0) |
|
|
|
if config._verbose: |
|
print "Creating inter-broker binding..." |
|
|
|
linkName = self.getLinkName(link) |
|
# Don't put <linkName> first in the bridge name as the "qpid." prefix will be rejected by the broker |
|
name = "%s:%s:%s:%s:%s" % (dest, key or src, linkName, srcIsQueue, srcIsLocal) |
|
|
|
brokers = self.agent.getObjects(_class="broker") |
|
broker = brokers[0] |
|
properties = {"link" : linkName, |
|
"src" : src, |
|
"dest" : dest, |
|
"key" : key, |
|
"tag" : tag, |
|
"excludes" : excludes, |
|
"srcIsQueue" : srcIsQueue, |
|
"srcIsLocal" : srcIsLocal, |
|
"durable" : durable, |
|
"dynamic" : dynamic, |
|
"sync" : sync, |
|
"credit" : credit } |
|
# Broker also decodes "queue", which is used by the bridge instead of creating a new one. However it is not a |
|
# Bridge property in the QMF schema so is omitted here. |
|
|
|
res = broker.create("bridge", name, properties, False) |
|
if res.status != 0: |
|
raise Exception(res.text) |
|
if config._verbose: |
|
print "Bridge method returned:", res.status, res.text |
|
|
|
def addRoute(self, remoteBroker, exchange, routingKey, tag, excludes, interbroker_mechanism="", dynamic=False): |
|
if dynamic and config._srclocal: |
|
raise Exception("--src-local is not permitted on dynamic routes") |
|
|
|
self.addLink(remoteBroker, interbroker_mechanism) |
|
link = self.getLink() |
|
self.checkLink(link) |
|
|
|
self.addBridge(link, exchange, exchange, routingKey, tag, |
|
excludes, False, config._srclocal, config._durable, dynamic, |
|
config._ack, config._credit) |
|
|
|
def addQueueRoute(self, remoteBroker, interbroker_mechanism, exchange, queue): |
|
self.addLink(remoteBroker, interbroker_mechanism) |
|
link = self.getLink() |
|
self.checkLink(link) |
|
|
|
self.addBridge(link, queue, exchange, "", "", "", True, config._srclocal, config._durable, False, |
|
config._ack, config._credit) |
|
|
|
def delQueueRoute(self, remoteBroker, exchange, queue): |
|
self.remote = BrokerURL(remoteBroker) |
|
link = self.getLink() |
|
if link == None: |
|
if not config._quiet: |
|
raise Exception("No link found from %s to %s" % (self.remote.name(), self.local.name())) |
|
sys.exit(0) |
|
|
|
bridges = self.agent.getObjects(_class="bridge") |
|
for bridge in bridges: |
|
if bridge.linkRef == link.getObjectId() and \ |
|
bridge.dest == exchange and bridge.src == queue and bridge.srcIsQueue and \ |
|
bridge.srcIsLocal == config._srclocal: |
|
if config._verbose: |
|
print "Closing bridge..." |
|
res = bridge.close() |
|
if res.status != 0: |
|
raise Exception("Error closing bridge: %d - %s" % (res.status, res.text)) |
|
if len(bridges) == 1 and config._dellink: |
|
if config._verbose: |
|
print "Last bridge on link, closing link..." |
|
res = link.close() |
|
if res.status != 0: |
|
raise Exception("Error closing link: %d - %s" % (res.status, res.text)) |
|
sys.exit(0) |
|
if not config._quiet: |
|
raise Exception("Route not found") |
|
|
|
def delRoute(self, remoteBroker, exchange, routingKey, dynamic=False): |
|
self.remote = BrokerURL(remoteBroker) |
|
link = self.getLink() |
|
if link == None: |
|
if not config._quiet: |
|
raise Exception("No link found from %s to %s" % (self.remote.name(), self.local.name())) |
|
sys.exit(0) |
|
|
|
bridges = self.agent.getObjects(_class="bridge") |
|
for bridge in bridges: |
|
if bridge.linkRef == link.getObjectId() and bridge.dest == exchange and bridge.key == routingKey \ |
|
and not bridge.srcIsQueue and bridge.dynamic == dynamic and bridge.srcIsLocal == config._srclocal: |
|
if config._verbose: |
|
print "Closing bridge..." |
|
res = bridge.close() |
|
if res.status != 0: |
|
raise Exception("Error closing bridge: %d - %s" % (res.status, res.text)) |
|
if len(bridges) == 1 and config._dellink: |
|
if config._verbose: |
|
print "Last bridge on link, closing link..." |
|
res = link.close() |
|
if res.status != 0: |
|
raise Exception("Error closing link: %d - %s" % (res.status, res.text)) |
|
return |
|
if not config._quiet: |
|
raise Exception("Route not found") |
|
|
|
def listRoutes(self): |
|
links = self.qmf.getObjects(_class="link") |
|
bridges = self.qmf.getObjects(_class="bridge") |
|
|
|
for bridge in bridges: |
|
myLink = None |
|
for link in links: |
|
if bridge.linkRef == link.getObjectId(): |
|
myLink = link |
|
break |
|
if myLink != None: |
|
if bridge.dynamic: |
|
keyText = "<dynamic>" |
|
else: |
|
keyText = bridge.key or bridge.src |
|
print "%s %s:%d %s %10s %s" % (self.local.name(), myLink.host, myLink.port, bridge.dest, keyText, |
|
bridge.srcIsLocal) |
|
|
|
def clearAllRoutes(self): |
|
links = self.qmf.getObjects(_class="link") |
|
bridges = self.qmf.getObjects(_class="bridge") |
|
|
|
for bridge in bridges: |
|
if config._verbose: |
|
myLink = None |
|
for link in links: |
|
if bridge.linkRef == link.getObjectId(): |
|
myLink = link |
|
break |
|
if myLink != None: |
|
print "Deleting Bridge: %s:%d %s %s... " % (myLink.host, myLink.port, bridge.dest, bridge.key), |
|
res = bridge.close() |
|
if res.status != 0: |
|
print "Error: %d - %s" % (res.status, res.text) |
|
elif config._verbose: |
|
print "Ok" |
|
|
|
if config._dellink: |
|
links = self.qmf.getObjects(_class="link") |
|
for link in links: |
|
if config._verbose: |
|
print "Deleting Link: %s:%d... " % (link.host, link.port), |
|
res = link.close() |
|
if res.status != 0: |
|
print "Error: %d - %s" % (res.status, res.text) |
|
elif config._verbose: |
|
print "Ok" |
|
|
|
class RoutePair: |
|
def __init__(self, fromUrl, toUrl): |
|
self.fromUrl = fromUrl |
|
self.toUrl = toUrl |
|
self.bidir = False |
|
|
|
def __repr__(self): |
|
if self.bidir: |
|
delimit = "<=>" |
|
else: |
|
delimit = " =>" |
|
return "%s %s %s" % (self.fromUrl, delimit, self.toUrl) |
|
|
|
def matches(self, fromUrl, toUrl): |
|
if fromUrl == self.fromUrl and toUrl == self.toUrl: |
|
return True |
|
if toUrl == self.fromUrl and fromUrl == self.toUrl: |
|
self.bidir = True |
|
return True |
|
return False |
|
|
|
|
|
def YN(val): |
|
if val == 1: |
|
return 'Y' |
|
return 'N' |
|
|
|
|
|
def main(argv=None): |
|
|
|
args = OptionsAndArguments(argv) |
|
nargs = len(args) |
|
if nargs < 2: |
|
Usage() |
|
return(-1) |
|
|
|
if nargs == 2: |
|
localBroker = "localhost" |
|
else: |
|
if config._srclocal: |
|
localBroker = args[3] |
|
remoteBroker = args[2] |
|
else: |
|
localBroker = args[2] |
|
if nargs > 3: |
|
remoteBroker = args[3] |
|
|
|
group = args[0] |
|
cmd = args[1] |
|
|
|
rm = None |
|
try: |
|
rm = RouteManager(localBroker) |
|
if group == "link": |
|
if cmd == "add": |
|
if nargs < 3 or nargs > 5: |
|
Usage() |
|
return(-1) |
|
interbroker_mechanism = "" |
|
if nargs > 4: interbroker_mechanism = args[4] |
|
rm.addLink(remoteBroker, interbroker_mechanism) |
|
rm.checkLink(rm.getLink()) |
|
elif cmd == "del": |
|
if nargs != 4: |
|
Usage() |
|
return(-1) |
|
rm.delLink(remoteBroker) |
|
elif cmd == "list": |
|
rm.listLinks() |
|
|
|
elif group == "dynamic": |
|
if cmd == "add": |
|
if nargs < 5 or nargs > 8: |
|
Usage() |
|
return(-1) |
|
|
|
tag = "" |
|
excludes = "" |
|
interbroker_mechanism = "" |
|
if nargs > 5: tag = args[5] |
|
if nargs > 6: excludes = args[6] |
|
if nargs > 7: interbroker_mechanism = args[7] |
|
rm.addRoute(remoteBroker, args[4], "", tag, excludes, interbroker_mechanism, dynamic=True) |
|
elif cmd == "del": |
|
if nargs != 5: |
|
Usage() |
|
return(-1) |
|
else: |
|
rm.delRoute(remoteBroker, args[4], "", dynamic=True) |
|
|
|
elif group == "route": |
|
if cmd == "add": |
|
if nargs < 6 or nargs > 9: |
|
Usage() |
|
return(-1) |
|
|
|
tag = "" |
|
excludes = "" |
|
interbroker_mechanism = "" |
|
if nargs > 6: tag = args[6] |
|
if nargs > 7: excludes = args[7] |
|
if nargs > 8: interbroker_mechanism = args[8] |
|
rm.addRoute(remoteBroker, args[4], args[5], tag, excludes, interbroker_mechanism, dynamic=False) |
|
elif cmd == "del": |
|
if nargs != 6: |
|
Usage() |
|
return(-1) |
|
rm.delRoute(remoteBroker, args[4], args[5], dynamic=False) |
|
elif cmd == "map": |
|
rm.mapRoutes() |
|
else: |
|
if cmd == "list": |
|
rm.listRoutes() |
|
elif cmd == "flush": |
|
rm.clearAllRoutes() |
|
else: |
|
Usage() |
|
return(-1) |
|
|
|
elif group == "queue": |
|
if nargs < 6 or nargs > 7: |
|
Usage() |
|
return(-1) |
|
if cmd == "add": |
|
interbroker_mechanism = "" |
|
if nargs > 6: interbroker_mechanism = args[6] |
|
rm.addQueueRoute(remoteBroker, interbroker_mechanism, exchange=args[4], queue=args[5] ) |
|
elif cmd == "del": |
|
rm.delQueueRoute(remoteBroker, exchange=args[4], queue=args[5]) |
|
else: |
|
Usage() |
|
return(-1) |
|
else: |
|
Usage() |
|
return(-1) |
|
|
|
except Exception,e: |
|
if rm: |
|
rm.disconnect() # try to release broker resources |
|
print "Failed: %s - %s" % (e.__class__.__name__, e) |
|
return 1 |
|
|
|
rm.disconnect() |
|
return 0 |
|
|
|
if __name__ == "__main__": |
|
sys.exit(main()) |