added CLI to fetch datacenter information. also started CLI documentation in the wiki and linked it from README.md
* `cd ~/son-emu/emuvim`
* `sudo python test` or `sudo python test -v` for more outputs
+### CLI
+* [Full CLI command documentation](https://github.com/sonata-nfv/son-emu/wiki/CLI-Command-Overview)
+
### TODO
* DCemulator
def __init__(self, dcs):
self.dcs = dcs
- def compute_action_start(self, dc_name, compute_name, image, network):
+ def compute_action_start(self, dc_label, compute_name, image, network):
# network e.g. {"ip": "10.0.0.254/8"}
# TODO what to return UUID / given name / internal name ?
logging.debug("RPC CALL: compute start")
try:
- c = self.dcs.get(dc_name).startCompute(
+ c = self.dcs.get(dc_label).startCompute(
compute_name, image=image, network=network)
return str(c.name)
except Exception as ex:
logging.exception("RPC error.")
return ex.message
- def compute_action_stop(self, dc_name, compute_name):
+ def compute_action_stop(self, dc_label, compute_name):
logging.debug("RPC CALL: compute stop")
try:
- return self.dcs.get(dc_name).stopCompute(compute_name)
+ return self.dcs.get(dc_label).stopCompute(compute_name)
except Exception as ex:
logging.exception("RPC error.")
return ex.message
- def compute_list(self, dc_name):
+ def compute_list(self, dc_label):
logging.debug("RPC CALL: compute list")
try:
- if dc_name is None:
+ if dc_label is None:
# return list with all compute nodes in all DCs
all_containers = []
for dc in self.dcs.itervalues():
else:
# return list of compute nodes for specified DC
return [(c.name, c.getStatus())
- for c in self.dcs.get(dc_name).listCompute()]
+ for c in self.dcs.get(dc_label).listCompute()]
except Exception as ex:
logging.exception("RPC error.")
return ex.message
- def compute_status(self, dc_name, compute_name):
+ def compute_status(self, dc_label, compute_name):
logging.debug("RPC CALL: compute status")
try:
return self.dcs.get(
- dc_name).containers.get(compute_name).getStatus()
+ dc_label).containers.get(compute_name).getStatus()
+ except Exception as ex:
+ logging.exception("RPC error.")
+ return ex.message
+
+ def datacenter_list(self):
+ logging.debug("RPC CALL: datacenter list")
+ try:
+ return [d.getStatus() for d in self.dcs.itervalues()]
+ except Exception as ex:
+ logging.exception("RPC error.")
+ return ex.message
+
+ def datacenter_status(self, dc_label):
+ logging.debug("RPC CALL: datacenter status")
+ try:
+ return self.dcs.get(dc_label).getStatus()
except Exception as ex:
logging.exception("RPC error.")
return ex.message
parser = argparse.ArgumentParser(description='son-emu compute')
parser.add_argument(
"command",
- help="Action to be executed: start|stop|list")
+ choices=['start', 'stop', 'list', 'status'],
+ help="Action to be executed.")
parser.add_argument(
"--datacenter", "-d", dest="datacenter",
help="Data center to in which the compute instance should be executed")
--- /dev/null
+"""
+son-emu datacenter CLI
+(c) 2016 by Manuel Peuster <manuel.peuster@upb.de>
+"""
+
+import argparse
+import pprint
+from tabulate import tabulate
+import zerorpc
+
+
+pp = pprint.PrettyPrinter(indent=4)
+
+
+class ZeroRpcClient(object):
+
+ def __init__(self):
+ self.c = zerorpc.Client()
+ self.c.connect("tcp://127.0.0.1:4242") # TODO hard coded for now. we'll change this later
+ self.cmds = {}
+
+ def execute_command(self, args):
+ if getattr(self, args["command"]) is not None:
+ # call the local method with the same name as the command arg
+ getattr(self, args["command"])(args)
+ else:
+ print "Command not implemented."
+
+ def list(self, args):
+ r = self.c.datacenter_list()
+ table = []
+ for d in r:
+ # for each dc add a line to the output table
+ if len(d) > 0:
+ table.append([d.get("label"),
+ d.get("internalname"),
+ d.get("switch"),
+ d.get("n_running_containers"),
+ len(d.get("metadata"))])
+ headers = ["Label",
+ "Internal Name",
+ "Switch",
+ "# Containers",
+ "# Metadata Items"]
+ print tabulate(table, headers=headers, tablefmt="grid")
+
+ def status(self, args):
+ r = self.c.datacenter_status(
+ args.get("datacenter"))
+ pp.pprint(r)
+
+
+parser = argparse.ArgumentParser(description='son-emu datacenter')
+parser.add_argument(
+ "command",
+ choices=['list', 'status'],
+ help="Action to be executed.")
+parser.add_argument(
+ "--datacenter", "-d", dest="datacenter",
+ help="Data center to which the command should be applied.")
+
+
+def main(argv):
+ args = vars(parser.parse_args(argv))
+ c = ZeroRpcClient()
+ c.execute_command(args)
import sys
import compute
import network
+import datacenter
def main():
compute.main(sys.argv[2:])
elif sys.argv[1] == "network":
network.main(sys.argv[2:])
+ elif sys.argv[1] == "datacenter":
+ datacenter.main(sys.argv[2:])
if __name__ == '__main__':
main()
self, controller=Controller, switch=OVSKernelSwitch, **kwargs)
self.addController('c0')
- def addDatacenter(self, label):
+ def addDatacenter(self, label, metadata={}):
"""
Create and add a logical cloud data center to the network.
"""
if label in self.dcs:
raise Exception("Data center label already exists: %s" % label)
- dc = Datacenter(label)
+ dc = Datacenter(label, metadata=metadata)
dc.net = self # set reference to network
self.dcs[label] = dc
dc.create() # finally create the data center in our Mininet instance
DC_COUNTER = 1
- def __init__(self, label):
+ def __init__(self, label, metadata={}):
self.net = None # DCNetwork to which we belong
# each node (DC) has a short internal name used by Mininet
# this is caused by Mininets naming limitations for swtiches etc.
self.name = "dc%d" % Datacenter.DC_COUNTER
Datacenter.DC_COUNTER += 1
- self.label = label # use this for user defined names
+ # use this for user defined names that can be longer than self.name
+ self.label = label
+ # dict to store arbitrary metadata (e.g. latitude and longitude)
+ self.metadata = metadata
self.switch = None # first prototype assumes one "bigswitch" per DC
self.containers = {} # keep track of running containers
data center.
"""
return list(self.containers.itervalues())
+
+ def getStatus(self):
+ """
+ Return a dict with status information about this DC.
+ """
+ return {
+ "label": self.label,
+ "internalname": self.name,
+ "switch": self.switch.name,
+ "n_running_containers": len(self.containers),
+ "metadata": self.metadata
+ }
"""
dc1 = net.addDatacenter("datacenter1")
dc2 = net.addDatacenter("datacenter2")
- dc3 = net.addDatacenter("a_very_long_data_center_name3")
- dc4 = net.addDatacenter("datacenter4")
+ dc3 = net.addDatacenter("long_data_center_name3")
+ dc4 = net.addDatacenter(
+ "datacenter4",
+ metadata={"mydata": "we can also add arbitrary metadata to each DC"})
"""
3. You can add additional SDN switches for data center
# connect data centers to this endpoint
zapi1.connectDatacenter(dc1)
zapi1.connectDatacenter(dc2)
+ zapi1.connectDatacenter(dc3)
+ zapi1.connectDatacenter(dc4)
# run API endpoint server (in another thread, don't block)
zapi1.start()
self.net.addLink(self.s[i], self.s[i + 1])
# add some data centers
for i in range(0, ndatacenter):
- self.dc.append(self.net.addDatacenter('datacenter%d' % i))
+ self.dc.append(
+ self.net.addDatacenter(
+ 'datacenter%d' % i,
+ metadata={"unittest_dc": i}))
# add some hosts
for i in range(0, nhosts):
self.h.append(self.net.addHost('h%d' % i))