From 0e8936e55956813f7f7db633b1cb96241a78ea58 Mon Sep 17 00:00:00 2001 From: Sander Vrijders Date: Tue, 28 Mar 2017 13:18:26 +0200 Subject: testbeds: Port to new API The new API passes the Experiment instance to the testbeds, so that the configs for the testbeds can be generated starting from the IPCPs. The classes Link, Interface, P2PLink have been deprecated. --- rumba/model.py | 93 ++++++++----------------------------------- rumba/testbeds/emulab.py | 67 +++++++++++++++---------------- rumba/testbeds/faketestbed.py | 2 +- rumba/testbeds/jfed.py | 78 +++++++++++++++++------------------- rumba/testbeds/qemu.py | 3 +- 5 files changed, 88 insertions(+), 155 deletions(-) diff --git a/rumba/model.py b/rumba/model.py index 098930a..0659cb1 100644 --- a/rumba/model.py +++ b/rumba/model.py @@ -36,56 +36,9 @@ class Testbed: self.exp_name = exp_name @abc.abstractmethod - def create_experiment(self, nodes, links): + def create_experiment(self, experiment): raise Exception('create_experiment() not implemented') - -# Represents an interface on a node -# -# @name [string] interface name -# @ip [int] IP address of that interface -# -class Interface: - def __init__(self, name = "", ip = ""): - self.name = name - self.ip = ip - - def __repr__(self): - return self.name - -# Represents a link in the physical graph -# -# @name [string] Link name -# -class Link: - def __init__(self, name): - self.name = name - - def __repr__(self): - return self.name - -# Represents a point-to-point link in the physical graph -# -# @name [string] DIF name -# -class P2PLink(Link): - def __init__(self, name, node_a, node_b, - int_a = None, - int_b = None): - Link.__init__(self, name) - self.node_a = node_a - self.node_b = node_b - if int_a is None: - int_a = Interface() - self.int_a = int_a - if int_b is None: - int_b = Interface() - self.int_b = int_b - - def __repr__(self): - return '%s:%s--%s:%s' % (self.node_a.name, self.int_a, - self.node_b.name, self.int_b) - # Base class for DIFs # # @name [string] DIF name @@ -96,6 +49,7 @@ class DIF: if members is None: members = list() self.members = members + self.ipcps = list() def __repr__(self): s = "DIF %s" % self.name @@ -359,25 +313,6 @@ class Experiment: return s - def get_links(self): - difs = set() - links = list() - for node in self.nodes: - for dif in node.difs: - if type(dif) is ShimEthDIF: - difs.add(dif) - - for dif in difs: - # Point-to-point link - if len(dif.members) == 2: - node_a = dif.members[0] - node_b = dif.members[1] - link = P2PLink(node_a.name + "-" + node_b.name, - node_a, node_b) - links.append(link) - - return links - def add_node(self, node): self.nodes.append(node) self.generate() @@ -417,7 +352,8 @@ class Experiment: #print(difsdeps_adj) #print(difsdeps_inc_cnt) - # Run Kahn's algorithm to compute topological ordering on the DIFs graph. + # Run Kahn's algorithm to compute topological + # ordering on the DIFs graph. frontier = set() self.dif_ordering = [] for dif in difsdeps_inc_cnt: @@ -433,11 +369,13 @@ class Experiment: frontier.add(nxt) difsdeps_adj[cur] = set() - circular_set = [dif for dif in difsdeps_inc_cnt if difsdeps_inc_cnt[dif] != 0] + circular_set = [dif for dif in difsdeps_inc_cnt \ + if difsdeps_inc_cnt[dif] != 0] if len(circular_set): - raise Exception("Fatal error: The specified DIFs topology has one or more"\ - "circular dependencies, involving the following"\ - " DIFs: %s" % circular_set) + raise Exception("Fatal error: The specified DIFs topology" \ + "has one or more" \ + "circular dependencies, involving the following" \ + " DIFs: %s" % circular_set) print("DIF topological ordering: %s" % self.dif_ordering) @@ -451,8 +389,8 @@ class Experiment: dif_graphs[dif] = dict() first = None - # For each N-1-DIF supporting this DIF, compute the set of nodes that - # share such N-1-DIF. This set will be called the 'neighset' of + # For each N-1-DIF supporting this DIF, compute the set of nodes + # that share such N-1-DIF. This set will be called the 'neighset' of # the N-1-DIF for the current DIF. for node in self.nodes: @@ -482,7 +420,9 @@ class Experiment: er = [] for node in dif_graphs[dif]: for edge in dif_graphs[dif][node]: - er.append("%s --[%s]--> %s" % (node.name, edge[1].name, edge[0].name)) + er.append("%s --[%s]--> %s" % (node.name, + edge[1].name, + edge[0].name)) print("DIF graph for %s: %s" % (dif, ', '.join(er))) if self.enrollment_strategy == 'minimal': @@ -556,6 +496,7 @@ class Experiment: break node.ipcps.append(ipcp) + dif.ipcps.append(ipcp) print("IPCP for node %s: %s" % (node.name, node.ipcps)) @@ -568,7 +509,7 @@ class Experiment: # Realize the experiment, using a testbed-specific setup def swap_in(self): - self.testbed.create_experiment(self.nodes, self.get_links()) + self.testbed.create_experiment(self) @abc.abstractmethod def run(self): diff --git a/rumba/testbeds/emulab.py b/rumba/testbeds/emulab.py index cbaa730..c696fbb 100644 --- a/rumba/testbeds/emulab.py +++ b/rumba/testbeds/emulab.py @@ -37,7 +37,7 @@ warnings.filterwarnings("ignore") # class Testbed(mod.Testbed): def __init__(self, exp_name, username, password = "", - proj_name = "ARCFIRE", url = "wall1.ilabt.iminds.be", + proj_name = "ARCFIRE", url = "wall2.ilabt.iminds.be", image = "UBUNTU14-64-STD"): mod.Testbed.__init__(self, exp_name, username, password, proj_name) self.url = url @@ -101,13 +101,12 @@ class Testbed(mod.Testbed): return output - def _create_experiment(self, nodes, links): + def _create_experiment(self, experiment): ''' Creates an emulab experiment @param self: testbed info - @param nodes: holds the nodes in the experiment - @param links: holds the links in the experiment + @param experiment: the experiment ''' proj_name = self.proj_name exp_name = self.exp_name @@ -121,7 +120,7 @@ class Testbed(mod.Testbed): except: print("First experiment to be created for that project.") - ns = self.generate_ns_script(nodes, links) + ns = self.generate_ns_script(experiment) dest_file_name = '/users/'+ self.username + \ '/temp_ns_file.%s.ns' % os.getpid() ssh.copy_file_to_testbed(self, self.ops_server(), ns, dest_file_name) @@ -135,13 +134,12 @@ class Testbed(mod.Testbed): ssh.execute_command(self, self.ops_server(),'rm ' + dest_file_name) print("New experiment succesfully created.") - def generate_ns_script(self, nodes, p2plinks): + def generate_ns_script(self, experiment): ''' Generate ns script based on network graph. Enables to customize default node image. - @param nodes: holds the nodes in the experiment - @param links: holds the links in the experiment + @param experiment: the experiment @param self: testbed info @return: ns2 script for Emulab experiment @@ -151,16 +149,19 @@ class Testbed(mod.Testbed): ns2_script += "set ns [new Simulator]\n" ns2_script += "source tb_compat.tcl\n" - for node in nodes: + for node in experiment.nodes: ns2_script += "set " + node.name + " [$ns node]\n" ns2_script += "tb-set-node-os $" + node.name + " " + \ self.image + "\n" - for link in p2plinks: - ns2_script += "set " + link.name + \ + for dif in experiment.dif_ordering: + if type(dif) is mod.ShimEthDIF: + if len(dif.ipcps) != 2: + continue + ns2_script += "set " + dif.name + \ " [$ns duplex-link $" + \ - link.node_a.name + " $" + \ - link.node_b.name + " 1000Mb 0ms DropTail]\n" + dif.members[0].name + " $" + \ + dif.members[1].name + " 1000Mb 0ms DropTail]\n" ns2_script += "$ns run\n" @@ -191,16 +192,15 @@ class Testbed(mod.Testbed): print("Still waiting") time.sleep(5) - def complete_experiment_graph(self, nodes, p2plinks): + def complete_experiment_graph(self, experiment): ''' Gets the interface (ethx) to link mapping @param self: testbed info - @param nodes: holds the nodes in the experiment - @param links: holds the links in the experiment + @param experiment: the experiment ''' - node_full_name = self.full_name(nodes[0].name) + node_full_name = self.full_name(experiment.nodes[0].name) cmd = 'cat /var/emulab/boot/topomap' topomap = ssh.execute_command(self, node_full_name, cmd) # Almost as ugly as yo momma @@ -214,31 +214,28 @@ class Testbed(mod.Testbed): item2 = item2.split(':') link_name = item2[0] link_ip = item2[1] - for link in p2plinks: - if link.name == link_name: - if link.node_a.name == node_name: - link.int_a.ip = link_ip - elif link.node_b.name == node_name: - link.int_b.ip = link_ip - - for node in nodes: + for node in experiment.nodes: + if node.name != node_name: + continue + for ipcp in node.ipcps: + if ipcp.dif.name == link_name: + ipcp.ip = link_ip + + for node in experiment.nodes: cmd = 'cat /var/emulab/boot/ifmap' node_full_name = self.full_name(node.name) output = ssh.execute_command(self, node_full_name, cmd) output = re.split('\\\\n', output) for item in output: item = item.split() - for link in p2plinks: - if link.node_a.name == node.name and \ - link.int_a.ip == item[1]: - link.int_a.name = item[0] - elif link.node_b.name == node.name and \ - link.int_b.ip == item[1]: - link.int_b.name = item[0] + for ipcp in node.ipcps: + if type(ipcp) is mod.ShimEthIPCP: + if ipcp.ip == item[1]: + ipcp.ifname = item[0] node.full_name = self.full_name(node.name) - def create_experiment(self, nodes, links): - self._create_experiment(nodes, links) + def create_experiment(self, experiment): + self._create_experiment(experiment) self.swap_exp_in() self.wait_until_nodes_up() - self.complete_experiment_graph(nodes, links) + self.complete_experiment_graph(experiment) diff --git a/rumba/testbeds/faketestbed.py b/rumba/testbeds/faketestbed.py index e47eb85..8d5e724 100644 --- a/rumba/testbeds/faketestbed.py +++ b/rumba/testbeds/faketestbed.py @@ -26,5 +26,5 @@ class Testbed(mod.Testbed): password = ""): mod.Testbed.__init__(self, exp_name, username, password, proj_name) - def create_experiment(self, nodes, links): + def create_experiment(self, experiment): print("[Fake testbed] experiment swapped in") diff --git a/rumba/testbeds/jfed.py b/rumba/testbeds/jfed.py index 92e615f..04c57ba 100644 --- a/rumba/testbeds/jfed.py +++ b/rumba/testbeds/jfed.py @@ -35,7 +35,7 @@ class Testbed(mod.Testbed): self.jfed_jar = jfed_jar self.exp_hours = exp_hours - def create_rspec(self, nodes, links): + def create_rspec(self, experiment): self.rspec = self.exp_name + ".rspec" impl = xml.getDOMImplementation() @@ -66,7 +66,7 @@ class Testbed(mod.Testbed): "resources/rspec/3 http://www.geni.net/" + "resources/rspec/3/request.xsd") - for node in nodes: + for node in experiment.nodes: el = doc.createElement("node") top_el.appendChild(el) el.setAttribute("client_id", node.name) @@ -78,50 +78,41 @@ class Testbed(mod.Testbed): el2.setAttribute("name", "raw-pc") node.ifs = 0 - for link in links: - if link.node_a == node or link.node_b == node: + for ipcp in node.ipcps: + if type(ipcp) is mod.ShimEthIPCP: el3 = doc.createElement("interface") - if link.node_a == node: - link.int_a.id = node.name + ":if" + str(node.ifs) - link_id = link.int_a.id - if link.node_b == node: - link.int_b.id = node.name + ":if" + str(node.ifs) - link_id = link.int_b.id - - el3.setAttribute("client_id", link_id) + ipcp.if_id = node.name + ":if" + str(node.ifs) + el3.setAttribute("client_id", ipcp.if_id) node.ifs += 1 el.appendChild(el3) - for link in links: - el = doc.createElement("link") - top_el.appendChild(el) - el.setAttribute("client_id", link.name) - - el2 = doc.createElement("component_manager_id") - el2.setAttribute("name", self.authority) - el.appendChild(el2) + for dif in experiment.dif_ordering: + if type(dif) is mod.ShimEthDIF: + el = doc.createElement("link") + top_el.appendChild(el) + el.setAttribute("client_id", dif.name) - el3 = doc.createElement("interface_ref") - el3.setAttribute("client_id", link.int_a.id) - el.appendChild(el3) + el2 = doc.createElement("component_manager_id") + el2.setAttribute("name", self.authority) + el.appendChild(el2) - el4 = doc.createElement("interface_ref") - el4.setAttribute("client_id", link.int_b.id) - el.appendChild(el4) + for ipcp in dif.ipcps: + el3 = doc.createElement("interface_ref") + el3.setAttribute("client_id", ipcp.if_id) + el.appendChild(el3) file = open(self.rspec, "w") file.write(doc.toprettyxml()) file.close() - def create_experiment(self, nodes, links): - self.create_rspec(nodes, links) + def create_experiment(self, experiment): + self.create_rspec(experiment) self.manifest = self.exp_name + ".rrspec" - for node in nodes: + for node in experiment.nodes: auth_name_r = self.auth_name.replace(".", "-") node.full_name = node.name + "." + self.exp_name + "." + \ - self.proj_name + "." + auth_name_r + \ - "." + self.auth_name + auth_name_r + "." + self.auth_name subprocess.call(["java", "-jar", self.jfed_jar, "create", "-S", \ self.proj_name, "--rspec", \ @@ -136,17 +127,22 @@ class Testbed(mod.Testbed): rspec = xml.parse(self.manifest) xml_nodes = rspec.getElementsByTagName("node") + # Complete details of the nodes after swapin for xml_node in xml_nodes: n_name = xml_node.getAttribute("client_id") intfs = xml_node.getElementsByTagName("interface") - for link in links: - if link.node_a.name == n_name: - interface = link.int_a - if link.node_b.name == n_name: - interface = link.int_b + + for node in experiment.nodes: + if node.name == n_name: + node_n = node + for intf in intfs: - comp_id = intf.getAttribute("component_id") - comp_arr = comp_id.split(":") - interface.name = comp_arr[-1] - xml_ip = intf.getElementsByTagName("ip") - interface.ip = xml_ip[0].getAttribute("address") + i_name = intf.getAttribute("client_id") + for ipcp in node_n.ipcps: + if type(ipcp) is mod.ShimEthIPCP: + if ipcp.if_id == i_name: + comp_id = intf.getAttribute("component_id") + comp_arr = comp_id.split(":") + ipcp.ifname = comp_arr[-1] + #xml_ip = intf.getElementsByTagName("ip") + #interface.ip = xml_ip[0].getAttribute("address") diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py index d44bb3e..3f4cb4a 100644 --- a/rumba/testbeds/qemu.py +++ b/rumba/testbeds/qemu.py @@ -26,8 +26,7 @@ class Testbed(mod.Testbed): password = ""): mod.Testbed.__init__(self, exp_name, username, password, proj_name) - def create_experiment(self, nodes, links): - print(links) + def create_experiment(self, experiment): print("[QEMU testbed] experiment swapped in") def __del__(self): -- cgit v1.2.3