platforms = "Linux, OSX",
packages = [
"nepi",
- "nepi.design",
"nepi.execution",
"nepi.resources",
"nepi.resources.all",
"nepi.resources.omf",
"nepi.resources.planetlab",
"nepi.resources.planetlab.openvswitch",
- "nepi.util"],
+ "nepi.util",
+ "nepi.util.parsers"],
package_dir = {"": "src"},
package_data = {
"nepi.resources.planetlab" : [ "scripts/*.py" ],
+++ /dev/null
-#!/usr/bin/python
+++ /dev/null
-#
-# NEPI, a framework to manage network experiments
-# Copyright (C) 2013 INRIA
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
-
-from nepi.util import guid
-
-guid_gen = guid.GuidGenerator()
-
-class Attributes(object):
- def __init__(self):
- super(Attributes, self).__init__()
- self._attributes = dict()
-
- def __getattr__(self, name):
- try:
- return self._attributes[name]
- except:
- return super(Attributes, self).__getattribute__(name)
-
- def __setattr__(self, name, value):
- try:
- if value == None:
- old = self._attributes[name]
- del self._attributes[name]
- return old
-
- self._attributes[name] = value
- return value
- except:
- return super(Attributes, self).__setattr__(name, value)
-
-class Connections(object):
- def __init__(self):
- super(Connections, self).__init__()
- self._connections = set()
-
- def __getattr__(self, guid_or_label):
- try:
- for b in self._connections:
- if guid_or_label in [b.guid, b.label]:
- return b
- except:
- return super(Connections, self).__getattribute__(guid_or_label)
-
-class Box(object):
- def __init__(self, label = None, guid = None):
- super(Box, self).__init__()
- self._guid = guid_gen.next(guid)
- self._a = Attributes()
- self._c = Connections()
- self._tags = set()
- self.label = label or self._guid
-
- # Graphical information to draw box
- self.x = 0
- self.y = 0
- self.width = 4
- self.height = 4
-
- @property
- def tags(self):
- return self._tags
-
- @property
- def attributes(self):
- return self._a._attributes.keys()
-
- @property
- def a(self):
- return self._a
-
- @property
- def c(self):
- return self._c
-
- @property
- def guid(self):
- return self._guid
-
- @property
- def connections(self):
- return set(self._c._connections)
-
- def tadd(self, name):
- self._tags.add(name)
-
- def tdel(self, name):
- self._tags.remove(name)
-
- def thas(self, name):
- return name in self._tags
-
- def connect(self, box, cascade = True):
- self._c._connections.add(box)
- if cascade:
- box.connect(self, cascade = False)
-
- def disconnect(self, box, cascade = True):
- self._c._connections.remove(box)
- if cascade:
- box.disconnect(self, cascade = False)
-
- def is_connected(self, box):
- return box in self.connections
-
adequate validation"""
return True
+ @property
def has_changed(self):
""" Returns true if the value has changed from the default """
return self.value != self.default
ResourceState, ResourceState2str
from nepi.execution.scheduler import HeapScheduler, Task, TaskStatus
from nepi.execution.trace import TraceAttr
+from nepi.util.serializer import ECSerializer, SFormats
# TODO: use multiprocessing instead of threading
# TODO: Allow to reconnect to a running experiment instance! (reconnect mode vs deploy mode)
"""
+ @classmethod
+ def load(cls, path, format = SFormats.XML):
+ serializer = ECSerializer()
+ ec = serializer.load(path)
+ return ec
+
def __init__(self, exp_id = None):
super(ExperimentController, self).__init__()
# The runner is a pool of threads used to parallelize
# execution of tasks
- nthreads = int(os.environ.get("NEPI_NTHREADS", "20"))
- self._runner = ParallelRun(maxthreads = nthreads)
+ self._nthreads = 20
+ self._runner = None
# Event processing thread
self._cond = threading.Condition()
"""
return self._run_id
+ @property
+ def nthreads(self):
+ """ Returns the number of processing nthreads used
+
+ """
+ return self._nthreads
+
+
@property
def abort(self):
""" Returns True if the experiment has failed and should be interrupted,
guids.append(guid)
time.sleep(0.5)
-
+
+ def serialize(self, format = SFormats.XML):
+ serializer = ECSerializer()
+ sec = serializer.load(self, format = format)
+ return sec
+
+ def save(self, path, format = SFormats.XML):
+ serializer = ECSerializer()
+ path = serializer.save(self, path, format = format)
+ return path
+
def get_task(self, tid):
""" Returns a task by its id
def get_resource(self, guid):
""" Returns a registered ResourceManager by its guid
- :param guid: Id of the task
+ :param guid: Id of the resource
:type guid: int
:rtype: ResourceManager
rm = self._resources.get(guid)
return rm
+ def get_resources_by_type(self, rtype):
+ """ Returns a registered ResourceManager by its guid
+
+ :param rtype: Resource type
+ :type rtype: string
+
+ :rtype: list of ResourceManagers
+
+ """
+ rms = []
+ for guid, rm in self._resources.iteritems():
+ if rm.get_rtype() == type:
+ rms.append(rm)
+ return rms
+
def remove_resource(self, guid):
del self._resources[guid]
"""
+ self._nthreads = int(os.environ.get("NEPI_NTHREADS", str(self._nthreads)))
+ self._runner = ParallelRun(maxthreads = self.nthreads)
self._runner.start()
while not self._stop:
:rtype: str
"""
attr = self._attrs[name]
- return attr.has_changed()
+ return attr.has_changed
def has_flag(self, name, flag):
""" Returns true if the attribute has the flag 'flag'
+++ /dev/null
-#
-# NEPI, a framework to manage network experiments
-# Copyright (C) 2013 INRIA
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
-
-from nepi.design.box import Box
-
-from xml.dom import minidom
-import sys
-
-STRING = "string"
-BOOL = "bool"
-INTEGER = "integer"
-DOUBLE = "float"
-
-def xmlencode(s):
- if isinstance(s, str):
- rv = s.decode("latin1")
- elif not isinstance(s, unicode):
- rv = unicode(s)
- else:
- rv = s
- return rv.replace(u'\x00',u'�')
-
-def xmldecode(s):
- return s.replace(u'�',u'\x00').encode("utf8")
-
-def from_type(value):
- if isinstance(value, str):
- return STRING
- if isinstance(value, bool):
- return BOOL
- if isinstance(value, int):
- return INTEGER
- if isinstance(value, float):
- return DOUBLE
-
-def to_type(type, value):
- if type == STRING:
- return str(value)
- if type == BOOL:
- return value == "True"
- if type == INTEGER:
- return int(value)
- if type == DOUBLE:
- return float(value)
-
-class XMLParser(object):
- def to_xml(self, box):
- doc = minidom.Document()
-
- root = doc.createElement("boxes")
- doc.appendChild(root)
-
- traversed = dict()
- self._traverse_boxes(doc, traversed, box)
-
- # Keep the order
- for guid in sorted(traversed.keys()):
- bnode = traversed[guid]
- root.appendChild(bnode)
-
- try:
- xml = doc.toprettyxml(indent=" ", encoding="UTF-8")
- except:
- print >>sys.stderr, "Oops: generating XML from %s" % (data,)
- raise
-
- return xml
-
- def _traverse_boxes(self, doc, traversed, box):
- bnode = doc.createElement("box")
- bnode.setAttribute("guid", xmlencode(box.guid))
- bnode.setAttribute("label", xmlencode(box.label))
- bnode.setAttribute("x", xmlencode(box.x))
- bnode.setAttribute("y", xmlencode(box.y))
- bnode.setAttribute("width", xmlencode(box.width))
- bnode.setAttribute("height", xmlencode(box.height))
-
- traversed[box.guid] = bnode
-
- anode = doc.createElement("attributes")
- bnode.appendChild(anode)
- for name in sorted(box.attributes):
- value = getattr(box.a, name)
- aanode = doc.createElement("attribute")
- anode.appendChild(aanode)
- aanode.setAttribute("name", xmlencode(name))
- aanode.setAttribute("value", xmlencode(value))
- aanode.setAttribute("type", from_type(value))
-
- tnode = doc.createElement("tags")
- bnode.appendChild(tnode)
- for tag in sorted(box.tags):
- ttnode = doc.createElement("tag")
- tnode.appendChild(ttnode)
- ttnode.setAttribute("name", xmlencode(tag))
-
- cnode = doc.createElement("connections")
- bnode.appendChild(cnode)
- for b in sorted(box.connections):
- ccnode = doc.createElement("connection")
- cnode.appendChild(ccnode)
- ccnode.setAttribute("guid", xmlencode(b.guid))
- if b.guid not in traversed:
- self._traverse_boxes(doc, traversed, b)
-
- def from_xml(self, xml):
- doc = minidom.parseString(xml)
- bnode_list = doc.getElementsByTagName("box")
-
- boxes = dict()
- connections = dict()
-
- for bnode in bnode_list:
- if bnode.nodeType == doc.ELEMENT_NODE:
- guid = int(bnode.getAttribute("guid"))
- label = xmldecode(bnode.getAttribute("label"))
- x = float(bnode.getAttribute("x"))
- y = float(bnode.getAttribute("y"))
- height = float(bnode.getAttribute("height"))
- width = float(bnode.getAttribute("width"))
- box = Box(label=label, guid=guid)
- boxes[guid] = box
-
- anode_list = bnode.getElementsByTagName("attribute")
- for anode in anode_list:
- name = xmldecode(anode.getAttribute("name"))
- value = xmldecode(anode.getAttribute("value"))
- type = xmldecode(anode.getAttribute("type"))
- value = to_type(type, value)
- setattr(box.a, name, value)
-
- tnode_list = bnode.getElementsByTagName("tag")
- for tnode in tnode_list:
- value = xmldecode(tnode.getAttribute("name"))
- box.tadd(value)
-
- connections[box] = set()
- cnode_list = bnode.getElementsByTagName("connection")
- for cnode in cnode_list:
- guid = int(cnode.getAttribute("guid"))
- connections[box].add(guid)
-
- for box, conns in connections.iteritems():
- for guid in conns:
- b = boxes[guid]
- box.connect(b)
-
- return box
-
--- /dev/null
+#
+# NEPI, a framework to manage network experiments
+# Copyright (C) 2013 INRIA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from xml.dom import minidom
+
+import sys
+import os
+
+STRING = "string"
+BOOL = "bool"
+INTEGER = "integer"
+DOUBLE = "float"
+
+def xmlencode(s):
+ if isinstance(s, str):
+ rv = s.decode("latin1")
+ elif not isinstance(s, unicode):
+ rv = unicode(s)
+ else:
+ rv = s
+ return rv.replace(u'\x00',u'�')
+
+def xmldecode(s):
+ return s.replace(u'�',u'\x00').encode("utf8")
+
+def from_type(value):
+ if value == None:
+ return str("None")
+
+ if isinstance(value, str):
+ return STRING
+ if isinstance(value, bool):
+ return BOOL
+ if isinstance(value, int):
+ return INTEGER
+ if isinstance(value, float):
+ return DOUBLE
+
+def to_type(type, value):
+ if type == STRING:
+ if value == "None":
+ return None
+ return str(value)
+ if type == BOOL:
+ return value == "True"
+ if type == INTEGER:
+ return int(value)
+ if type == DOUBLE:
+ return float(value)
+
+class ECXMLParser(object):
+ def to_xml(self, ec):
+
+ doc = minidom.Document()
+
+ self._ec_to_xml(doc, ec)
+
+ try:
+ xml = doc.toprettyxml(indent=" ", encoding="UTF-8")
+ except:
+ print >>sys.stderr, "Oops: generating XML from %s" % (data,)
+ raise
+
+ return xml
+
+ def _ec_to_xml(self, doc, ec):
+ ecnode = doc.createElement("experiment")
+ ecnode.setAttribute("exp_id", xmlencode(ec.exp_id))
+ ecnode.setAttribute("run_id", xmlencode(ec.run_id))
+ ecnode.setAttribute("nthreads", xmlencode(ec.nthreads))
+ doc.appendChild(ecnode)
+
+ for guid, rm in ec._resources.iteritems():
+ self._rm_to_xml(doc, ecnode, ec, guid, rm)
+
+ return doc
+
+ def _rm_to_xml(self, doc, ecnode, ec, guid, rm):
+ rmnode = doc.createElement("rm")
+ rmnode.setAttribute("guid", xmlencode(guid))
+ rmnode.setAttribute("rtype", xmlencode(rm._rtype))
+ rmnode.setAttribute("state", xmlencode(rm._state))
+ if rm._start_time:
+ rmnode.setAttribute("start_time", xmlencode(rm._start_time))
+ if rm._stop_time:
+ rmnode.setAttribute("stop_time", xmlencode(rm._stop_time))
+ if rm._discover_time:
+ rmnode.setAttribute("discover_time", xmlencode(rm._discover_time))
+ if rm._provision_time:
+ rmnode.setAttribute("provision_time", xmlencode(rm._provision_time))
+ if rm._ready_time:
+ rmnode.setAttribute("ready_time", xmlencode(rm._ready_time))
+ if rm._release_time:
+ rmnode.setAttribute("release_time", xmlencode(rm._release_time))
+ if rm._failed_time:
+ rmnode.setAttribute("failed_time", xmlencode(rm._failed_time))
+ ecnode.appendChild(rmnode)
+
+ anode = doc.createElement("attributes")
+ attributes = False
+
+ for attr in rm._attrs.values():
+ if attr.has_changed:
+ attributes = True
+ aanode = doc.createElement("attribute")
+ aanode.setAttribute("name", xmlencode(attr.name))
+ aanode.setAttribute("value", xmlencode(attr.value))
+ aanode.setAttribute("type", from_type(attr.value))
+ anode.appendChild(aanode)
+
+ if attributes:
+ rmnode.appendChild(anode)
+
+ cnode = doc.createElement("connections")
+ connections = False
+
+ for guid in rm._connections:
+ connections = True
+ ccnode = doc.createElement("connection")
+ ccnode.setAttribute("guid", xmlencode(guid))
+ cnode.appendChild(ccnode)
+
+ if connections:
+ rmnode.appendChild(cnode)
+
+ cnnode = doc.createElement("conditions")
+ conditions = False
+
+ for action, conds in rm._conditions.iteritems():
+ conditions = True
+ for (group, state, time) in conds:
+ cnnode = doc.createElement("condition")
+ ccnnode.setAttribute("action", xmlencode(action))
+ ccnnode.setAttribute("group", xmlencode(group))
+ ccnnode.setAttribute("state", xmlencode(state))
+ ccnnode.setAttribute("time", xmlencode(time))
+ cnnode.appendChild(ccnnode)
+
+ if conditions:
+ rmnode.appendChild(cnnode)
+
+ tnode = doc.createElement("traces")
+ traces = False
+
+ for trace in rm._trcs.values():
+ if trace.enabled:
+ traces = True
+ ttnode = doc.createElement("trace")
+ ttnode.setAttribute("name", xmlencode(trace.name))
+ tnode.appendChild(ttnode)
+
+ if traces:
+ rmnode.appendChild(tnode)
+
+ def from_xml(self, xml):
+ doc = minidom.parseString(xml)
+ return self._ec_from_xml(doc)
+
+ def _ec_from_xml(self, doc):
+ from nepi.execution.ec import ExperimentController
+ ec = None
+
+ ecnode_list = doc.getElementsByTagName("experiment")
+ for ecnode in ecnode_list:
+ if ecnode.nodeType == doc.ELEMENT_NODE:
+ exp_id = ecnode.getAttribute("exp_id")
+ run_id = ecnode.getAttribute("run_id")
+ nthreads = int(ecnode.getAttribute("nthreads"))
+
+ os.environ["NEPI_NTHREADS"] = str(nthreads)
+ ec = ExperimentController(exp_id = exp_id)
+
+ connections = set()
+
+ rmnode_list = ecnode.getElementsByTagName("rm")
+ for rmnode in rmnode_list:
+ if rmnode.nodeType == doc.ELEMENT_NODE:
+ self._rm_from_xml(doc, rmnode, ec, connections)
+
+ for (guid1, guid2) in connections:
+ ec.register_connection(guid1, guid2)
+
+ break
+
+ return ec
+
+ def _rm_from_xml(self, doc, rmnode, ec, connections):
+ start_time = None
+ stop_time = None
+ discover_time = None
+ provision_time = None
+ ready_time = None
+ release_time = None
+ failed_time = None
+
+ guid = int(rmnode.getAttribute("guid"))
+ rtype = xmldecode(rmnode.getAttribute("rtype"))
+ state = int(rmnode.getAttribute("state"))
+
+ if rmnode.hasAttribute("start_time"):
+ start_time = xmldecode(rmnode.getAttribute("start_time"))
+ if rmnode.hasAttribute("stop_time"):
+ stop_time = xmldecode(rmnode.getAttribute("stop_time"))
+ if rmnode.hasAttribute("discover_time"):
+ dicover_time = xmldecode(rmnode.getAttribute("discover_time"))
+ if rmnode.hasAttribute("provision_time"):
+ provision_time = xmldecode(rmnode.getAttribute("provision_time"))
+ if rmnode.hasAttribute("ready_time"):
+ ready_time = xmldecode(rmnode.getAttribute("ready_time"))
+ if rmnode.hasAttribute("release_time"):
+ release_time = xmldecode(rmnode.getAttribute("release_time"))
+ if rmnode.hasAttribute("failed_time"):
+ failed_time = xmldecode(rmnode.getAttribute("failed_time"))
+
+ ec.register_resource(rtype, guid = guid)
+ rm = ec.get_resource(guid)
+ rm.set_state_time(state, "_start_time", start_time)
+ rm.set_state_time(state, "_stop_time", stop_time)
+ rm.set_state_time(state, "_discover_time", discover_time)
+ rm.set_state_time(state, "_provision_time", provision_time)
+ rm.set_state_time(state, "_ready_time", ready_time)
+ rm.set_state_time(state, "_release_time", release_time)
+ rm.set_state_time(state, "_failed_time", failed_time)
+
+ anode_list = rmnode.getElementsByTagName("attributes")
+ if anode_list:
+ aanode_list = anode_list[0].getElementsByTagName("attribute")
+ for aanode in aanode_list:
+ name = xmldecode(aanode.getAttribute("name"))
+ value = xmldecode(aanode.getAttribute("value"))
+ type = xmldecode(aanode.getAttribute("type"))
+ value = to_type(type, value)
+ rm.set(name, value)
+
+ cnode_list = rmnode.getElementsByTagName("connections")
+ if cnode_list:
+ ccnode_list = cnode_list[0].getElementsByTagName("connection")
+ for ccnode in ccnode_list:
+ guid2 = int(ccnode.getAttribute("guid"))
+ connections.add((guid, guid2))
+
+ tnode_list = rmnode.getElementsByTagName("traces")
+ if tnode_list:
+ ttnode_list = tnode_list[0].getElementsByTagName("trace")
+ for ttnode in ttnode_list:
+ name = xmldecode(ttnode.getAttribute("name"))
+ ec.enable_trace(guid, name)
+
+ cnnode_list = rmnode.getElementsByTagName("conditions")
+ if cnnode_list:
+ ccnnode_list = cnnode_list[0].getElementsByTagName("condition")
+ for ccnnode in ccnnode_list:
+ action = int(ccnnode.getAttribute("action"))
+ group = int(ccnnode.getAttribute("group"))
+ state = int(ccnnode.getAttribute("state"))
+ time = ccnnode.getAttribute("time")
+ ec.register_condition(guid, action, group, state, time = time)
+
--- /dev/null
+#
+# NEPI, a framework to manage network experiments
+# Copyright (C) 2013 INRIA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+import datetime
+import os
+
+class SFormats:
+ XML = "xml"
+
+class ECSerializer(object):
+ def load(self, path, format = SFormats.XML):
+ if format == SFormats.XML:
+ from nepi.util.parsers.xml_parser import ECXMLParser
+
+ parser = ECXMLParser()
+ f = open(path, "r")
+ xml = f.read()
+ f.close()
+
+ ec = parser.from_xml(xml)
+
+ return ec
+
+ def serialize(self, ec, format = SFormats.XML):
+ if format == SFormats.XML:
+ from nepi.util.parsers.xml_parser import ECXMLParser
+
+ parser = ECXMLParser()
+ sec = parser.to_xml(ec)
+
+ return sec
+
+ def save(self, ec, path, format = SFormats.XML):
+ date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
+ filename = "%s_%s" % (ec.exp_id, date)
+
+ if format == SFormats.XML:
+ path = os.path.join(path, "%s.xml" % filename)
+ sec = self.serialize(ec, format = format)
+ f = open(path, "w")
+ f.write(sec)
+ f.close()
+
+ return path
+
+++ /dev/null
-#!/usr/bin/env python
-#
-# NEPI, a framework to manage network experiments
-# Copyright (C) 2013 INRIA
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
-
-
-from nepi.design.box import Box
-
-import unittest
-
-class BoxDesignTestCase(unittest.TestCase):
- def test_simple_design(self):
- node1 = Box()
- node2 = Box()
-
- node1.label = "uno"
- node2.label = "dos"
-
- node1.tadd('nodo')
- node2.tadd('mynodo')
-
- self.assertEquals(node1.tags, set(['nodo']))
- self.assertEquals(node2.tags, set(['mynodo']))
-
- node1.a.hola = "chau"
- node2.a.hello = "bye"
-
- self.assertEquals(node1.a.hola, "chau")
- self.assertEquals(node2.a.hello, "bye")
-
- node1.connect(node2)
-
- self.assertEquals(node1.connections, set([node2]))
- self.assertEquals(node2.connections, set([node1]))
- self.assertTrue(node1.is_connected(node2))
- self.assertTrue(node2.is_connected(node1))
-
- self.assertEquals(node1.c.dos.a.hello, "bye")
- self.assertEquals(node2.c.uno.a.hola, "chau")
-
- node2.disconnect(node1)
-
- self.assertEquals(node1.connections, set([]))
- self.assertEquals(node2.connections, set([]))
- self.assertFalse(node1.is_connected(node2))
- self.assertFalse(node2.is_connected(node1))
-
- self.assertRaises(AttributeError, node1.c.dos)
- self.assertRaises(AttributeError, node2.c.uno)
-
-
-if __name__ == '__main__':
- unittest.main()
-
+++ /dev/null
-#!/usr/bin/env python
-#
-# NEPI, a framework to manage network experiments
-# Copyright (C) 2013 INRIA
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
-
-
-from nepi.design.box import Box
-from nepi.util.parser import XMLParser
-
-import unittest
-
-class BoxDesignTestCase(unittest.TestCase):
- def test_to_xml(self):
- node1 = Box()
- node2 = Box()
-
- node1.label = "node1"
- node2.label = "node2"
-
- node1.connect(node2)
-
- node1.a.dog = "cat"
- node1.a.one = "two"
- node1.a.t = "q"
-
- node1.c.node2.a.sky = "sea"
- node2.a.bee = "honey"
-
- node1.tadd("unooo")
- node2.tadd("dosss")
-
- parser = XMLParser()
- xml = parser.to_xml(node1)
-
- node = parser.from_xml(xml)
- xml2 = parser.to_xml(node)
-
- self.assertEquals(xml, xml2)
-
-if __name__ == '__main__':
- unittest.main()
-
--- /dev/null
+#!/usr/bin/env python
+#
+# NEPI, a framework to manage network experiments
+# Copyright (C) 2013 INRIA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.ec import ExperimentController
+from nepi.execution.resource import ResourceManager, ResourceState, \
+ clsinit_copy, ResourceAction, ResourceFactory
+
+import tempfile
+import time
+import unittest
+
+reschedule_delay = "0.5s"
+deploy_time = 0
+run_time = 0
+
+class Link(ResourceManager):
+ _rtype = "dummy::Link"
+ def do_deploy(self):
+ time.sleep(deploy_time)
+ super(Link, self).do_deploy()
+ self.logger.debug(" -------- DEPLOYED ------- ")
+
+class Interface(ResourceManager):
+ _rtype = "dummy::Interface"
+
+ def do_deploy(self):
+ node = self.get_connected(Node.get_rtype())[0]
+ link = self.get_connected(Link.get_rtype())[0]
+
+ if node.state < ResourceState.READY or \
+ link.state < ResourceState.READY:
+ self.ec.schedule(reschedule_delay, self.deploy)
+ self.logger.debug(" -------- RESCHEDULING ------- ")
+ else:
+ time.sleep(deploy_time)
+ super(Interface, self).do_deploy()
+ self.logger.debug(" -------- DEPLOYED ------- ")
+
+class Node(ResourceManager):
+ _rtype = "dummy::Node"
+
+ def do_deploy(self):
+ self.logger.debug(" -------- DO_DEPLOY ------- ")
+ time.sleep(deploy_time)
+ super(Node, self).do_deploy()
+ self.logger.debug(" -------- DEPLOYED ------- ")
+
+class Application(ResourceManager):
+ _rtype = "dummy::Application"
+
+ def do_deploy(self):
+ node = self.get_connected(Node.get_rtype())[0]
+
+ if node.state < ResourceState.READY:
+ self.ec.schedule(reschedule_delay, self.deploy)
+ self.logger.debug(" -------- RESCHEDULING ------- ")
+ else:
+ time.sleep(deploy_time)
+ super(Application, self).do_deploy()
+ self.logger.debug(" -------- DEPLOYED ------- ")
+
+ def do_start(self):
+ super(Application, self).do_start()
+ time.sleep(run_time)
+ self.ec.schedule("0s", self.stop)
+
+ResourceFactory.register_type(Application)
+ResourceFactory.register_type(Node)
+ResourceFactory.register_type(Interface)
+ResourceFactory.register_type(Link)
+
+class SerializeTestCase(unittest.TestCase):
+ def test_serialize(self):
+ node_count = 4
+ app_count = 2
+
+ dirpath = tempfile.mkdtemp()
+
+ ec = ExperimentController(exp_id = "serialize-test")
+
+ # Add simulated nodes and applications
+ nodes = list()
+ apps = list()
+ ifaces = list()
+
+ for i in xrange(node_count):
+ node = ec.register_resource("dummy::Node")
+ nodes.append(node)
+
+ iface = ec.register_resource("dummy::Interface")
+ ec.register_connection(node, iface)
+ ifaces.append(iface)
+
+ for i in xrange(app_count):
+ app = ec.register_resource("dummy::Application")
+ ec.register_connection(node, app)
+ apps.append(app)
+
+ link = ec.register_resource("dummy::Link")
+
+ for iface in ifaces:
+ ec.register_connection(link, iface)
+
+ filepath = ec.save(dirpath)
+ print filepath
+
+ ec.deploy()
+
+ # Wait until nodes and apps are deployed
+ ec.wait_finished(apps)
+
+ # Do the experiment controller shutdown
+ ec.shutdown()
+
+ ec2 = ExperimentController.load(filepath)
+ apps = ec2.get_resources_by_type("dummy::Application")
+ ec2.deploy()
+ ec2.wait_finished(apps)
+ ec2.shutdown()
+
+ self.assertEquals(len(ec.resources), len(ec2.resources))
+
+
+if __name__ == '__main__':
+ unittest.main()
+