From: Alina Quereilhac Date: Thu, 11 Jul 2013 19:46:17 +0000 (-0700) Subject: Added LinuxPing and LinuxMtr RMs X-Git-Tag: nepi-3.0.0~79 X-Git-Url: http://git.onelab.eu/?p=nepi.git;a=commitdiff_plain;h=a0eefc4e266c584dfa3363e30154b3fdaa5b4f60 Added LinuxPing and LinuxMtr RMs --- diff --git a/setup.py b/setup.py index 1ee32fad..69fc5b27 100755 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ setup( "nepi.resources.ns3", "nepi.resources.omf", "nepi.resources.planetlab", + "nepi.resources.planetlab", "nepi.util"], package_dir = {"": "src"}, ) diff --git a/src/nepi/resources/all/collector.py b/src/nepi/resources/all/collector.py index 2dfd2007..61efa22b 100644 --- a/src/nepi/resources/all/collector.py +++ b/src/nepi/resources/all/collector.py @@ -52,10 +52,13 @@ class Collector(ResourceManager): flags = Flags.ExecReadOnly) sub_dir = Attribute("subDir", "Sub directory to collect traces into", flags = Flags.ExecReadOnly) + rename = Attribute("rename", "Name to give to the collected trace file", + flags = Flags.ExecReadOnly) cls._register_attribute(trace_name) cls._register_attribute(store_dir) cls._register_attribute(sub_dir) + cls._register_attribute(rename) def __init__(self, ec, guid): super(Collector, self).__init__(ec, guid) @@ -104,6 +107,7 @@ class Collector(ResourceManager): def release(self): trace_name = self.get("traceName") + rename = self.get("rename") or trace_name msg = "Collecting '%s' traces to local directory %s" % ( trace_name, self.store_path) @@ -113,7 +117,7 @@ class Collector(ResourceManager): for rm in rms: result = self.ec.trace(rm.guid, trace_name) fpath = os.path.join(self.store_path, "%d.%s" % (rm.guid, - trace_name)) + rename)) f = open(fpath, "w") f.write(result) f.close() diff --git a/src/nepi/resources/linux/ccn/fibentry.py b/src/nepi/resources/linux/ccn/fibentry.py index 3c82a038..83fbe9c7 100644 --- a/src/nepi/resources/linux/ccn/fibentry.py +++ b/src/nepi/resources/linux/ccn/fibentry.py @@ -138,7 +138,15 @@ class LinuxFIBEntry(LinuxApplication): if not self.trace_enabled("ping"): return - command = """ping %s""" % self.get("host") + ping_script = """echo "Staring PING %(host)s at date `date +'%Y%m%d%H%M%S'`"; ping %(host)s""" % ({ + "host": self.get("host")}) + ping_file = os.path.join(self.run_home, "ping.sh") + self.node.upload(ping_script, + ping_file, + text = True, + overwrite = False) + + command = """bash %s""" % ping_file (out, err), proc = self.node.run(command, self.run_home, stdout = "ping", stderr = "ping_stderr", @@ -159,6 +167,8 @@ class LinuxFIBEntry(LinuxApplication): msg = " Failed to deploy ping trace command '%s' " % command self.error(msg, out, err) raise RuntimeError, msg + + #while true; do echo `date +'%Y%m%d%H%M%S'`; mtr --no-dns --report -c 1 roseval.pl.sophia.inria.fr;sleep 2;done def start(self): if self._state in [ResourceState.READY, ResourceState.STARTED]: diff --git a/src/nepi/resources/linux/mtr.py b/src/nepi/resources/linux/mtr.py new file mode 100644 index 00000000..0bf5fae2 --- /dev/null +++ b/src/nepi/resources/linux/mtr.py @@ -0,0 +1,100 @@ +# +# 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 . +# +# Author: Alina Quereilhac + +from nepi.execution.attribute import Attribute, Flags, Types +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 LinuxMtr(LinuxApplication): + _rtype = "LinuxMtr" + + @classmethod + def _register_attributes(cls): + report_cycles = Attribute("reportCycles", + "sets mtr --report-cycles (-c) option. Determines the number of " + "pings sent to determine both machines in the networks. Each " + "cycle lasts one sencond.", + flags = Flags.ExecReadOnly) + + no_dns = Attribute("noDns", + "sets mtr --no-dns (-n) option. Forces mtr to display IPs intead of " + "trying to resolve to host names ", + type = Types.Bool, + default = True, + flags = Flags.ExecReadOnly) + + address = Attribute("address", + "sets mtr --address (-a) option. Binds the socket to send outgoing " + "packets to the interface of the specified address, so that any " + "any packets are sent through this interface. ", + flags = Flags.ExecReadOnly) + + interval = Attribute("interval", + "sets mtr --interval (-i) option. Specifies the number of seconds " + "between ICMP ECHO requests. Default value is one second ", + flags = Flags.ExecReadOnly) + + target = Attribute("target", + "mtr target host (host that will be pinged)", + flags = Flags.ExecReadOnly) + + cls._register_attribute(report_cycles) + cls._register_attribute(no_dns) + cls._register_attribute(address) + cls._register_attribute(interval) + cls._register_attribute(target) + + def __init__(self, ec, guid): + super(LinuxMtr, self).__init__(ec, guid) + self._home = "mtr-%s" % self.guid + + def deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + if not self.get("depends"): + self.set("depends", "mtr") + + super(LinuxMtr, self).deploy() + + @property + def _start_command(self): + args = [] + if self.get("reportCycles"): + args.append("-c %s" % self.get("reportCycles")) + if self.get("noDns") == True: + args.append("-n") + if self.get("address"): + args.append("-a %s" % self.get("address")) + args.append(self.get("target")) + + command = """echo "Starting mtr `date +'%Y%m%d%H%M%S'`"; """ + command += " sudo -S mtr --report " + command += " ".join(args) + + return command + + def valid_connection(self, guid): + # TODO: Validate! + return True + diff --git a/src/nepi/resources/linux/ping.py b/src/nepi/resources/linux/ping.py new file mode 100644 index 00000000..0a5796a0 --- /dev/null +++ b/src/nepi/resources/linux/ping.py @@ -0,0 +1,250 @@ +# +# 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 . +# +# Author: Alina Quereilhac + +from nepi.execution.attribute import Attribute, Flags, Types +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 LinuxPing(LinuxApplication): + _rtype = "LinuxPing" + + @classmethod + def _register_attributes(cls): + count = Attribute("count", + "Sets ping -c option. Determines the number of ECHO_REQUEST " + "packates to send before stopping.", + flags = Flags.ExecReadOnly) + + mark = Attribute("mark", + "Sets ping -m option. Uses 'mark' to tag outgoing packets. ", + flags = Flags.ExecReadOnly) + + interval = Attribute("interval", + "Sets ping -i option. Leaves interval seconds between " + "successive ECHO_REUQEST packets. ", + flags = Flags.ExecReadOnly) + + address = Attribute("address", + "Sets ping -I option. Sets ECHO_REQUEST packets souce address " + "to the specified interface address ", + flags = Flags.ExecReadOnly) + + preload = Attribute("preload", + "Sets ping -l option. Sends preload amount of packets " + "without waiting for a reply ", + flags = Flags.ExecReadOnly) + + numeric = Attribute("numeric", + "Sets ping -n option. Disables resolution of host addresses into " + "symbolic names ", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + pattern = Attribute("pattern", + "Sets ping -p option. Species a up to 16 ''pad'' bytes to fill " + "out sent packets. ", + flags = Flags.ExecReadOnly) + + printtmp = Attribute("printTimestamp", + "Sets ping -D option. Prints timestamp befor each line as: " + "unix time + microseconds as in gettimeofday ", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + tos = Attribute("tos", + "Sets ping -Q option. Sets Quality of Service related bits in ICMP " + "datagrams. tos can be either a decimal or hexadecime number ", + flags = Flags.ExecReadOnly) + + quiet = Attribute("quiet", + "Sets ping -q option. Disables ping standard output ", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + rec_route = Attribute("recordRoute", + "Sets ping -R option. Includes the RECORD_ROUTE option in the " + "ECHO REQUEST packet and displays route buffer on the Disables " + "ping standard output.", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + route_bypass = Attribute("routeBypass", + "Sets ping -r option. Bypasses normal routing tables and sends " + "ECHO REQUEST packets directly yo a host on an attached interface. ", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + packetsize = Attribute("packetSize", + "Sets ping -s option. Specifies the number of data bytes to be " + "sent. Defaults to 56. ", + flags = Flags.ExecReadOnly) + + sendbuff = Attribute("sendBuff", + "Sets ping -S option. Specifies the number of packets to buffer. " + "Defaults to one. ", + flags = Flags.ExecReadOnly) + + ttl = Attribute("ttl", + "Sets ping -t option. Specifies the IP Time to Live for the " + "packets. ", + flags = Flags.ExecReadOnly) + + timestamp = Attribute("timestamp", + "Sets ping -T option. Sets special IP timestamp options. ", + flags = Flags.ExecReadOnly) + + hint = Attribute("hint", + "Sets ping -M option. Selects Path MTU Discovery strategy. ", + flags = Flags.ExecReadOnly) + + full_latency = Attribute("fullLatency", + "Sets ping -U option. Calculates round trip time taking into " + "account the full user-to-user latency instead of only the " + "network round trip time. ", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + verbose = Attribute("verbose", + "Sets ping -v option. Verbose output. ", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + flood = Attribute("flood", + "Sets ping -f option. Flood ping. ", + type = Types.Bool, + default = False, + flags = Flags.ExecReadOnly) + + deadline = Attribute("deadline", + "Sets ping -w option. Specify a timeout, in seconds, before ping " + "exits regardless of how many packets have been sent or received.", + flags = Flags.ExecReadOnly) + + timeout = Attribute("timeout", + "Sets ping -W option. Time to wait for a respone in seconds .", + flags = Flags.ExecReadOnly) + + target = Attribute("target", + "The host to ping .", + flags = Flags.ExecReadOnly) + + cls._register_attribute(count) + cls._register_attribute(mark) + cls._register_attribute(interval) + cls._register_attribute(address) + cls._register_attribute(preload) + cls._register_attribute(numeric) + cls._register_attribute(pattern) + cls._register_attribute(printtmp) + cls._register_attribute(tos) + cls._register_attribute(quiet) + cls._register_attribute(rec_route) + cls._register_attribute(route_bypass) + cls._register_attribute(packetsize) + cls._register_attribute(sendbuff) + cls._register_attribute(ttl) + cls._register_attribute(timestamp) + cls._register_attribute(hint) + cls._register_attribute(full_latency) + cls._register_attribute(verbose) + cls._register_attribute(flood) + cls._register_attribute(deadline) + cls._register_attribute(timeout) + cls._register_attribute(target) + + def __init__(self, ec, guid): + super(LinuxPing, self).__init__(ec, guid) + self._home = "ping-%s" % self.guid + + def deploy(self): + if not self.get("command"): + self.set("command", self._start_command) + + super(LinuxPing, self).deploy() + + @property + def _start_command(self): + args = [] + + if self.get("count"): + args.append("-c %s" % self.get("count")) + if self.get("mark"): + args.append("-m %s" % self.get("mark")) + if self.get("interval"): + args.append("-i %s" % self.get("interval")) + if self.get("address"): + args.append("-I %s" % self.get("address")) + if self.get("preload"): + args.append("-l %s" % self.get("preload")) + if self.get("numeric") == True: + args.append("-n") + if self.get("pattern"): + args.append("-p %s" % self.get("pattern")) + if self.get("printTimestamp") == True: + args.append("-D") + if self.get("tos"): + args.append("-Q %s" % self.get("tos")) + if self.get("quiet"): + args.append("-q %s" % self.get("quiet")) + if self.get("recordRoute") == True: + args.append("-R") + if self.get("routeBypass") == True: + args.append("-r") + if self.get("packetSize"): + args.append("-s %s" % self.get("packetSize")) + if self.get("sendBuff"): + args.append("-S %s" % self.get("sendBuff")) + if self.get("ttl"): + args.append("-t %s" % self.get("ttl")) + if self.get("timestamp"): + args.append("-T %s" % self.get("timestamp")) + if self.get("hint"): + args.append("-M %s" % self.get("hint")) + if self.get("fullLatency") == True: + args.append("-U") + if self.get("verbose") == True: + args.append("-v") + if self.get("flood") == True: + args.append("-f") + if self.get("deadline"): + args.append("-w %s" % self.get("deadline")) + if self.get("timeout"): + args.append("-W %s" % self.get("timeout")) + args.append(self.get("target")) + + command = " sudo -S ping " + command += " ".join(args) + + return command + + def valid_connection(self, guid): + # TODO: Validate! + return True + diff --git a/src/nepi/resources/planetlab/tap.py b/src/nepi/resources/planetlab/tap.py index 7d8cd3e2..ed6c2aae 100644 --- a/src/nepi/resources/planetlab/tap.py +++ b/src/nepi/resources/planetlab/tap.py @@ -29,8 +29,6 @@ import time # TODO: - routes!!! # - Make base clase 'virtual device' and redefine vif_type -# - write the name of the device (if_name) to a file and allow the -# RM to read it and set the 'deviceName' attribute # - Instead of doing an infinite loop, open a port for communication allowing # to pass the fd to another process diff --git a/test/resources/linux/mtr.py b/test/resources/linux/mtr.py new file mode 100755 index 00000000..a34068d8 --- /dev/null +++ b/test/resources/linux/mtr.py @@ -0,0 +1,72 @@ +#!/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 . +# +# Author: Alina Quereilhac + +from nepi.execution.ec import ExperimentController +from test_utils import skipIfNotAlive, skipInteractive + +import os +import time +import tempfile +import unittest + +class LinuxMtrTestCase(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" + + @skipIfNotAlive + def t_nodns(self, host, user): + + ec = ExperimentController(exp_id = "test-nodns") + + node = ec.register_resource("LinuxNode") + ec.set(node, "hostname", host) + ec.set(node, "username", user) + ec.set(node, "cleanHome", True) + ec.set(node, "cleanProcesses", True) + + app = ec.register_resource("LinuxMtr") + ec.set(app, "noDns", False) + ec.set(app, "target", self.target) + ec.register_connection(app, node) + + ec.deploy() + + ec.wait_finished(app) + + stdout = ec.trace(app, "stdout") + self.assertTrue(stdout.find("1.") > -1) + + ec.shutdown() + + def test_nodns_fedora(self): + self.t_nodns(self.fedora_host, self.fedora_user) + + def test_nodns_ubuntu(self): + self.t_nodns(self.ubuntu_host, self.ubuntu_user) + +if __name__ == '__main__': + unittest.main() + diff --git a/test/resources/linux/ping.py b/test/resources/linux/ping.py new file mode 100755 index 00000000..65302767 --- /dev/null +++ b/test/resources/linux/ping.py @@ -0,0 +1,73 @@ +#!/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 . +# +# Author: Alina Quereilhac + +from nepi.execution.ec import ExperimentController +from test_utils import skipIfNotAlive, skipInteractive + +import os +import time +import tempfile +import unittest + +class LinuxPingTestCase(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" + + @skipIfNotAlive + def t_count(self, host, user): + + ec = ExperimentController(exp_id = "test-ping-count") + + node = ec.register_resource("LinuxNode") + ec.set(node, "hostname", host) + ec.set(node, "username", user) + ec.set(node, "cleanHome", True) + ec.set(node, "cleanProcesses", True) + + app = ec.register_resource("LinuxPing") + ec.set(app, "count", "3") + ec.set(app, "target", self.target) + ec.register_connection(app, node) + + ec.deploy() + + ec.wait_finished(app) + + stdout = ec.trace(app, "stdout") + expected = "3 packets transmitted, 3 received, 0% packet loss" + self.assertTrue(stdout.find(expected) > -1) + + ec.shutdown() + + def test_count_fedora(self): + self.t_count(self.fedora_host, self.fedora_user) + + def test_count_ubuntu(self): + self.t_count(self.ubuntu_host, self.ubuntu_user) + +if __name__ == '__main__': + unittest.main() +