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.simulator import NS3Simulator
32 class LinuxNS3Simulator(LinuxApplication, NS3Simulator):
33 _rtype = "LinuxSimulator"
36 def _register_attributes(cls):
37 max_rte = Attribute("maxRteMicrosec",
38 "Sets the CCND_MAX_RTE_MICROSEC environmental variable. ",
39 flags = Flags.ExecReadOnly)
41 keystore = Attribute("keyStoreDirectory",
42 "Sets the CCND_KEYSTORE_DIRECTORY environmental variable. ",
43 flags = Flags.ExecReadOnly)
45 cls._register_attribute(debug)
46 cls._register_attribute(port)
49 def _register_traces(cls):
50 log = Trace("log", "CCND log output")
51 status = Trace("status", "ccndstatus output")
53 cls._register_trace(log)
54 cls._register_trace(status)
56 def __init__(self, ec, guid):
57 super(LinuxCCND, self).__init__(ec, guid)
58 self._home = "ccnd-%s" % self.guid
59 self._version = "ccnx"
67 return "PATH=$PATH:${BIN}/%s/" % self.version
70 if not self.node or self.node.state < ResourceState.READY:
71 self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state )
73 # ccnd needs to wait until node is deployed and running
74 self.ec.schedule(reschedule_delay, self.deploy)
76 if not self.get("command"):
77 self.set("command", self._start_command)
79 if not self.get("depends"):
80 self.set("depends", self._dependencies)
82 if not self.get("sources"):
83 self.set("sources", self._sources)
85 sources = self.get("sources")
86 source = sources.split(" ")[0]
87 basename = os.path.basename(source)
88 self._version = ( basename.strip().replace(".tar.gz", "")
93 if not self.get("build"):
94 self.set("build", self._build)
96 if not self.get("install"):
97 self.set("install", self._install)
99 if not self.get("env"):
100 self.set("env", self._environment)
102 command = self.get("command")
104 self.info("Deploying command '%s' " % command)
109 self.debug("----- READY ---- ")
112 def upload_start_command(self):
113 command = self.get("command")
114 env = self.get("env")
116 # We want to make sure the ccnd is running
117 # before the experiment starts.
118 # Run the command as a bash script in background,
119 # in the host ( but wait until the command has
120 # finished to continue )
121 env = self.replace_paths(env)
122 command = self.replace_paths(command)
124 shfile = os.path.join(self.app_home, "start.sh")
125 self.node.run_and_wait(command, self.run_home,
129 raise_on_error = True)
132 if self.state == ResourceState.READY:
133 command = self.get("command")
134 self.info("Starting command '%s'" % command)
138 msg = " Failed to execute command '%s'" % command
139 self.error(msg, out, err)
140 raise RuntimeError, msg
143 command = self.get('command') or ''
145 if self.state == ResourceState.STARTED:
146 self.info("Stopping command '%s'" % command)
149 env = self.get("env")
151 # replace application specific paths in the command
152 command = self.replace_paths(command)
153 env = env and self.replace_paths(env)
155 # Upload the command to a file, and execute asynchronously
156 shfile = os.path.join(self.app_home, "stop.sh")
157 self.node.run_and_wait(command, self.run_home,
161 pidfile = "ccndstop_pidfile",
162 ecodefile = "ccndstop_exitcode",
163 stdout = "ccndstop_stdout",
164 stderr = "ccndstop_stderr")
170 # First check if the ccnd has failed
171 state_check_delay = 0.5
172 if self._state == ResourceState.STARTED and \
173 tdiffsec(tnow(), self._last_state_check) > state_check_delay:
174 (out, err), proc = self._ccndstatus()
176 retcode = proc.poll()
178 if retcode == 1 and err.find("No such file or directory") > -1:
179 # ccnd is not running (socket not found)
183 msg = " Failed to execute command '%s'" % self.get("command")
184 self.error(msg, out, err)
187 self._last_state_check = tnow()
191 def _ccndstatus(self):
192 env = self.get('env') or ""
193 environ = self.node.format_environment(env, inline = True)
194 command = environ + " ccndstatus"
195 command = self.replace_paths(command)
197 return self.node.execute(command)
200 def _start_command(self):
204 def _dependencies(self):
205 if self.node.use_rpm:
206 return ( " autoconf openssl-devel expat-devel libpcap-devel "
207 " ecryptfs-utils-devel libxml2-devel automake gawk "
208 " gcc gcc-c++ git pcre-devel make ")
209 elif self.node.use_deb:
210 return ( " autoconf libssl-dev libexpat-dev libpcap-dev "
211 " libecryptfs0 libxml2-utils automake gawk gcc g++ "
212 " git-core pkg-config libpcre3-dev make ")
217 return "http://www.ccnx.org/releases/ccnx-0.7.2.tar.gz"
221 sources = self.get("sources").split(" ")[0]
222 sources = os.path.basename(sources)
225 # Evaluate if ccnx binaries are already installed
227 " test -f ${BIN}/%(version)s/ccnd && "
228 " echo 'binaries found, nothing to do' "
230 # If not, untar and build
232 " mkdir -p ${SRC}/%(version)s && "
233 " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/%(version)s "
235 "cd ${SRC}/%(version)s && "
236 # Just execute and silence warnings...
237 " ( ./configure && make ) "
238 " )") % ({ 'sources': sources,
239 'version': self.version
245 # Evaluate if ccnx binaries are already installed
247 " test -f ${BIN}/%(version)s/ccnd && "
248 " echo 'binaries found, nothing to do' "
251 " mkdir -p ${BIN}/%(version)s && "
252 " mv ${SRC}/%(version)s/bin/* ${BIN}/%(version)s/ "
254 ) % ({ 'version': self.version
258 def _environment(self):
260 "debug": "CCND_DEBUG",
261 "port": "CCN_LOCAL_PORT",
262 "sockname" : "CCN_LOCAL_SOCKNAME",
263 "capacity" : "CCND_CAP",
265 "dataPauseMicrosec" : "CCND_DATA_PAUSE_MICROSEC",
266 "defaultTimeToStale" : "CCND_DEFAULT_TIME_TO_STALE",
267 "maxTimeToStale" : "CCND_MAX_TIME_TO_STALE",
268 "maxRteMicrosec" : "CCND_MAX_RTE_MICROSEC",
269 "keyStoreDirectory" : "CCND_KEYSTORE_DIRECTORY",
270 "listenOn" : "CCND_LISTEN_ON",
271 "autoreg" : "CCND_AUTOREG",
272 "prefix" : "CCND_PREFIX",
276 env += " ".join(map(lambda k: "%s=%s" % (envs.get(k), str(self.get(k))) \
277 if self.get(k) else "", envs.keys()))
281 def valid_connection(self, guid):