blob: 532d549b116e8823722912b527e5cd66598ac3fd [file]
#!/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 optparse
from proton import Endpoint, generate_uuid
from proton import Message
from proton.handlers import MessagingHandler
from proton.reactor import Container
import json
from pprint import pprint
import os
import string
import random
import shutil
from mock import Connection, RouterLink, Schema, Listener, RouterNode, Hopper, Router, Address, Policy, Connector, \
RouterAddresses, Allocators, Logs
import pdb
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
class Manager(object):
def __init__(self, topology, verbose):
self.topology = topology
self.verbose = verbose
self.base = "topologies/"
def operation(self, op, request):
m = op.replace("-", "_")
try:
method = getattr(self, m)
except AttributeError:
print op + " is not implemented yet"
return []
if self.verbose:
print "Got request " + op
return method(request)
def GET_LOG(self, request):
return []
def GET_SCHEMA(self, request):
with open(self.base + "schema.json") as fp:
data = json.load(fp)
return data
def GET_MGMT_NODES(self, request):
onlyfiles = []
if not os.path.exists(self.base + self.topology):
os.makedirs(self.base + self.topology)
for f in os.listdir(self.base + self.topology):
if os.path.isfile(os.path.join(self.base + self.topology, f)):
if os.path.splitext(f)[1] == ".json":
onlyfiles.append(unicode("amqp:/_topo_/0/" + os.path.splitext(f)[0] + "/$management"))
'''
onlyfiles = [
unicode("amqp:/_topo/0/" + os.path.splitext(f)[0] + "/$management", "utf-8")
for f in os.listdir(self.topology)
if os.path.isfile(os.path.join(self.topology, f)) and os.path.splitext(f)[1] == ".json"
]
'''
if self.verbose:
pprint (onlyfiles)
return onlyfiles
def QUERY(self, request):
#pdb.set_trace()
if not getattr(request, "address"):
nodes = self.GET_MGMT_NODES(request)
node = nodes[0]
else:
node = request.address
print "node is"
pprint (node)
nid = node.split('/')[-2]
fullentity = request.properties["entityType"]
entity = fullentity[len("org.apache.qpid.dispatch"):]
if self.verbose:
pprint("nid is " + nid + " entity is " + entity)
if not "arrtibuteNmaes" in request.body:
requestedAttrs = []
else:
requestedAttrs = request.body["attributeNames"]
if not os.path.isfile(self.base + self.topology + "/" + nid + ".json"):
return {"results": [], "attributeNames": requestedAttrs}
with open(self.base + self.topology + "/" + nid + ".json") as fp:
data = json.load(fp)
ent = data.get(entity, {'attributeNames': [], 'results': []})
attributeNames = ent['attributeNames']
allresults = ent['results']
if len(requestedAttrs) == 0:
requestedAttrs = attributeNames
results = []
for result in allresults:
newresult = []
for atr in requestedAttrs:
atrindex = attributeNames.index(atr)
if atrindex < 0 or atrindex >= len(result):
newresult.append('not found')
else:
newresult.append(result[atrindex])
results.append(newresult)
newdata = {"results": results, "attributeNames": requestedAttrs}
if self.verbose:
pprint(newdata)
return newdata
def LOAD(self, request):
topology = request.properties["topology"]
fname = self.base + topology + "/nodeslinks.dat"
if not os.path.isfile(fname):
if self.verbose:
print "returning empty topology for " + topology
return {"nodes": [], "links": [], "topology": topology}
with open(fname) as fp:
data = json.load(fp)
return data
def GET_TOPOLOGY(self, request):
if self.verbose:
pprint (self.topology)
return unicode(self.topology)
def GET_TOPOLOGY_LIST(self, request):
return [unicode(f) for f in os.listdir(self.base) if os.path.splitext(f)[1] != ".json"]
def SWITCH(self, request):
self.topology = request.properties["topology"]
return self.LOAD(request)
def PUBLISH(self, request):
nodes = request.properties["nodes"]
links = request.properties["links"]
topology = request.properties["topology"]
if self.verbose:
print("PUBLISHing to " + topology)
shutil.rmtree(self.base + topology)
if not os.path.exists(self.base + topology):
os.makedirs(self.base + topology)
with open(self.base + topology + "/nodeslinks.dat", "w+") as fp:
fp.write(json.dumps({"nodes": nodes, "links": links, "topology": topology}, indent=2))
port = 20001
clients = {}
connectionId = 1
# cache any connections and links for clients first
for node in nodes:
if node['nodeType'] != 'inter-router':
if not node['key'] in clients:
clients[node['key']] = {"connections": [], "links": [], "addresses": []}
for normal in node["normals"]:
clients[node['key']]["connections"].append(Connection(node, connectionId).vals())
ldir = "in" if node['cdir'] == "in" else "out"
owningAddr = "M0" + normal['addr'] if "console_identifier" not in node['properties'] else ""
clients[node['key']]["links"].append(RouterLink(node, str(len(clients[node['key']]["links"])),
ldir, owningAddr, "endpoint", connectionId).vals())
if node['cdir'] == "both":
otherAddr = "M0" + normal['addr'] if "console_identifier" not in node['properties'] \
else "Ltemp." + id_generator(15)
clients[node['key']]["links"].append(RouterLink(node,
str(len(clients[node['key']]["links"])), "in",
otherAddr, "endpoint", connectionId).vals())
connectionId += 1
hopper = Hopper(self.verbose)
for node in nodes:
if node['nodeType'] == 'inter-router':
nodeInfo = {}
# this should be driven by the schema and not hard coded like this
nname = node["name"]
entities = ("connection", "router", "router.link", "router.node", "allocator",
"sslProfile", "autoLink", "linkRoute", "address", "policy", "log",
"vhost", "vhostStats", "listener", "router.address", "connector")
for entity in entities:
savedAs = entity
if entity == "address":
savedAs = "router.config.address"
nodeInfo["."+savedAs] = {"results": [], "attributeNames": Schema.schema[entity]["attributeNames"]}
# find all the other nodes that are linked to this node
nodeCons = []
nodeLinks = []
# if the link source or target is this node's id
for link in links:
# only process links to other routers
if link['cls'] != "small":
toNode = None
if link['source']['name'] == node['name']:
toNode = link['target']
toNode["cdir"] = "in"
if link['target']['name'] == node['name']:
toNode = link['source']
toNode["cdir"] = "out"
if toNode:
toNode["container"] = toNode["name"]
nodeCons.append(Connection(toNode, connectionId).vals())
nodeLinks.append(RouterLink(toNode, str(len(nodeLinks)+1), "in",
'', "router-control", connectionId).vals())
nodeLinks.append(RouterLink(toNode, str(len(nodeLinks)+1), "out",
'', "router-control", connectionId).vals())
nodeLinks.append(RouterLink(toNode, str(len(nodeLinks)+1), "in",
'', "inter-router", connectionId).vals())
nodeLinks.append(RouterLink(toNode, str(len(nodeLinks)+1), "out",
'', "inter-router", connectionId).vals())
connectionId += 1
nodeInfo[".connection"]["results"] = nodeCons
nodeInfo[".router.link"]["results"] = nodeLinks
# add any connections and links for clients
if node['key'] in clients:
nodeInfo[".connection"]["results"].extend(clients[node['key']]["connections"])
nodeInfo[".router.link"]["results"].extend(clients[node['key']]["links"])
nodeInfo[".listener"]["results"].append(Listener(port).vals())
port += 1
nodeInfo[".router"]["results"].append(Router(node).vals())
nodeInfo[".router.config.address"]["results"].append(Address().vals())
nodeInfo[".policy"]["results"].append(Policy().vals())
for connection in nodeInfo[".connection"]["results"]:
dir = connection[Schema.i("connection", "dir")]
if dir == "out":
hostIndex = Schema.i("connection", "host")
connhost, connport = connection[hostIndex].split(":")
nodeInfo[".connector"]["results"].append(Connector(connhost, connport).vals())
for n in nodes:
if n['nodeType'] == 'inter-router':
nodeInfo[".router.node"]["results"].append(RouterNode(node['name'], n['name'], links, hopper).vals())
nodeInfo[".router.address"]["results"] = RouterAddresses(node, nodes).vals()
nodeInfo[".allocator"]["results"] = Allocators().vals()
nodeInfo[".log"]["results"] = Logs().vals()
with open(self.base + topology + "/" + nname + ".json", "w+") as fp:
fp.write(json.dumps(nodeInfo, indent=2, sort_keys=True))
return "published"
class MockRouter(MessagingHandler):
def __init__(self, url, topology, verbose):
super(MockRouter, self).__init__()
self.url = url
self.manager = Manager(topology, verbose)
self.senders = {}
self.verbose = verbose
def on_start(self, event):
self.acceptor = event.container.listen(self.url)
def on_link_opening(self, event):
if event.link.is_sender:
if event.link.remote_source.dynamic:
if self.verbose:
print("opening dynamic sender")
address = str(generate_uuid())
event.link.source.address = address
elif event.link.remote_source.address:
if self.verbose:
print("opening remote_source address sender")
event.link.source.address = event.link.remote_source.address
else:
print("received unknown sender link")
self.senders[event.link.source.address] = event.link
elif event.link.is_receiver:
if self.verbose:
print "got a receiver link"
event.link.target.address = event.link.remote_target.address
def on_message(self, event):
ret = self.manager.operation(event.message.properties["operation"], event.message)
m = Message(address=event.message.reply_to, body=ret,
correlation_id=event.message.correlation_id,
properties={"statusCode": 200} )
self.senders[event.message.reply_to].send(m)
parser = optparse.OptionParser(usage="usage: %prog [options]")
parser.add_option("-a", "--address", default="localhost:5672",
help="address router listens on (default %default)")
parser.add_option("-t", "--topology", default="config-80",
help="which topology directory to return (default %default)")
parser.add_option("-v", "--verbose", default=False,
help="display requests and responses to stdout (default %default)")
opts, args = parser.parse_args()
try:
Container(MockRouter(opts.address, opts.topology, opts.verbose)).run()
except KeyboardInterrupt: pass