Remote ns-3 with ping working
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Sun, 9 Feb 2014 02:01:18 +0000 (03:01 +0100)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Sun, 9 Feb 2014 02:01:18 +0000 (03:01 +0100)
12 files changed:
src/nepi/resources/linux/application.py
src/nepi/resources/linux/ns3/ns3client.py
src/nepi/resources/linux/ns3/ns3simulation.py
src/nepi/resources/ns3/ns3application.py
src/nepi/resources/ns3/ns3base.py
src/nepi/resources/ns3/ns3client.py
src/nepi/resources/ns3/ns3server.py
src/nepi/resources/ns3/ns3simulation.py
src/nepi/resources/ns3/ns3wrapper.py
test/resources/linux/ns3/ns3client.py
test/resources/linux/ns3/ns3simulation.py
test/resources/ns3/ns3wrapper.py

index 642b287..4e9cce7 100644 (file)
@@ -593,7 +593,7 @@ class LinuxApplication(ResourceManager):
                             sudo = self._sudo_kill)
 
                     # TODO: check if execution errors occurred
-                    if proc.poll() or err:
+                    if (proc and proc.poll()) or err:
                         msg = " Failed to STOP command '%s' " % self.get("command")
                         self.error(msg, out, err)
         
index 59b0458..76a37bf 100644 (file)
@@ -94,16 +94,19 @@ class LinuxNS3Client(NS3Client):
 
         return self.send_msg(NS3WrapperMessage.GET, *args)
 
-    def trace(self, *args):
-        return self.send_msg(NS3WrapperMessage.TRACE, *args)
+    def enable_trace(self, *args):
+        return self.send_msg(NS3WrapperMessage.ENABLE_TRACE, *args)
+
+    def flush(self):
+        return self.send_msg(NS3WrapperMessage.FLUSH, [])
 
     def start(self):
         return self.send_msg(NS3WrapperMessage.START, [])
 
     def stop(self, time = None):
-        args = None
+        args = []
         if time:
-            args = [time]
+            args.append(time)
 
         return self.send_msg(NS3WrapperMessage.STOP, *args)
 
index e3d41f7..6fbcb73 100644 (file)
@@ -35,7 +35,8 @@ class LinuxNS3Simulation(LinuxApplication, NS3Simulation):
     @classmethod
     def _register_attributes(cls):
         ns_log = Attribute("nsLog",
-            "NS_LOG environment variable ",
+            "NS_LOG environment variable. " \
+                    " Will only generate output if ns-3 is compiled in DEBUG mode. ",
             flags = Flags.Design)
 
         verbose = Attribute("verbose",
@@ -70,6 +71,10 @@ class LinuxNS3Simulation(LinuxApplication, NS3Simulation):
 
         return os.path.join("/", "tmp", self.socket_name)
 
+    def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0):
+        self._client.flush() 
+        return LinuxApplication.trace(self, name, attr, block, offset)
+
     def upload_sources(self):
         self.node.mkdir(os.path.join(self.node.src_dir, "ns3wrapper"))
 
@@ -156,6 +161,7 @@ class LinuxNS3Simulation(LinuxApplication, NS3Simulation):
         self.info("Starting ns-3 simulation")
 
         if self.state == ResourceState.READY:
+            self._client.start() 
             self.set_started()
         else:
             msg = " Failed to execute command '%s'" % command
@@ -167,7 +173,8 @@ class LinuxNS3Simulation(LinuxApplication, NS3Simulation):
 
         """
         if self.state == ResourceState.STARTED:
-            # TODO: Stop simulation
+            self._client.stop() 
+            self._client.shutdown()
             LinuxApplication.do_stop(self)
 
     def do_release(self):
@@ -178,8 +185,6 @@ class LinuxNS3Simulation(LinuxApplication, NS3Simulation):
             self.node.execute(tear_down)
 
         self.do_stop()
-
-        self._client.shutdown()
         
         super(LinuxApplication, self).do_release()
 
@@ -193,12 +198,10 @@ class LinuxNS3Simulation(LinuxApplication, NS3Simulation):
         ns_log = self.get("nsLog")
         if ns_log:
             command.append("-L %s" % ns_log)
+
         if self.get("verbose"):
             command.append("-v")
 
-        command.append("-H")
-        command.append(self.run_home)
-        
         command = " ".join(command)
         return command
 
index c30a00c..aa11a72 100644 (file)
@@ -17,7 +17,7 @@
 #
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 
-from nepi.execution.resource import clsinit_copy
+from nepi.execution.resource import clsinit_copy, ResourceState
 from nepi.resources.ns3.ns3base import NS3Base
 
 @clsinit_copy
@@ -48,7 +48,6 @@ class NS3BaseApplication(NS3Base):
             self.simulation.invoke(node.uuid, "AddApplication", self.uuid)
             self._connected.add(node.uuid)
 
-
     def do_stop(self):
         if self.state == ResourceState.STARTED:
             # No need to do anything, simulation.Destroy() will stop every object
@@ -58,27 +57,10 @@ class NS3BaseApplication(NS3Base):
 
     @property
     def state(self):
-        #if self._state == ResourceState.STARTED:
+        if self._state == ResourceState.STARTED:
+            is_running = self.simulation.invoke(self.uuid, "isAppRunning")
+            if not is_running:
+                self._state = ResourceState.STOPPED
 
         return self._state
-        """
-        now = testbed_instance.ns3.Simulator.Now()
-        if now.IsZero():
-            return STATUS_NOT_STARTED
-        app = testbed_instance.elements[guid]
-        parameters = testbed_instance._get_parameters(guid)
-        if "StartTime" in parameters and parameters["StartTime"]:
-            start_value = parameters["StartTime"]
-            start_time = testbed_instance.ns3.Time(start_value)
-            if now.Compare(start_time) < 0:
-                return STATUS_NOT_STARTED
-        if "StopTime" in parameters and parameters["StopTime"]:
-            stop_value = parameters["StopTime"]
-            stop_time = testbed_instance.ns3.Time(stop_value)
-            if now.Compare(stop_time) < 0:
-                return STATUS_RUNNING
-            else:
-                return STATUS_FINISHED
-        return STATUS_UNDETERMINED
-        """
 
index adcbb8b..358011a 100644 (file)
@@ -29,6 +29,8 @@ class NS3Base(ResourceManager):
     _rtype = "abstract::ns3::Object"
     _backend_type = "ns3"
 
+    SIMULATOR_UUID = "singleton::Simulator"
+
     def __init__(self, ec, guid):
         super(NS3Base, self).__init__(ec, guid)
         self._uuid = None
index 86bb77b..c9e6d77 100644 (file)
@@ -40,6 +40,9 @@ class NS3Client(object):
     def trace(self, *args):
         pass
 
+    def flush(self):
+        pass
+
     def start(self):
         pass
 
index becf605..0b27a68 100644 (file)
@@ -35,7 +35,8 @@ class NS3WrapperMessage:
     INVOKE = "INVOKE"
     SET = "SET"
     GET = "GET"
-    TRACE = "TRACE"
+    ENABLE_TRACE = "ENABLE_TRACE"
+    FLUSH = "FLUSH"
     START = "START"
     STOP = "STOP"
     SHUTDOWN = "SHUTDOWN"
@@ -85,7 +86,8 @@ def handle_message(ns3_wrapper, msg, args):
         uuid = args.pop(0)
         operation = args.pop(0)
         
-        ns3_wrapper.logger.debug("INVOKE %s %s %s" % (uuid, operation, str(args)))
+        ns3_wrapper.logger.debug("INVOKE %s %s %s " % (uuid, operation, 
+            str(args)))
     
         uuid = ns3_wrapper.invoke(uuid, operation, *args)
         return uuid
@@ -104,14 +106,26 @@ def handle_message(ns3_wrapper, msg, args):
         name = args.pop(0)
         value = args.pop(0)
 
-        ns3_wrapper.logger.debug("SET %s %s" % (uuid, name, str(value)))
+        ns3_wrapper.logger.debug("SET %s %s %s" % (uuid, name, str(value)))
 
         value = ns3_wrapper.set(uuid, name, value)
         return value
  
-    if msg == NS3WrapperMessage.TRACE:
-        ns3_wrapper.logger.debug("TRACE") 
-        return "NOT IMPLEMENTED"
+    if msg == NS3WrapperMessage.ENABLE_TRACE:
+        ns3_wrapper.logger.debug("ENABLE_TRACE")
+
+        return "NOT YET IMPLEMENTED"
+    if msg == NS3WrapperMessage.FLUSH:
+        # Forces flushing output and error streams.
+        # NS-3 output will stay unflushed until the program exits or 
+        # explicit invocation flush is done
+        sys.stdout.flush()
+        sys.stderr.flush()
+
+        ns3_wrapper.logger.debug("FLUSHED") 
+        
+        return "FLUSHED"
 
 def create_socket(socket_name):
     sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -157,7 +171,7 @@ def send_reply(conn, reply):
     conn.send("%s\n" % encoded)
 
 def get_options():
-    usage = ("usage: %prog -S <socket-name> -L <NS_LOG> -H <home_dir> -v ")
+    usage = ("usage: %prog -S <socket-name> -L <NS_LOG> -v ")
     
     parser = OptionParser(usage = usage)
 
@@ -169,10 +183,6 @@ def get_options():
         help = "NS_LOG environmental variable to be set", 
         default = "", type="str")
 
-    parser.add_option("-H", "--homedir", dest="homedir",
-        help = "Home directory where to store results", 
-        default = "", type="str")
-
     parser.add_option("-v", "--verbose",
         help="Print debug output",
         action="store_true", 
@@ -180,11 +190,9 @@ def get_options():
 
     (options, args) = parser.parse_args()
     
-    return (options.socket_name, options.homedir, options.verbose, 
-            options.ns_log)
+    return (options.socket_name, options.verbose, options.ns_log)
 
-def run_server(socket_name, homedir = None, level = logging.INFO, 
-        ns_log = None):
+def run_server(socket_name, level = logging.INFO, ns_log = None):
 
     # Sets NS_LOG environmental variable for NS debugging
     if ns_log:
@@ -192,7 +200,7 @@ def run_server(socket_name, homedir = None, level = logging.INFO,
 
     ###### ns-3 wrapper instantiation
 
-    ns3_wrapper = NS3Wrapper(homedir = homedir, loglevel=level)
+    ns3_wrapper = NS3Wrapper(loglevel=level)
     
     ns3_wrapper.logger.info("STARTING...")
 
@@ -237,7 +245,7 @@ def run_server(socket_name, homedir = None, level = logging.INFO,
 
 if __name__ == '__main__':
             
-    (socket_name, homedir, verbose, ns_log) = get_options()
+    (socket_name, verbose, ns_log) = get_options()
 
     ## configure logging
     FORMAT = "%(asctime)s %(name)s %(levelname)-4s %(message)s"
@@ -245,12 +253,6 @@ if __name__ == '__main__':
 
     logging.basicConfig(format = FORMAT, level = level)
 
-    # Make sure to send DEBUG messages to stdout instead of stderr
-    root = logging.getLogger()
-    handler = logging.StreamHandler(sys.stdout)
-    handler.setLevel(logging.DEBUG)
-    root.addHandler(handler)
-
     ## Run the server
-    run_server(socket_name, homedir, level, ns_log)
+    run_server(socket_name, level, ns_log)
 
index 2baf1a3..abcf847 100644 (file)
@@ -37,8 +37,11 @@ class NS3Simulation(object):
     def get(self, uuid, name):
         return self.client.get(uuid, name)
 
-    def trace(self, *args):
-        return self.client.trace(*args)
+    def enable_trace(self, *args):
+        return self.client.enable_trace(*args)
+
+    def flush(self):
+        return self.client.flush()
 
     def start(self):
         return self.client.start()
index 9f84db7..00245bb 100644 (file)
@@ -94,26 +94,18 @@ def load_ns3_module():
     return ns3mod
 
 class NS3Wrapper(object):
-    def __init__(self, homedir = None, loglevel = logging.INFO):
+    def __init__(self, loglevel = logging.INFO):
         super(NS3Wrapper, self).__init__()
         # Thread used to run the simulation
         self._simulation_thread = None
         self._condition = None
 
-        # XXX: Started should be global. There is no support for more than
-        # one simulator per process
+        # True if Simulator::Run was invoked
         self._started = False
 
         # holds reference to all C++ objects and variables in the simulation
         self._objects = dict()
 
-        # create home dir (where all simulation related files will end up)
-        self._homedir = homedir or os.path.join("/", "tmp", "ns3_wrapper" )
-        
-        home = os.path.normpath(self.homedir)
-        if not os.path.exists(home):
-            os.makedirs(home, 0755)
-
         # Logging
         self._logger = logging.getLogger("ns3wrapper")
         self._logger.setLevel(loglevel)
@@ -161,10 +153,6 @@ class NS3Wrapper(object):
         
         return self._allowed_types
 
-    @property
-    def homedir(self):
-        return self._homedir
-
     @property
     def logger(self):
         return self._logger
@@ -217,11 +205,14 @@ class NS3Wrapper(object):
         return uuid
 
     def invoke(self, uuid, operation, *args):
+        if operation == "isAppRunning":
+            return self._is_app_running(uuid)
+
         if uuid.startswith(SINGLETON):
             obj = self._singleton(uuid)
         else:
             obj = self.get_object(uuid)
-    
+        
         method = getattr(obj, operation)
 
         # arguments starting with 'uuid' identify ns-3 C++
@@ -231,8 +222,8 @@ class NS3Wrapper(object):
         result = method(*realargs)
 
         if not result:
-            return None
-        
+            return result
+       
         newuuid = self.make_uuid()
         self._objects[newuuid] = result
 
@@ -253,11 +244,15 @@ class NS3Wrapper(object):
         # to set the value by scheduling an event, else
         # we risk to corrupt the state of the
         # simulation.
+        
+        event_executed = [False]
+
         if self.is_running:
             # schedule the event in the Simulator
-            self._schedule_event(self._condition, self._set_attr, 
-                    obj, name, ns3_value)
-        else:
+            self._schedule_event(self._condition, event_executed, 
+                    self._set_attr, obj, name, ns3_value)
+
+        if not event_executed[0]:
             self._set_attr(obj, name, ns3_value)
 
         return value
@@ -270,12 +265,15 @@ class NS3Wrapper(object):
         type_name = obj.GetInstanceTypeId().GetName()
         ns3_value = self._create_attr_ns3_value(type_name, name)
 
+        event_executed = [False]
+
         if self.is_running:
             # schedule the event in the Simulator
-            self._schedule_event(self._condition, self._get_attr, obj,
-                    name, ns3_value)
-        else:
-            get_attr(obj, name, ns3_value)
+            self._schedule_event(self._condition, event_executed,
+                    self._get_attr, obj, name, ns3_value)
+
+        if not event_executed[0]:
+            self._get_attr(obj, name, ns3_value)
 
         return self._attr_from_ns3_value_to_string(type_name, name, ns3_value)
 
@@ -301,7 +299,6 @@ class NS3Wrapper(object):
             #self.logger.debug("Waiting for simulation to finish")
             time.sleep(0.5)
         
-        # TODO!!!! SHOULD WAIT UNTIL THE THREAD FINISHES
         if self._simulator_thread:
             self._simulator_thread.join()
         
@@ -322,17 +319,16 @@ class NS3Wrapper(object):
         condition.notifyAll()
         condition.release()
 
-    def _schedule_event(self, condition, func, *args):
+    def _schedule_event(self, condition, event_executed, func, *args):
         """ Schedules event on running simulation, and wait until
             event is executed"""
 
-        def execute_event(contextId, condition, has_event_occurred, func, *args):
+        def execute_event(contextId, condition, event_executed, func, *args):
             try:
                 func(*args)
+                event_executed[0] = True
             finally:
-                # flag event occured
-                has_event_occurred[0] = True
-                # notify condition indicating attribute was set
+                # notify condition indicating event was executed
                 condition.acquire()
                 condition.notifyAll()
                 condition.release()
@@ -342,21 +338,16 @@ class NS3Wrapper(object):
 
         # delay 0 means that the event is expected to execute inmediately
         delay = self.ns3.Seconds(0)
+    
+        # Mark event as not executed
+        event_executed[0] = False
 
-        # flag to indicate that the event occured
-        # because bool is an inmutable object in python, in order to create a
-        # bool flag, a list is used as wrapper
-        has_event_occurred = [False]
         condition.acquire()
-
-        simu = self.ns3.Simulator
-
         try:
-            if not simu.IsFinished():
-                simu.ScheduleWithContext(contextId, delay, execute_event,
-                     condition, has_event_occurred, func, *args)
-                while not has_event_occurred[0] and not simu.IsFinished():
-                    condition.wait()
+            self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event, 
+                    condition, event_executed, func, *args)
+            if not self.ns3.Simulator.IsFinished():
+                condition.wait()
         finally:
             condition.release()
 
@@ -432,3 +423,19 @@ class NS3Wrapper(object):
 
         return realargs
 
+    def _is_app_running(self, uuid): 
+        now = self.ns3.Simulator.Now()
+        if now.IsZero():
+            return False
+
+        stop_value = self.get(uuid, "StopTime")
+        stop_time = self.ns3.Time(stop_value)
+        
+        start_value = self.get(uuid, "StartTime")
+        start_time = self.ns3.Time(start_value)
+        
+        if now.Compare(start_time) >= 0 and now.Compare(stop_time) <= 0:
+            return True
+
+        return False
+
index aea015b..afe7586 100644 (file)
@@ -38,6 +38,15 @@ import threading
 import time
 import unittest
 
+class DummySimulation(object):
+    def __init__(self, socket_name):
+        self.socket_name = socket_name
+        self.node = dict({'hostname': 'localhost'})
+
+    @property
+    def local_socket(self):
+        return self.socket_name
+
 class LinuxNS3ClientTest(unittest.TestCase):
     def setUp(self):
         self.socket_name = os.path.join("/", "tmp", "NS3WrapperServer.sock")
@@ -59,8 +68,11 @@ class LinuxNS3ClientTest(unittest.TestCase):
         # Verify that the communication socket was created
         self.assertTrue(os.path.exists(self.socket_name))
 
+        # Create a dummy simulation object
+        simulation = DummySimulation(self.socket_name) 
+
         # Instantiate the NS3 client
-        client = LinuxNS3Client(self.socket_name)
+        client = LinuxNS3Client(simulation)
  
         # Define a real time simulation 
         stype = client.create("StringValue", "ns3::RealtimeSimulatorImpl")
@@ -181,6 +193,7 @@ class LinuxNS3ClientTest(unittest.TestCase):
         # wait until simulation is over
         client.shutdown()
 
+        ## TODO: Add assertions !!
 
 if __name__ == '__main__':
     unittest.main()
index cf08f0e..53c03a2 100644 (file)
@@ -36,22 +36,23 @@ import time
 import unittest
 
 class LinuxNS3ClientTest(unittest.TestCase):
-    def test_runtime_attr_modify(self):
-        ssh_key = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
+    def setUp(self):
+        self.fedora_host = "nepi2.pl.sophia.inria.fr"
+        #self.fedora_host = "peeramide.irisa.fr"
+        self.fedora_user = "inria_test"
 
+    def test_simple_ping(self):
         ec = ExperimentController(exp_id = "test-ns3-simu")
         
         node = ec.register_resource("LinuxNode")
-        #ec.set(node, "hostname", "roseval.pl.sophia.inria.fr")
-        #ec.set(node, "username", "alina")
-        ec.set(node, "hostname", "peeramide.irisa.fr")
-        #ec.set(node, "hostname", "planetlab2.upc.es")
-        ec.set(node, "username", "inria_alina")
-        ec.set(node, "identity", ssh_key)
+        ec.set(node, "hostname", self.fedora_host)
+        ec.set(node, "username", self.fedora_user)
         ec.set(node, "cleanProcesses", True)
+        ec.set(node, "cleanHome", True)
 
         simu = ec.register_resource("LinuxNS3Simulation")
         ec.set(simu, "verbose", True)
+        ec.set(simu, "nsLog", "V4Ping:Node")
         ec.register_connection(simu, node)
 
         nsnode1 = ec.register_resource("ns3::Node")
@@ -109,9 +110,12 @@ class LinuxNS3ClientTest(unittest.TestCase):
 
         ec.deploy()
 
-        #time.sleep(60)
-        ec.wait_started([ping])
-        #ec.wait_finised([ping])
+        ec.wait_finished([ping])
+        
+        stdout = ec.trace(simu, "stdout") 
+
+        expected = "20 packets transmitted, 20 received, 0% packet loss"
+        self.assertTrue(stdout.find(expected) > -1)
 
         ec.shutdown()
 
index 3843864..8765761 100755 (executable)
@@ -32,7 +32,9 @@
 
 from nepi.resources.ns3.ns3wrapper import NS3Wrapper
 
+import StringIO
 import subprocess
+import sys
 import time
 import unittest
 
@@ -218,6 +220,7 @@ class NS3WrapperTest(unittest.TestCase):
         p.communicate()
 
     def test_start(self):
+        # Instantiate ns-3
         wrapper = NS3Wrapper()
 
         ### create 2  nodes
@@ -291,6 +294,8 @@ class NS3WrapperTest(unittest.TestCase):
         # wait until simulation is over
         wrapper.shutdown()
 
+        # TODO: Add assertions !!
+
     def test_runtime_attr_modify(self):
         wrapper = NS3Wrapper()
        
@@ -416,6 +421,8 @@ class NS3WrapperTest(unittest.TestCase):
 
         p = subprocess.Popen("rm /tmp/trace-p2p-*",  shell = True)
         p.communicate()
+        
+        # TODO: Add assertions !!
 
 if __name__ == '__main__':
     unittest.main()