aboutsummaryrefslogtreecommitdiff
path: root/rhumba.py
diff options
context:
space:
mode:
authorvmaffione <[email protected]>2017-01-24 15:15:07 +0000
committervmaffione <[email protected]>2017-01-24 15:15:07 +0000
commit2a085b29e2754500e87cbb1a90e89301671eabe8 (patch)
tree0f4cca29dd5bd4236122be280c53c6a34ced12fe /rhumba.py
parente184e2838cc2b65fe9afe1cf7649b01ce4dcf73f (diff)
parent97e601fdc5c03de7c643c855228b83419394f728 (diff)
downloadrumba-2a085b29e2754500e87cbb1a90e89301671eabe8.tar.gz
rumba-2a085b29e2754500e87cbb1a90e89301671eabe8.zip
Merge branch 'master-sander' into 'master'
rhumba: Add emulab support See merge request !3
Diffstat (limited to 'rhumba.py')
-rwxr-xr-xrhumba.py175
1 files changed, 159 insertions, 16 deletions
diff --git a/rhumba.py b/rhumba.py
index d94cd9e..d8cb17c 100755
--- a/rhumba.py
+++ b/rhumba.py
@@ -1,26 +1,156 @@
#
# A library to manage ARCFIRE experiments
#
+# Sander Vrijders <[email protected]>
+# Vincenzo Maffione <[email protected]>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA
+
+import emulab_support as es
+import jfed_support as js
+import abc
+import getpass
+
+# Represents generic testbed info
+#
+# @username [string] user name
+# @password [string] password
+# @proj_name [string] project name
+# @exp_name [string] experiment name
+#
+class Testbed:
+ def __init__(self, exp_name, username, password, proj_name):
+ self.username = username
+ self.password = password
+ self.proj_name = proj_name
+ self.exp_name = exp_name
+
+ @abc.abstractmethod
+ def create_experiment(self, nodes, links):
+ return
+
+# Represents an emulab testbed info
+#
+# @url [string] URL of the testbed
+# @image [string] specific image to use
+#
+class EmulabTestbed:
+ def __init__(self, exp_name, username, password = "",
+ proj_name = "ARCFIRE", url = "wall1.ilabt.iminds.be",
+ image = "UBUNTU14-64-STD"):
+ Testbed.__init__(self, exp_name, username, password, proj_name)
+ self.url = url
+ self.image = image
+
+ def create_experiment(self, nodes, links):
+ es.create_experiment(self, nodes, links)
+ es.swap_exp_in(self)
+ es.wait_until_nodes_up(self)
+ es.complete_experiment_graph(self, nodes, links)
+
+class jFedTestbed:
+ def __init__(self, exp_name, username, cert_file, jfed_jar, exp_hours = "2",
+ proj_name = "ARCFIRE", authority = "wall2.ilabt.iminds.be"):
+ passwd = getpass.getpass(prompt = "Password for certificate file: ")
+ Testbed.__init__(self, exp_name, username, passwd, proj_name)
+ self.authority = "urn:publicid:IDN+" + authority + "+authority+cm"
+ self.cert_file = cert_file
+ self.jfed_jar = jfed_jar
+ self.exp_hours = exp_hours
+
+ def create_experiment(self, nodes, links):
+ js.create_experiment(self, nodes, links)
+
+# 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
+
+# Represents a link in the physical graph
+#
+# @name [string] Link name
+#
+class Link:
+ def __init__(self, name):
+ self.name = 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 = Interface(),
+ int_b = Interface()):
+ Link.__init__(self, name)
+ self.node_a = node_a
+ self.node_b = node_b
+ self.int_a = int_a
+ self.int_b = int_b
+
+def get_links(nodes):
+ difs = set()
+ links = list()
+ for node in 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
# Base class for DIFs
#
# @name [string] DIF name
#
class DIF:
- def __init__(self, name):
+ def __init__(self, name, members = list()):
self.name = name
+ self.members = members
def __repr__(self):
s = "DIF %s" % self.name
return s
+ def add_member(self, node):
+ self.members.append(node)
+
+ def del_member(self, node):
+ self.members.remove(node)
+
# Shim over Ethernet
#
# @link_speed [int] Speed of the Ethernet network, in Mbps
#
class ShimEthDIF(DIF):
- def __init__(self, name, link_speed = 0):
- DIF.__init__(self, name)
+ def __init__(self, name, members = list(), link_speed = 0):
+ DIF.__init__(self, name, members)
self.link_speed = int(link_speed)
if self.link_speed < 0:
raise ValueError("link_speed must be a non-negative number")
@@ -30,8 +160,8 @@ class ShimEthDIF(DIF):
# @policies [dict] Policies of the normal DIF
#
class NormalDIF(DIF):
- def __init__(self, name, policies = dict()):
- DIF.__init__(self, name)
+ def __init__(self, name, members = list(), policies = dict()):
+ DIF.__init__(self, name, members)
self.policies = policies
def add_policy(self, comp, pol):
@@ -54,12 +184,14 @@ class NormalDIF(DIF):
# @bindings: Binding of names on the processing system
#
class Node:
- def __init__(self, name, difs = set(),
+ def __init__(self, name, difs = list(),
dif_registrations = dict(),
registrations = dict(),
bindings = dict()):
self.name = name
self.difs = difs
+ for dif in difs:
+ dif.add_member(self)
self.dif_registrations = dif_registrations
self.registrations = registrations
self.bindings = bindings
@@ -90,6 +222,14 @@ class Node:
s += " ]\n"
return s
+ def add_dif(self, dif):
+ self.difs.append(dif)
+ dif.add_member(self)
+
+ def del_dif(self, dif):
+ self.difs.remove(dif)
+ dif.del_member(self)
+
def add_dif_registration(self, dif_a, dif_b):
self.dif_registrations[dif_a].append(dif_b)
@@ -114,9 +254,10 @@ class Node:
# @nodes: Nodes in the experiment
#
class Experiment:
- def __init__(self, name, nodes = set()):
+ def __init__(self, name, testbed, nodes = list()):
self.name = name
self.nodes = nodes
+ self.testbed = testbed
def __repr__(self):
s = "%s:" % self.name
@@ -132,35 +273,37 @@ class Experiment:
self.nodes.remove(node)
def run(self):
- print("[Experiment %s] start" % self.name)
- print("[Experiment %s] end" % self.name)
-
+ self.links = get_links(self.nodes)
+ self.testbed.create_experiment(self.nodes, self.links)
# An experiment over the IRATI implementation
class IRATIExperiment(Experiment):
- def __init__(self, name, nodes = set()):
- Experiment.__init__(self, name, nodes)
+ def __init__(self, name, testbed, nodes = list()):
+ Experiment.__init__(self, name, testbed, nodes)
def run(self):
print("[IRATI experiment %s] start" % self.name)
+ Experiment.run(self)
print("[IRATI experiment %s] end" % self.name)
# An experiment over the RLITE implementation
class RLITEExperiment(Experiment):
- def __init__(self, name, nodes = set()):
- Experiment.__init__(self, name, nodes)
+ def __init__(self, name, testbed, nodes = list()):
+ Experiment.__init__(self, name, testbed, nodes)
def run(self):
print("[RLITE experiment %s] start" % self.name)
+ Experiment.run(self)
print("[RLITE experiment %s] end" % self.name)
# An experiment over the Ouroboros implementation
class OuroborosExperiment(Experiment):
- def __init__(self, name, nodes = set()):
- Experiment.__init__(self, name, nodes)
+ def __init__(self, name, testbed, nodes = list()):
+ Experiment.__init__(self, name, testbed, nodes)
def run(self):
print("[Ouroboros experiment %s] start" % self.name)
+ Experiment.run(self)
print("[Ouroboros experiment %s] end" % self.name)