2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2013 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 version 2 as
7 # published by the Free Software Foundation;
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19 from nepi.execution.attribute import Attribute, Flags, Types
20 from nepi.execution.trace import Trace, TraceAttr
21 from nepi.execution.resource import clsinit_copy, ResourceState, \
23 from nepi.resources.linux.application import LinuxApplication
24 from nepi.resources.linux.ccn.ccnd import LinuxCCND
25 from nepi.util.timefuncs import tnow
32 # TODO: Add rest of options for ccndc!!!
33 # Implement ENTRY DELETE!!
36 class LinuxFIBEntry(LinuxApplication):
37 _rtype = "linux::FIBEntry"
40 def _register_attributes(cls):
41 uri = Attribute("uri",
42 "URI prefix to match and route for this FIB entry",
46 protocol = Attribute("protocol",
47 "Transport protocol used in network connection to peer "
48 "for this FIB entry. One of 'udp' or 'tcp'.",
49 type = Types.Enumerate,
51 allowed = ["udp", "tcp"],
54 host = Attribute("host",
55 "Peer hostname used in network connection for this FIB entry. ",
58 port = Attribute("port",
59 "Peer port address used in network connection to peer "
60 "for this FIB entry.",
64 "Peer host public IP used in network connection for this FIB entry. ",
67 cls._register_attribute(uri)
68 cls._register_attribute(protocol)
69 cls._register_attribute(host)
70 cls._register_attribute(port)
71 cls._register_attribute(ip)
74 def _register_traces(cls):
75 ping = Trace("ping", "Ping to the peer end")
76 mtr = Trace("mtr", "Mtr to the peer end")
77 traceroute = Trace("traceroute", "Tracerout to the peer end")
79 cls._register_trace(ping)
80 cls._register_trace(mtr)
81 cls._register_trace(traceroute)
83 def __init__(self, ec, guid):
84 super(LinuxFIBEntry, self).__init__(ec, guid)
85 self._home = "fib-%s" % self.guid
87 self._traceroute = None
93 ccnd = self.get_connected(LinuxCCND.get_rtype())
102 from nepi.resources.linux.ping import LinuxPing
103 ping = self.get_connected(LinuxPing.get_rtype())
110 def traceroute(self):
111 if not self._traceroute:
112 from nepi.resources.linux.traceroute import LinuxTraceroute
113 traceroute = self.get_connected(LinuxTraceroute.get_rtype())
115 self._traceroute = traceroute[0]
117 return self._traceroute
121 if self.ccnd: return self.ccnd.node
124 def trace(self, name, attr = TraceAttr.ALL, block = 512, offset = 0):
128 return self.ec.trace(self.ping.guid, "stdout", attr, block, offset)
130 if name == "traceroute":
131 if not self.traceroute:
133 return self.ec.trace(self.traceroute.guid, "stdout", attr, block, offset)
135 return super(LinuxFIBEntry, self).trace(name, attr, block, offset)
138 # Wait until associated ccnd is provisioned
139 if not self.ccnd or self.ccnd.state < ResourceState.READY:
140 # ccnr needs to wait until ccnd is deployed and running
141 self.ec.schedule(self.reschedule_delay, self.deploy)
143 if not self.get("ip"):
144 host = self.get("host")
145 ip = socket.gethostbyname(host)
148 if not self.get("command"):
149 self.set("command", self._start_command)
151 if not self.get("env"):
152 self.set("env", self._environment)
154 command = self.get("command")
156 self.info("Deploying command '%s' " % command)
164 def upload_start_command(self):
165 command = self.get("command")
166 env = self.get("env")
168 # We want to make sure the FIB entries are created
169 # before the experiment starts.
170 # Run the command as a bash script in the background,
171 # in the host ( but wait until the command has
172 # finished to continue )
173 env = env and self.replace_paths(env)
174 command = self.replace_paths(command)
176 # ccndc seems to return exitcode OK even if a (dns) error
177 # occurred, so we need to account for this case here.
178 (out, err), proc = self.execute_command(command,
179 env, blocking = True)
182 msg = "Failed to execute command"
183 self.error(msg, out, err)
184 raise RuntimeError, msg
187 if self.trace_enabled("ping") and not self.ping:
188 self.info("Configuring PING trace")
189 ping = self.ec.register_resource("linux::Ping")
190 self.ec.set(ping, "printTimestamp", True)
191 self.ec.set(ping, "target", self.get("host"))
192 self.ec.set(ping, "earlyStart", True)
193 self.ec.register_connection(ping, self.node.guid)
194 self.ec.register_connection(ping, self.guid)
195 # schedule ping deploy
196 self.ec.deploy(guids=[ping], group = self.deployment_group)
198 if self.trace_enabled("traceroute") and not self.traceroute:
199 self.info("Configuring TRACEROUTE trace")
200 traceroute = self.ec.register_resource("linux::Traceroute")
201 self.ec.set(traceroute, "printTimestamp", True)
202 self.ec.set(traceroute, "continuous", True)
203 self.ec.set(traceroute, "target", self.get("host"))
204 self.ec.set(traceroute, "earlyStart", True)
205 self.ec.register_connection(traceroute, self.node.guid)
206 self.ec.register_connection(traceroute, self.guid)
207 # schedule mtr deploy
208 self.ec.deploy(guids=[traceroute], group = self.deployment_group)
211 if self.state == ResourceState.READY:
212 command = self.get("command")
213 self.info("Starting command '%s'" % command)
217 msg = " Failed to execute command '%s'" % command
218 self.error(msg, out, err)
219 raise RuntimeError, msg
222 command = self.get('command')
223 env = self.get('env')
225 if self.state == ResourceState.STARTED:
226 self.info("Stopping command '%s'" % command)
228 command = self._stop_command
229 (out, err), proc = self.execute_command(command, env,
235 msg = " Failed to execute command '%s'" % command
236 self.error(msg, out, err)
237 raise RuntimeError, msg
240 def _start_command(self):
241 uri = self.get("uri") or ""
242 protocol = self.get("protocol") or ""
243 ip = self.get("ip") or ""
244 port = self.get("port") or ""
246 # add ccnx:/example.com/ udp 224.0.0.204 52428
247 return "ccndc add %(uri)s %(protocol)s %(host)s %(port)s" % ({
249 "protocol": protocol,
255 def _stop_command(self):
256 uri = self.get("uri") or ""
257 protocol = self.get("protocol") or ""
258 ip = self.get("ip") or ""
259 port = self.get("port") or ""
261 # add ccnx:/example.com/ udp 224.0.0.204 52428
262 return "ccndc del %(uri)s %(protocol)s %(host)s %(port)s" % ({
264 "protocol": protocol,
270 def _environment(self):
271 return self.ccnd.path
273 def valid_connection(self, guid):