def do_provision(self):
# take a snapshot of the system if user is root
- # to assure cleanProcess kill every nepi process
+ # to ensure that cleanProcess will not kill
+ # pre-existent processes
if self.node.get("username") == 'root':
import pickle
procs = dict()
env = env,
overwrite = overwrite)
- def execute_deploy_command(self, command):
+ def execute_deploy_command(self, command, prefix="deploy"):
if command:
# Upload the command to a bash script and run it
# in background ( but wait until the command has
# finished to continue )
- shfile = os.path.join(self.app_home, "deploy.sh")
+ shfile = os.path.join(self.app_home, "%s.sh" % prefix)
self.node.run_and_wait(command, self.run_home,
shfile = shfile,
overwrite = False,
- pidfile = "deploy_pidfile",
- ecodefile = "deploy_exitcode",
- stdout = "deploy_stdout",
- stderr = "deploy_stderr")
-
- def upload_sources(self, src_dir = None):
- sources = self.get("sources")
+ pidfile = "%s_pidfile" % prefix,
+ ecodefile = "%s_exitcode" % prefix,
+ stdout = "%s_stdout" % prefix,
+ stderr = "%s_stderr" % prefix)
+
+ def upload_sources(self, sources = None, src_dir = None):
+ if not sources:
+ sources = self.get("sources")
command = ""
return command
- def upload_files(self):
- files = self.get("files")
+ def upload_files(self, files = None):
+ if not files:
+ files = self.get("files")
if files:
self.info("Uploading files %s " % files)
self.node.upload(files, self.node.share_dir, overwrite = False)
- def upload_libraries(self):
- libs = self.get("libs")
+ def upload_libraries(self, libs = None):
+ if not libs:
+ libs = self.get("libs")
if libs:
self.info("Uploading libraries %s " % libaries)
self.node.upload(libs, self.node.lib_dir, overwrite = False)
- def upload_binaries(self):
- bins = self.get("bins")
+ def upload_binaries(self, bins = None):
+ if not bins:
+ bins = self.get("bins")
if bins:
self.info("Uploading binaries %s " % binaries)
self.node.upload(bins, self.node.bin_dir, overwrite = False)
- def upload_code(self):
- code = self.get("code")
+ def upload_code(self, code = None):
+ if not code:
+ code = self.get("code")
if code:
self.info("Uploading code")
dst = os.path.join(self.app_home, "code")
self.node.upload(code, dst, overwrite = False, text = True)
- def upload_stdin(self):
- stdin = self.get("stdin")
+ def upload_stdin(self, stdin = None):
+ if not stdin:
+ stdin = self.get("stdin")
+
if stdin:
# create dir for sources
self.info("Uploading stdin")
return command
- def install_dependencies(self):
- depends = self.get("depends")
+ def install_dependencies(self, depends = None):
+ if not depends:
+ depends = self.get("depends")
+
if depends:
self.info("Installing dependencies %s" % depends)
return self.node.install_packages_command(depends)
- def build(self):
- build = self.get("build")
+ def build(self, build = None):
+ if not build:
+ build = self.get("build")
if build:
self.info("Building sources ")
# replace application specific paths in the command
return self.replace_paths(build)
- def install(self):
- install = self.get("install")
+ def install(self, install = None):
+ if not install:
+ install = self.get("install")
if install:
self.info("Installing sources ")
--- /dev/null
+#
+# NEPI, a framework to manage network experiments
+# Copyright (C) 2014 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 clsinit_copy, ResourceState, reschedule_delay
+from nepi.resources.ns3.ns3dceapplication import NS3BaseDceApplication
+
+@clsinit_copy
+class NS3LinuxDceApplication(NS3BaseDceApplication):
+ _rtype = "ns3::LinuxDceApplication"
+
+ @classmethod
+ def _register_attributes(cls):
+ sources = Attribute("sources",
+ "Path to tar.gz file with sources for the application execute in DCE. "
+ "Sources will be uploaded to ${SRC} and it is the responsibility of "
+ "the build instructions (in the build attribute) to copy the compiled "
+ "binaries to the ${BIN_DCE} directory",
+ flags = Flags.Design)
+
+ build = Attribute("build",
+ "Instructions to compile sources DCE-compatible way. "
+ "Note that sources will be uploaded to ${SRC} and the "
+ "build instructions are responsible for copying the "
+ "binaries to the ${BIN_DCE} directory. ",
+ flags = Flags.Design)
+
+ starttime = Attribute("StartTime",
+ "Time at which the application will start",
+ default = "+0.0ns",
+ flags = Flags.Reserved | Flags.Construct)
+
+
+ stoptime = Attribute("StopTime",
+ "Time at which the application will stop",
+ default = "+0.0ns",
+ flags = Flags.Reserved | Flags.Construct)
+
+ cls._register_attribute(sources)
+ cls._register_attribute(build)
+ cls._register_attribute(stoptime)
+ cls._register_attribute(starttime)
+
+ def _instantiate_object(self):
+ command = []
+
+ sources = self.get("sources")
+ if sources:
+ self.info("Uploading sources %s " % sources)
+ scmd = self.simulation.upload_extra_sources(sources = sources)
+ if scmd:
+ command.append(scmd)
+
+ build = self.get("build")
+ if build:
+ bcmd = self.simulation.build(build = build)
+ if bcmd:
+ command.append(bcmd)
+
+ if command:
+ deploy_command = ";".join(command)
+ prefix = "%d_deploy" % self.guid
+ self.simulation.execute_deploy_command(deploy_command, prefix=prefix)
+
src_dir = os.path.join(self.node.src_dir, "ns-3")
super(LinuxNS3Simulation, self).upload_sources(src_dir = src_dir)
+
+ def upload_extra_sources(self, sources = None, src_dir = None):
+ return super(LinuxNS3Simulation, self).upload_sources(
+ sources = sources,
+ src_dir = src_dir)
def upload_start_command(self):
command = self.get("command")
env.append("PYTHONPATH=$PYTHONPATH:${NS3BINDINGS:=%(ns3_build_home)s/lib/python/site-packages}" % {
'ns3_build_home': self.ns3_build_home
})
- env.append("LD_LIBRARY_PATH=${NS3LIBRARIES:=%(ns3_build_home)s/lib/}" % {
+ # If NS3LIBRARIES is defined and not empty, assign its value,
+ # if not assign ns3_build_home/lib/ to NS3LIBRARIES and LD_LIBARY_PATH
+ env.append("LD_LIBRARY_PATH=${NS3LIBRARIES:=%(ns3_build_home)s/lib}" % {
'ns3_build_home': self.ns3_build_home
})
- env.append("DCE_PATH=$PATH:$NS3LIBRARIES/../bin_dce")
- env.append("DCE_ROOT=$PATH:$NS3LIBRARIES/..")
+ env.append("DCE_PATH=$NS3LIBRARIES/../bin_dce")
+ env.append("DCE_ROOT=$NS3LIBRARIES/..")
return " ".join(env)
+ def replace_paths(self, command):
+ """
+ Replace all special path tags with shell-escaped actual paths.
+ """
+ return ( command
+ .replace("${USR}", self.node.usr_dir)
+ .replace("${LIB}", self.node.lib_dir)
+ .replace("${BIN}", self.node.bin_dir)
+ .replace("${SRC}", self.node.src_dir)
+ .replace("${SHARE}", self.node.share_dir)
+ .replace("${EXP}", self.node.exp_dir)
+ .replace("${EXP_HOME}", self.node.exp_home)
+ .replace("${APP_HOME}", self.app_home)
+ .replace("${RUN_HOME}", self.run_home)
+ .replace("${NODE_HOME}", self.node.node_home)
+ .replace("${HOME}", self.node.home_dir)
+ # If NS3LIBRARIES is defined and not empty, use that value,
+ # if not use ns3_build_home/lib/
+ .replace("${BIN_DCE}", "${NS3LIBRARIES-%s/lib/}../bin_dce" % \
+ self.ns3_build_home)
+ )
+
def valid_connection(self, guid):
# TODO: Validate!
return True
--- /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.trace import TraceAttr
+
+import os
+import time
+import unittest
+
+def add_ns3_node(ec, simu):
+ node = ec.register_resource("ns3::Node")
+ ec.register_connection(node, simu)
+
+ ipv4 = ec.register_resource("ns3::Ipv4L3Protocol")
+ ec.register_connection(node, ipv4)
+
+ arp = ec.register_resource("ns3::ArpL3Protocol")
+ ec.register_connection(node, arp)
+
+ icmp = ec.register_resource("ns3::Icmpv4L4Protocol")
+ ec.register_connection(node, icmp)
+
+ udp = ec.register_resource("ns3::UdpL4Protocol")
+ ec.register_connection(node, udp)
+
+ return node
+
+def add_point2point_device(ec, node, address = None, prefix = None):
+ dev = ec.register_resource("ns3::PointToPointNetDevice")
+ if address:
+ ec.set(dev, "ip", address)
+ if prefix:
+ ec.set(dev, "prefix", prefix)
+ ec.register_connection(node, dev)
+
+ queue = ec.register_resource("ns3::DropTailQueue")
+ ec.register_connection(dev, queue)
+
+ return dev
+
+def add_csma_device(ec, node, address = None, prefix = None):
+ dev = ec.register_resource("ns3::CsmaNetDevice")
+ if address:
+ ec.set(dev, "ip", address)
+ if prefix:
+ ec.set(dev, "prefix", prefix)
+ ec.register_connection(node, dev)
+
+ queue = ec.register_resource("ns3::DropTailQueue")
+ ec.register_connection(dev, queue)
+
+ return dev
+
+def add_wifi_device(ec, node, address = None, prefix = None,
+ access_point = False):
+ dev = ec.register_resource("ns3::WifiNetDevice")
+ if address:
+ ec.set(dev, "ip", address)
+ if prefix:
+ ec.set(dev, "prefix", prefix)
+ ec.register_connection(node, dev)
+
+ phy = ec.register_resource("ns3::YansWifiPhy")
+ ec.set(phy, "Standard", "WIFI_PHY_STANDARD_80211a")
+ ec.register_connection(dev, phy)
+
+ error = ec.register_resource("ns3::NistErrorRateModel")
+ ec.register_connection(phy, error)
+
+ manager = ec.register_resource("ns3::ArfWifiManager")
+ ec.register_connection(dev, manager)
+
+ if access_point:
+ mac = ec.register_resource("ns3::ApWifiMac")
+ else:
+ mac = ec.register_resource("ns3::StaWifiMac")
+
+ ec.set(mac, "Standard", "WIFI_PHY_STANDARD_80211a")
+ ec.register_connection(dev, mac)
+
+ return dev, phy
+
+def add_random_mobility(ec, node, x, y, z, speed, bounds_width,
+ bounds_height):
+ position = "%d:%d:%d" % (x, y, z)
+ bounds = "0|%d|0|%d" % (bounds_width, bounds_height)
+ speed = "ns3::UniformRandomVariable[Min=%d|Max=%s]" % (speed, speed)
+ pause = "ns3::ConstantRandomVariable[Constant=1.0]"
+
+ mobility = ec.register_resource("ns3::RandomDirection2dMobilityModel")
+ ec.set(mobility, "Position", position)
+ ec.set(mobility, "Bounds", bounds)
+ ec.set(mobility, "Speed", speed)
+ ec.set(mobility, "Pause", pause)
+ ec.register_connection(node, mobility)
+ return mobility
+
+def add_constant_mobility(ec, node, x, y, z):
+ mobility = ec.register_resource("ns3::ConstantPositionMobilityModel")
+ position = "%d:%d:%d" % (x, y, z)
+ ec.set(mobility, "Position", position)
+ ec.register_connection(node, mobility)
+ return mobility
+
+def add_wifi_channel(ec):
+ channel = ec.register_resource("ns3::YansWifiChannel")
+ delay = ec.register_resource("ns3::ConstantSpeedPropagationDelayModel")
+ ec.register_connection(channel, delay)
+
+ loss = ec.register_resource("ns3::LogDistancePropagationLossModel")
+ ec.register_connection(channel, loss)
+
+ return channel
+
+class LinuxNS3DceApplicationTest(unittest.TestCase):
+ def setUp(self):
+ #elf.fedora_host = "nepi2.pl.sophia.inria.fr"
+ #self.fedora_host = "planetlabpc1.upf.edu"
+ self.fedora_host = "peeramide.irisa.fr"
+ self.fedora_user = "inria_nepi"
+ #self.fedora_user = "inria_alina"
+ self.fedora_identity = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
+
+ def test_dce_application(self):
+ ec = ExperimentController(exp_id = "test-linux-ns3-dce")
+
+ node = ec.register_resource("LinuxNode")
+ ec.set(node, "hostname", self.fedora_host)
+ ec.set(node, "username", self.fedora_user)
+ ec.set(node, "identity", self.fedora_identity)
+ ec.set(node, "cleanProcesses", True)
+ #ec.set(node, "cleanHome", True)
+
+ simu = ec.register_resource("LinuxNS3Simulation")
+ ec.set(simu, "verbose", True)
+ ec.set(simu, "enableDCE", True)
+ ec.set(simu, "buildMode", "debug")
+ ec.set(simu, "nsLog", "DceApplication")
+ ec.register_connection(simu, node)
+
+ nsnode1 = add_ns3_node(ec, simu)
+ ec.set(nsnode1, "enableDCE", True)
+ p2p1 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30")
+ ec.set(p2p1, "DataRate", "5Mbps")
+
+ nsnode2 = add_ns3_node(ec, simu)
+ ec.set(nsnode2, "enableDCE", True)
+ p2p2 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30")
+ ec.set(p2p2, "DataRate", "5Mbps")
+
+ # Create channel
+ chan = ec.register_resource("ns3::PointToPointChannel")
+ ec.set(chan, "Delay", "2ms")
+
+ ec.register_connection(chan, p2p1)
+ ec.register_connection(chan, p2p2)
+
+ ### create applications
+ ping = ec.register_resource("ns3::LinuxDceApplication")
+ """
+ ec.set (ping, "sources", "http://www.skbuff.net/iputils/iputils-s20101006.tar.bz2")
+ ec.set (ping, "build", "tar xvjf ${SRC}/iputils-s20101006.tar.bz2 && "
+ "cd iputils-s20101006/ && "
+ "sed -i 's/CFLAGS=/CFLAGS+=/g' Makefile && "
+ "make CFLAGS=-fPIC LDFLAGS=-pie ping && "
+ "cp ping ${BIN_DCE} ")
+ """
+ ec.set (ping, "binary", "ping")
+ ec.set (ping, "stackSize", 1<<20)
+ ec.set (ping, "arguments", "-c 10;-s 1000;10.0.0.2")
+ ec.set (ping, "StartTime", "1s")
+ ec.set (ping, "StopTime", "20s")
+ ec.register_connection(ping, nsnode1)
+
+ ec.deploy()
+
+ ec.wait_finished([ping])
+
+ expected = "ping -c 10 -s 1000 10.0.0.2"
+ cmdline = ec.trace(ping, "cmdline")
+ self.assertTrue(cmdline.find(expected) > -1, cmdline)
+
+ expected = "Start Time: NS3 Time: 1s ("
+ status = ec.trace(ping, "status")
+ self.assertTrue(status.find(expected) > -1, status)
+
+ expected = "10 packets transmitted, 10 received, 0% packet loss, time 9002ms"
+ stdout = ec.trace(ping, "stdout")
+ self.assertTrue(stdout.find(expected) > -1, stdout)
+
+ stderr = ec.trace(simu, "stderr")
+ expected = "DceApplication:StartApplication"
+ self.assertTrue(stderr.find(expected) > -1, stderr)
+
+ ec.shutdown()
+
+
+if __name__ == '__main__':
+ unittest.main()