2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2014 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
20 from nepi.execution.attribute import Attribute, Flags, Types
21 from nepi.execution.trace import Trace, TraceAttr
22 from nepi.execution.resource import ResourceManager, clsinit_copy, \
23 ResourceState, reschedule_delay
24 from nepi.resources.linux.application import LinuxApplication
25 from nepi.resources.linux.node import OSType
26 from nepi.util.timefuncs import tnow, tdiffsec
27 from nepi.resources.ns3.ns3simulator import NS3Simulator
28 from nepi.resources.linux.ns3.ns3client import LinuxNS3Client
33 class LinuxNS3Simulator(LinuxApplication, NS3Simulator):
34 _rtype = "LinuxNS3Simulator"
37 def _register_attributes(cls):
38 max_rte = Attribute("maxRteMicrosec",
39 "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ",
40 flags = Flags.ExecReadOnly)
42 cls._register_attribute(debug)
44 def __init__(self, ec, guid):
45 super(LinuxApplication, self).__init__(ec, guid)
46 super(NS3Simulator, self).__init__()
48 self._home = "ns3-simu-%s" % self.guid
50 # TODO: Create socket!!
51 self._client = LinuxNS3Client(socket_name)
55 if not self.node or self.node.state < ResourceState.READY:
56 self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state )
58 # ccnd needs to wait until node is deployed and running
59 self.ec.schedule(reschedule_delay, self.deploy)
61 if not self.get("command"):
62 self.set("command", self._start_command)
64 if not self.get("depends"):
65 self.set("depends", self._dependencies)
67 if not self.get("sources"):
68 self.set("sources", self._sources)
70 sources = self.get("sources")
71 source = sources.split(" ")[0]
72 basename = os.path.basename(source)
73 self._version = ( basename.strip().replace(".tar.gz", "")
78 if not self.get("build"):
79 self.set("build", self._build)
81 if not self.get("install"):
82 self.set("install", self._install)
84 if not self.get("env"):
85 self.set("env", self._environment)
87 command = self.get("command")
89 self.info("Deploying command '%s' " % command)
94 self.debug("----- READY ---- ")
97 def upload_start_command(self):
98 command = self.get("command")
101 # We want to make sure the ccnd is running
102 # before the experiment starts.
103 # Run the command as a bash script in background,
104 # in the host ( but wait until the command has
105 # finished to continue )
106 env = self.replace_paths(env)
107 command = self.replace_paths(command)
109 shfile = os.path.join(self.app_home, "start.sh")
110 self.node.run_and_wait(command, self.run_home,
114 raise_on_error = True)
117 if self.state == ResourceState.READY:
118 command = self.get("command")
119 self.info("Starting command '%s'" % command)
123 msg = " Failed to execute command '%s'" % command
124 self.error(msg, out, err)
125 raise RuntimeError, msg
128 command = self.get('command') or ''
130 if self.state == ResourceState.STARTED:
131 self.info("Stopping command '%s'" % command)
134 env = self.get("env")
136 # replace application specific paths in the command
137 command = self.replace_paths(command)
138 env = env and self.replace_paths(env)
140 # Upload the command to a file, and execute asynchronously
141 shfile = os.path.join(self.app_home, "stop.sh")
142 self.node.run_and_wait(command, self.run_home,
146 pidfile = "ccndstop_pidfile",
147 ecodefile = "ccndstop_exitcode",
148 stdout = "ccndstop_stdout",
149 stderr = "ccndstop_stderr")
155 # First check if the ccnd has failed
156 state_check_delay = 0.5
157 if self._state == ResourceState.STARTED and \
158 tdiffsec(tnow(), self._last_state_check) > state_check_delay:
159 (out, err), proc = self._ccndstatus()
161 retcode = proc.poll()
163 if retcode == 1 and err.find("No such file or directory") > -1:
164 # ccnd is not running (socket not found)
168 msg = " Failed to execute command '%s'" % self.get("command")
169 self.error(msg, out, err)
172 self._last_state_check = tnow()
176 def _ccndstatus(self):
177 env = self.get('env') or ""
178 environ = self.node.format_environment(env, inline = True)
179 command = environ + " ccndstatus"
180 command = self.replace_paths(command)
182 return self.node.execute(command)
185 def _start_command(self):
189 def _dependencies(self):
190 if self.node.use_rpm:
191 return ( " autoconf openssl-devel expat-devel libpcap-devel "
192 " ecryptfs-utils-devel libxml2-devel automake gawk "
193 " gcc gcc-c++ git pcre-devel make ")
194 elif self.node.use_deb:
195 return ( " autoconf libssl-dev libexpat-dev libpcap-dev "
196 " libecryptfs0 libxml2-utils automake gawk gcc g++ "
197 " git-core pkg-config libpcre3-dev make ")
202 return "http://www.ccnx.org/releases/ccnx-0.7.2.tar.gz"
206 sources = self.get("sources").split(" ")[0]
207 sources = os.path.basename(sources)
210 # Evaluate if ccnx binaries are already installed
212 " test -f ${BIN}/%(version)s/ccnd && "
213 " echo 'binaries found, nothing to do' "
215 # If not, untar and build
217 " mkdir -p ${SRC}/%(version)s && "
218 " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/%(version)s "
220 "cd ${SRC}/%(version)s && "
221 # Just execute and silence warnings...
222 " ( ./configure && make ) "
223 " )") % ({ 'sources': sources,
224 'version': self.version
230 # Evaluate if ccnx binaries are already installed
232 " test -f ${BIN}/%(version)s/ccnd && "
233 " echo 'binaries found, nothing to do' "
236 " mkdir -p ${BIN}/%(version)s && "
237 " mv ${SRC}/%(version)s/bin/* ${BIN}/%(version)s/ "
239 ) % ({ 'version': self.version
243 def _environment(self):
245 "debug": "CCND_DEBUG",
246 "port": "CCN_LOCAL_PORT",
247 "sockname" : "CCN_LOCAL_SOCKNAME",
248 "capacity" : "CCND_CAP",
250 "dataPauseMicrosec" : "CCND_DATA_PAUSE_MICROSEC",
251 "defaultTimeToStale" : "CCND_DEFAULT_TIME_TO_STALE",
252 "maxTimeToStale" : "CCND_MAX_TIME_TO_STALE",
253 "maxRteMicrosec" : "CCND_MAX_RTE_MICROSEC",
254 "keyStoreDirectory" : "CCND_KEYSTORE_DIRECTORY",
255 "listenOn" : "CCND_LISTEN_ON",
256 "autoreg" : "CCND_AUTOREG",
257 "prefix" : "CCND_PREFIX",
261 env += " ".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))) \
262 if self.get(k) else "", envs.keys()))
266 def valid_connection(self, guid):