Adding LinuxUdpTest RM
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Wed, 17 Jul 2013 22:54:27 +0000 (15:54 -0700)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Wed, 17 Jul 2013 22:54:27 +0000 (15:54 -0700)
src/nepi/resources/linux/udptest.py [new file with mode: 0644]
test/lib/test_utils.py
test/resources/linux/udptest.py [new file with mode: 0755]
test/resources/planetlab/udptunnel.py

diff --git a/src/nepi/resources/linux/udptest.py b/src/nepi/resources/linux/udptest.py
new file mode 100644 (file)
index 0000000..dbb0813
--- /dev/null
@@ -0,0 +1,376 @@
+#
+#    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.attribute import Attribute, Flags, Types
+from nepi.execution.resource import ResourceManager, clsinit_copy, ResourceState, \
+        reschedule_delay
+from nepi.execution.resource import clsinit_copy 
+from nepi.resources.linux.application import LinuxApplication
+from nepi.util.timefuncs import tnow
+
+import os
+
+@clsinit_copy
+class LinuxUdpTest(LinuxApplication):
+    """ Uses the hpcbench udptest tool to gather UDP measurements.
+    Measurements require two ends, a server and a client RM.
+
+    http://hpcbench.sourceforge.net/
+    """
+    _rtype = "LinuxUdpTest"
+
+    @classmethod
+    def _register_attributes(cls):
+        s = Attribute("s",
+            "Runs in server mode. ",
+            type = Types.Bool,
+            default = False,
+            flags = Flags.ExecReadOnly)
+
+        p = Attribute("p",
+            "Port to listen to in server mode, or to connect to in client mode. "
+            "Defaults to 5678. ",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        a = Attribute("a",
+            "Client option. Perform UDP Round Trip Time (latency) ",
+            type = Types.Bool,
+            flags = Flags.ExecReadOnly)
+
+        A = Attribute("A",
+            "Client option. "
+            "Message size for UDP RTT test. "
+            "UDP RTT (latency) test with specified message size.",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        b = Attribute("b",
+            "Client option. "
+            "Client UDP buffer size in bytes. Using system default "
+            "value if not defined.",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        B = Attribute("B",
+            "Client option. "
+            "Server UDP buffer size in bytes. The same as cleint's by default.",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        c = Attribute("c",
+            "Client option. "
+            "CPU log option. Tracing system info during the test. "
+            "Only available when output is defined. ",
+            type = Types.Bool,
+            flags = Flags.ExecReadOnly)
+
+        d = Attribute("d",
+            "Client option. "
+            "Data size of each read/write in bytes. The same as packet size "
+            "by default.",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        e = Attribute("e",
+            "Client option. "
+            "Exponential test (data size of each sending increasing from 1 "
+            "byte to packet size). ",
+            type = Types.Bool,
+            flags = Flags.ExecReadOnly)
+
+        g = Attribute("g",
+            "Client option. "
+            "UDP traffic generator (Keep sending data to a host). "
+            "Work without server's support.",
+            type = Types.Bool,
+            flags = Flags.ExecReadOnly)
+
+        target = Attribute("target",
+            "Client option. "
+            "Hostname or IP address of UDP server. Must be specified.",
+            flags = Flags.ExecReadOnly)
+
+        i = Attribute("i",
+            "Client option. "
+            "Bidirectional UDP throuhgput test. Default is unidirection "
+            "stream test. ",
+            type = Types.Bool,
+            flags = Flags.ExecReadOnly)
+
+        l = Attribute("l",
+            "Client option. "
+            "UDP datagram (packet) size in bytes ( < udp-buffer-szie ). "
+            "1460 by default.",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        m = Attribute("m",
+            "Client option. "
+            "Total message size in bytes. 1048576 by default.",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        o = Attribute("o",
+            "Client option. "
+            "Output file name. ",
+            flags = Flags.ExecReadOnly)
+
+        P = Attribute("P",
+            "Client option. "
+            "Write the plot file for gnuplot. Only enable when the output "
+            "is specified. ",
+            type = Types.Bool,
+            flags = Flags.ExecReadOnly)
+
+        q = Attribute("q",
+            "Client option. "
+            "Define the TOS field of IP packets. "
+            "Six values can be used for this setting:\n"
+            " 1:(IPTOS)-Minimize delay\n"
+            " 2:(IPTOS)-Maximize throughput\n"
+            " 3:(DiffServ)-Class1 with low drop probability\n"
+            " 4:(DiffServ)-class1 with high drop probability\n"
+            " 5:(DiffServ)-Class4 with low drop probabiltiy\n"
+            " 6:(DiffServ)-Class4 with high drop probabiltiy\n"
+            "Write the plot file for gnuplot. Only enable when the output "
+            "is specified. ",
+            type = Types.Enumerate,
+            allowed = ["1", "2", "3", "4", "5", "6"],
+            flags = Flags.ExecReadOnly)
+
+        r = Attribute("r",
+            "Client option. "
+            "Repetition of tests. 10 by default. ",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        t = Attribute("t",
+            "Client option. "
+            "Test time constraint in seconds. 5 by default. ",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        T = Attribute("T",
+            "Client option. "
+            "Throughput constraint for UDP generator or throughput "
+            "test. Unlimited by default. ",
+            type = Types.Integer,
+            flags = Flags.ExecReadOnly)
+
+        continuous = Attribute("continuous",
+            "Run nping in a while loop",
+            type = Types.Bool,
+            default = False,
+            flags = Flags.ExecReadOnly)
+
+        print_timestamp = Attribute("printTimestamp",
+            "Print timestamp before running nping",
+            type = Types.Bool,
+            default = False,
+            flags = Flags.ExecReadOnly)
+
+        cls._register_attribute(s)
+        cls._register_attribute(p)
+        cls._register_attribute(a)
+        cls._register_attribute(A)
+        cls._register_attribute(b)
+        cls._register_attribute(B)
+        cls._register_attribute(c)
+        cls._register_attribute(d)
+        cls._register_attribute(e)
+        cls._register_attribute(g)
+        cls._register_attribute(target)
+        cls._register_attribute(g)
+        cls._register_attribute(i)
+        cls._register_attribute(l)
+        cls._register_attribute(m)
+        cls._register_attribute(o)
+        cls._register_attribute(P)
+        cls._register_attribute(q)
+        cls._register_attribute(r)
+        cls._register_attribute(t)
+        cls._register_attribute(T)
+        cls._register_attribute(continuous)
+        cls._register_attribute(print_timestamp)
+
+    def __init__(self, ec, guid):
+        super(LinuxUdpTest, self).__init__(ec, guid)
+        self._home = "udptest-%s" % self.guid
+
+    def deploy(self):
+        if not self.get("command"):
+            self.set("command", self._start_command)
+
+        if not self.get("sources"):
+            self.set("sources", self._sources)
+
+        if not self.get("install"):
+            self.set("install", self._install)
+
+        if not self.get("build"):
+            self.set("build", self._build)
+
+        if not self.get("env"):
+            self.set("env", self._environment)
+
+        if not self.get("depends"):
+            self.set("depends", self._depends)
+
+        super(LinuxUdpTest, self).deploy()
+
+    def upload_start_command(self):
+
+        super(LinuxUdpTest, self).upload_start_command()
+
+        if self.get("s") == True:
+            # We want to make sure the server is running
+            # before the client starts.
+            # Run the command as a bash script in background,
+            # in the host ( but wait until the command has
+            # finished to continue )
+            self._run_in_background()
+    
+    def start(self):
+        if self.get("s") == True:
+            # Server is already running
+            if self._state == ResourceState.READY:
+                command = self.get("command")
+                self.info("Starting command '%s'" % command)
+
+                self._start_time = tnow()
+                self._state = ResourceState.STARTED
+            else:
+                msg = " Failed to execute command '%s'" % command
+                self.error(msg, out, err)
+                self._state = ResourceState.FAILED
+                raise RuntimeError, msg
+        else:
+            super(LinuxUdpTest, self).start()
+    @property
+    def _start_command(self):
+        args = []
+        if self.get("continuous") == True:
+            args.append("while true; do ")
+
+        if self.get("printTimestamp") == True:
+            args.append("""echo "`date +'%Y%m%d%H%M%S'`";""")
+
+        if self.get("s") == True:
+            args.append("udpserver")
+        else:
+            args.append("udptest")
+
+        if self.get("p"):
+            args.append("-p %d" % self.get("p"))
+        if self.get("a") == True:
+            args.append("-a")
+        if self.get("A"):
+            args.append("-A %d" % self.get("A"))
+        if self.get("b"):
+            args.append("-b %d" % self.get("b"))
+        if self.get("B"):
+            args.append("-B %d" % self.get("B"))
+        if self.get("c") == True:
+            args.append("-c")
+        if self.get("d"):
+            args.append("-d %d" % self.get("d"))
+        if self.get("e") == True:
+            args.append("-e")
+        if self.get("g") == True:
+            args.append("-g")
+        if self.get("target"):
+            args.append("-h %s" % self.get("target"))
+        if self.get("i") == True:
+            args.append("-i")
+        if self.get("l"):
+            args.append("-l %d" % self.get("l"))
+        if self.get("m"):
+            args.append("-m %d" % self.get("m"))
+        if self.get("o"):
+            args.append("-o %d" % self.get("o"))
+        if self.get("P"):
+            args.append("-P %d" % self.get("P"))
+        if self.get("q"):
+            args.append("-q %s" % self.get("q"))
+        if self.get("r"):
+            args.append("-r %d" % self.get("r"))
+        if self.get("t"):
+            args.append("-t %d" % self.get("t"))
+        if self.get("T"):
+            args.append("-T %d" % self.get("T"))
+
+        if self.get("continuous") == True:
+            args.append("; done ")
+
+        command = " ".join(args)
+
+        return command
+
+    @property
+    def _sources(self):
+        return "http://hpcbench.sourceforge.net/udp.tar.gz"
+
+    @property
+    def _depends(self):
+        return "gcc make"
+
+    @property
+    def _build(self):
+        sources = self.get("sources").split(" ")[0]
+        sources = os.path.basename(sources)
+
+        return (
+            # Evaluate if ccnx binaries are already installed
+            " ( "
+                " test -f ${BIN}/udptest && "
+                " echo 'binaries found, nothing to do' "
+            " ) || ( "
+            # If not, untar and build
+                " ( "
+                    " mkdir -p ${SRC}/udptest && "
+                    " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/udptest "
+                 " ) && "
+                    "cd ${SRC}/udptest && "
+                    # Just execute and silence warnings...
+                    " ( make ) "
+             " )") % ({ 'sources': sources,
+                 })
+
+    @property
+    def _install(self):
+        return (
+            # Evaluate if ccnx binaries are already installed
+            " ( "
+                " test -f ${BIN}/udptest && "
+                " echo 'binaries found, nothing to do' "
+            " ) || ( "
+            # If not, install
+                "  mv ${SRC}/udptest ${BIN} "
+            " )")
+
+    @property
+    def _environment(self):
+        return "PATH=$PATH:${BIN}/udptest"
+
+    def valid_connection(self, guid):
+        # TODO: Validate!
+        return True
+
index e6f0d2e..d314f6b 100644 (file)
@@ -56,9 +56,9 @@ def skipIfAnyNotAlive(func):
     def wrapped(*args, **kwargs):
         argss = list(args)
         argss.pop(0)
-        username = argss.pop(0)
-
-        for hostname in argss:
+        for i in xrange(len(argss)/2):
+            username = argss[i*2]
+            hostname = argss[i*2+1]
             node, ec = create_node(hostname, username)
 
             if not node.is_alive():
diff --git a/test/resources/linux/udptest.py b/test/resources/linux/udptest.py
new file mode 100755 (executable)
index 0000000..c4f697a
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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 test_utils import skipIfAnyNotAlive
+
+import os
+import time
+import tempfile
+import unittest
+
+class LinuxUdpTestTestCase(unittest.TestCase):
+    def setUp(self):
+        self.fedora_host = "nepi2.pl.sophia.inria.fr"
+        self.fedora_user = "inria_nepi"
+
+        self.ubuntu_host = "roseval.pl.sophia.inria.fr"
+        self.ubuntu_user = "alina"
+        
+        self.target = "nepi5.pl.sophia.inria.fr"
+
+    @skipIfAnyNotAlive
+    def t_rtt(self, user1, host1, user2, host2):
+
+        ec = ExperimentController(exp_id = "test-usptest-rtt")
+        
+        node1 = ec.register_resource("LinuxNode")
+        ec.set(node1, "hostname", host1)
+        ec.set(node1, "username", user1)
+        ec.set(node1, "cleanHome", True)
+        ec.set(node1, "cleanProcesses", True)
+
+        server = ec.register_resource("LinuxUdpTest")
+        ec.set(server, "s", True)
+        ec.register_connection(server, node1)
+        node2 = ec.register_resource("LinuxNode")
+        ec.set(node2, "hostname", host2)
+        ec.set(node2, "username", user2)
+        ec.set(node2, "cleanHome", True)
+        ec.set(node2, "cleanProcesses", True)
+
+        client = ec.register_resource("LinuxUdpTest")
+        ec.set(client, "a", True)
+        ec.set(client, "target", host1)
+        ec.register_connection(client, node2)
+
+        ec.deploy()
+
+        ec.wait_finished(client)
+
+        stdout = ec.trace(client, "stderr")
+        self.assertTrue(stdout.find("10 trials with message size 64 Bytes.") > -1)
+
+        ec.shutdown()
+
+    def test_rtt_fedora(self):
+        self.t_rtt(self.fedora_user, self.fedora_host, self.fedora_user, 
+                self.target)
+
+    def ztest_rtt_ubuntu(self):
+        self.t_rtt(self.ubuntu_user, self.ubuntu_host, self.fedora_user,
+                self.target)
+
+if __name__ == '__main__':
+    unittest.main()
+
index 6f45ae8..3a73cab 100755 (executable)
@@ -33,13 +33,13 @@ class UdpTunnelTestCase(unittest.TestCase):
         self.user = "inria_nepi"
 
     @skipIfAnyNotAlive
-    def t_tap_udp_tunnel(self, user, host1, host2):
+    def t_tap_udp_tunnel(self, user1, host1, user2, host2):
 
         ec = ExperimentController(exp_id = "test-tap-udp-tunnel")
         
         node1 = ec.register_resource("PlanetlabNode")
         ec.set(node1, "hostname", host1)
-        ec.set(node1, "username", user)
+        ec.set(node1, "username", user1)
         ec.set(node1, "cleanHome", True)
         ec.set(node1, "cleanProcesses", True)
 
@@ -51,7 +51,7 @@ class UdpTunnelTestCase(unittest.TestCase):
 
         node2 = ec.register_resource("PlanetlabNode")
         ec.set(node2, "hostname", host2)
-        ec.set(node2, "username", user)
+        ec.set(node2, "username", user2)
         ec.set(node2, "cleanHome", True)
         ec.set(node2, "cleanProcesses", True)
 
@@ -87,13 +87,13 @@ class UdpTunnelTestCase(unittest.TestCase):
         ec.shutdown()
 
     @skipIfAnyNotAlive
-    def t_tun_udp_tunnel(self, user, host1, host2):
+    def t_tun_udp_tunnel(self, user1, host1, user2, host2):
 
         ec = ExperimentController(exp_id = "test-tap-udp-tunnel")
         
         node1 = ec.register_resource("PlanetlabNode")
         ec.set(node1, "hostname", host1)
-        ec.set(node1, "username", user)
+        ec.set(node1, "username", user1)
         ec.set(node1, "cleanHome", True)
         ec.set(node1, "cleanProcesses", True)
 
@@ -105,7 +105,7 @@ class UdpTunnelTestCase(unittest.TestCase):
 
         node2 = ec.register_resource("PlanetlabNode")
         ec.set(node2, "hostname", host2)
-        ec.set(node2, "username", user)
+        ec.set(node2, "username", user2)
         ec.set(node2, "cleanHome", True)
         ec.set(node2, "cleanProcesses", True)
 
@@ -141,10 +141,10 @@ class UdpTunnelTestCase(unittest.TestCase):
         ec.shutdown()
 
     def test_tap_udp_tunnel(self):
-        self.t_tap_udp_tunnel(self.user, self.host1, self.host2)
+        self.t_tap_udp_tunnel(self.user, self.host1, self.user, self.host2)
 
     def test_tun_udp_tunnel(self):
-        self.t_tun_udp_tunnel(self.user, self.host1, self.host2)
+        self.t_tun_udp_tunnel(self.user, self.host1, self.user, self.host2)
 
 if __name__ == '__main__':
     unittest.main()