[spp] [PATCH 11/13] controller: add topo_subgraph command
ogawa.yasufumi at lab.ntt.co.jp
ogawa.yasufumi at lab.ntt.co.jp
Tue Mar 6 11:50:53 CET 2018
From: Yasufumi Ogawa <ogawa.yasufumi at lab.ntt.co.jp>
'topo_subgraph' is for defining subgraph of resources in a network
topology generated by 'topo'. Typically it is used for grouping vhost
interfaces of each of VMs or containers to be more understandable the
generated network topology.
Usage: topo_subgraph [VERB] [LABEL] [SUBGRAPH]
VERB: 'add' or 'del'
If you assign vhost1 and vhost2 to VM1, define subgraph as following.
spp > topo_subgraph add VM1 vhost1,vhost2
Or delete defined subgraph.
spp > topo_subgraph del VM1
To show all of defined subgraphs, simply run without arguments.
spp > topo_subgraph
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi at lab.ntt.co.jp>
---
src/controller/shell.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-
src/controller/topo.py | 43 +++++++++++++++++++++----
2 files changed, 120 insertions(+), 8 deletions(-)
diff --git a/src/controller/shell.py b/src/controller/shell.py
index 8a0580a..8aae86d 100644
--- a/src/controller/shell.py
+++ b/src/controller/shell.py
@@ -30,6 +30,7 @@ class Shell(cmd.Cmd, object):
BYE_CMDS = ['sec', 'all']
PLUGIN_DIR = 'command'
+ subgraphs = {}
def default(self, line):
"""Define defualt behaviour
@@ -483,6 +484,87 @@ class Shell(cmd.Cmd, object):
if args == '':
pprint(vars(self))
+ def terms_topo_subgraph(self):
+ """Define terms of topo_subgraph command"""
+
+ return ['add', 'del']
+
+ def do_topo_subgraph(self, args):
+ """Subgarph manager for topo
+
+ Subgraph is a group of object defined in dot language.
+ For topo command, it is used for grouping resources of each
+ of VM or container to topology be more understandable.
+
+ Add subgraph labeled 'vm1'. Resource name is capitalized and
+ both of them is OK.
+ spp > topo_subgraph add vm1 VHOST1;VHOST2 # upper case
+ spp > topo_subgraph add vm1 vhost1;vhost2 # lower case
+
+ Delete subgraph 'vm1'.
+ spp > topo_subgraph del vm1
+
+ To show subgraphs, run topo_subgraph without args.
+ spp > topo_subgraph
+ {'vm1', 'VHOST1;VHOST2'}
+ """
+
+ args_cleaned = re.sub(r"\s+", ' ', args).strip()
+ # Show subgraphs if given no argments
+ if (args_cleaned == ''):
+ if len(self.subgraphs) == 0:
+ print("No subgraph.")
+ else:
+ for label, subg in self.subgraphs.items():
+ print('label: %s\tsubgraph: "%s"' % (label, subg))
+ else: # add or del
+ tokens = args_cleaned.split(' ')
+ # Add subgraph
+ if tokens[0] == 'add':
+ if len(tokens) == 3:
+ label = tokens[1]
+ subg = tokens[2].upper()
+ if ',' in subg:
+ subg = re.sub(r",", ";", subg)
+
+ # TODO(yasufum) add validation for subgraph
+ self.subgraphs[label] = subg
+ print("Add subgraph '%s'" % label)
+ else:
+ print("Invalid syntax '%s'!" % args_cleaned)
+ # Delete subgraph
+ elif ((tokens[0] == 'del') or
+ (tokens[0] == 'delete') or
+ (tokens[0] == 'remove')):
+ del(self.subgraphs[tokens[1]])
+ print("Delete subgraph '%s'" % tokens[1])
+
+ else:
+ print("Ivalid subcommand '%s'!" % tokens[0])
+
+ def complete_topo_subgraph(self, text, line, begidx, endidx):
+ terms = self.terms_topo_subgraph()
+
+ tokens = re.sub(r"\s+", ' ', line).strip().split(' ')
+ if text == '':
+ if len(tokens) == 1:
+ return terms
+ elif len(tokens) == 2 and tokens[1] == 'del':
+ return self.subgraphs.keys()
+ elif text != '':
+ completions = []
+ if len(tokens) == 3 and tokens[1] == 'del':
+ for t in self.subgraphs.keys():
+ if t.startswith(tokens[2]):
+ completions.append(t)
+ elif len(tokens) == 2:
+ for t in terms:
+ if t.startswith(text):
+ completions.append(t)
+ return completions
+ else:
+ pass
+
def do_topo(self, args):
"""Output network topology
@@ -506,7 +588,8 @@ class Shell(cmd.Cmd, object):
tp = topo.Topo(
spp_common.SECONDARY_LIST,
spp_common.MAIN2SEC,
- spp_common.SEC2MAIN)
+ spp_common.SEC2MAIN,
+ self.subgraphs)
args_ary = args.split()
if len(args_ary) == 0:
print("Usage: topo dst [ftype]")
diff --git a/src/controller/topo.py b/src/controller/topo.py
index 30a9c1a..92d1634 100644
--- a/src/controller/topo.py
+++ b/src/controller/topo.py
@@ -20,11 +20,12 @@ class Topo(object):
* text (dot, json, yaml)
"""
- def __init__(self, sec_ids, m2s_queues, s2m_queues):
+ def __init__(self, sec_ids, m2s_queues, s2m_queues, sub_graphs):
logger.info("Topo initialized with sec IDs %s" % sec_ids)
self.sec_ids = sec_ids
self.m2s_queues = m2s_queues
self.s2m_queues = s2m_queues
+ self.sub_graphs = sub_graphs
def show(self, dtype):
res_ary = []
@@ -153,26 +154,54 @@ class Topo(object):
# rank
output.append(
'{rank=same; %s}' % ("; ".join(ring_labels)))
+ output.append(
+ '{rank=same; %s}' % ("; ".join(vhost_labels)))
+
if len(phys) > 0:
output.append(
'{rank=max; %s}' % (
phys[0]["iface"]["type"] + phys[0]["iface"]["id"]))
- output.append(
- '{rank=same; %s}' % ("; ".join(phy_labels)))
+ elif len(vhosts) > 0:
+ output.append(
+ '{rank=max; %s}' % (
+ vhosts[0]["iface"]["type"] + vhosts[0]["iface"]["id"]))
+
+ if len(phy_labels) > 0:
+ output.append(
+ '{rank=same; %s}' % ("; ".join(phy_labels)))
+
+ # Add subgraph
+ ssgs = []
+ if len(self.sub_graphs) > 0:
+ cnt = 1
+ for label, val in self.sub_graphs.items():
+ cluster_id = "cluster%d" % cnt
+ ssg_label = label
+ ssg_ports = val
+ ssg = 'subgraph %s {label="%s" %s}' % (
+ cluster_id, ssg_label, ssg_ports)
+ ssgs.append(ssg)
+ cnt += 1
- # subgraph
cluster_id = "cluster0"
sg_label = "Host"
sg_ports = "; ".join(phy_labels + ring_labels)
- output.append(
- 'subgraph %s {label="%s" %s}' % (cluster_id, sg_label, sg_ports))
+ if len(ssgs) == 0:
+ output.append(
+ 'subgraph %s {label="%s" %s}' % (
+ cluster_id, sg_label, sg_ports))
+ else:
+ tmp = 'label="%s" %s' % (sg_label, sg_ports)
+ contents = [tmp] + ssgs
+ output.append(
+ 'subgraph %s {%s}' % (cluster_id, '; '.join(contents)))
+ # Add links
for link in links:
output.append(link)
output.append("}")
- # remove duplicated entries
f = open(output_fname, "w+")
f.write("\n".join(output))
f.close()
--
2.13.1
More information about the spp
mailing list