Adding LinuxUdpTest RM
[nepi.git] / src / nepi / resources / linux / udptest.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
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.
9 #
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.
14 #
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/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20 from nepi.execution.attribute import Attribute, Flags, Types
21 from nepi.execution.resource import ResourceManager, clsinit_copy, ResourceState, \
22         reschedule_delay
23 from nepi.execution.resource import clsinit_copy 
24 from nepi.resources.linux.application import LinuxApplication
25 from nepi.util.timefuncs import tnow
26
27 import os
28
29 @clsinit_copy
30 class LinuxUdpTest(LinuxApplication):
31     """ Uses the hpcbench udptest tool to gather UDP measurements.
32     Measurements require two ends, a server and a client RM.
33
34     http://hpcbench.sourceforge.net/
35     """
36     _rtype = "LinuxUdpTest"
37
38     @classmethod
39     def _register_attributes(cls):
40         s = Attribute("s",
41             "Runs in server mode. ",
42             type = Types.Bool,
43             default = False,
44             flags = Flags.ExecReadOnly)
45
46         p = Attribute("p",
47             "Port to listen to in server mode, or to connect to in client mode. "
48             "Defaults to 5678. ",
49             type = Types.Integer,
50             flags = Flags.ExecReadOnly)
51
52         a = Attribute("a",
53             "Client option. Perform UDP Round Trip Time (latency) ",
54             type = Types.Bool,
55             flags = Flags.ExecReadOnly)
56
57         A = Attribute("A",
58             "Client option. "
59             "Message size for UDP RTT test. "
60             "UDP RTT (latency) test with specified message size.",
61             type = Types.Integer,
62             flags = Flags.ExecReadOnly)
63
64         b = Attribute("b",
65             "Client option. "
66             "Client UDP buffer size in bytes. Using system default "
67             "value if not defined.",
68             type = Types.Integer,
69             flags = Flags.ExecReadOnly)
70
71         B = Attribute("B",
72             "Client option. "
73             "Server UDP buffer size in bytes. The same as cleint's by default.",
74             type = Types.Integer,
75             flags = Flags.ExecReadOnly)
76
77         c = Attribute("c",
78             "Client option. "
79             "CPU log option. Tracing system info during the test. "
80             "Only available when output is defined. ",
81             type = Types.Bool,
82             flags = Flags.ExecReadOnly)
83
84         d = Attribute("d",
85             "Client option. "
86             "Data size of each read/write in bytes. The same as packet size "
87             "by default.",
88             type = Types.Integer,
89             flags = Flags.ExecReadOnly)
90
91         e = Attribute("e",
92             "Client option. "
93             "Exponential test (data size of each sending increasing from 1 "
94             "byte to packet size). ",
95             type = Types.Bool,
96             flags = Flags.ExecReadOnly)
97
98         g = Attribute("g",
99             "Client option. "
100             "UDP traffic generator (Keep sending data to a host). "
101             "Work without server's support.",
102             type = Types.Bool,
103             flags = Flags.ExecReadOnly)
104
105         target = Attribute("target",
106             "Client option. "
107             "Hostname or IP address of UDP server. Must be specified.",
108             flags = Flags.ExecReadOnly)
109
110         i = Attribute("i",
111             "Client option. "
112             "Bidirectional UDP throuhgput test. Default is unidirection "
113             "stream test. ",
114             type = Types.Bool,
115             flags = Flags.ExecReadOnly)
116
117         l = Attribute("l",
118             "Client option. "
119             "UDP datagram (packet) size in bytes ( < udp-buffer-szie ). "
120             "1460 by default.",
121             type = Types.Integer,
122             flags = Flags.ExecReadOnly)
123
124         m = Attribute("m",
125             "Client option. "
126             "Total message size in bytes. 1048576 by default.",
127             type = Types.Integer,
128             flags = Flags.ExecReadOnly)
129
130         o = Attribute("o",
131             "Client option. "
132             "Output file name. ",
133             flags = Flags.ExecReadOnly)
134
135         P = Attribute("P",
136             "Client option. "
137             "Write the plot file for gnuplot. Only enable when the output "
138             "is specified. ",
139             type = Types.Bool,
140             flags = Flags.ExecReadOnly)
141
142         q = Attribute("q",
143             "Client option. "
144             "Define the TOS field of IP packets. "
145             "Six values can be used for this setting:\n"
146             " 1:(IPTOS)-Minimize delay\n"
147             " 2:(IPTOS)-Maximize throughput\n"
148             " 3:(DiffServ)-Class1 with low drop probability\n"
149             " 4:(DiffServ)-class1 with high drop probability\n"
150             " 5:(DiffServ)-Class4 with low drop probabiltiy\n"
151             " 6:(DiffServ)-Class4 with high drop probabiltiy\n"
152             "Write the plot file for gnuplot. Only enable when the output "
153             "is specified. ",
154             type = Types.Enumerate,
155             allowed = ["1", "2", "3", "4", "5", "6"],
156             flags = Flags.ExecReadOnly)
157
158         r = Attribute("r",
159             "Client option. "
160             "Repetition of tests. 10 by default. ",
161             type = Types.Integer,
162             flags = Flags.ExecReadOnly)
163
164         t = Attribute("t",
165             "Client option. "
166             "Test time constraint in seconds. 5 by default. ",
167             type = Types.Integer,
168             flags = Flags.ExecReadOnly)
169
170         T = Attribute("T",
171             "Client option. "
172             "Throughput constraint for UDP generator or throughput "
173             "test. Unlimited by default. ",
174             type = Types.Integer,
175             flags = Flags.ExecReadOnly)
176
177         continuous = Attribute("continuous",
178             "Run nping in a while loop",
179             type = Types.Bool,
180             default = False,
181             flags = Flags.ExecReadOnly)
182
183         print_timestamp = Attribute("printTimestamp",
184             "Print timestamp before running nping",
185             type = Types.Bool,
186             default = False,
187             flags = Flags.ExecReadOnly)
188
189         cls._register_attribute(s)
190         cls._register_attribute(p)
191         cls._register_attribute(a)
192         cls._register_attribute(A)
193         cls._register_attribute(b)
194         cls._register_attribute(B)
195         cls._register_attribute(c)
196         cls._register_attribute(d)
197         cls._register_attribute(e)
198         cls._register_attribute(g)
199         cls._register_attribute(target)
200         cls._register_attribute(g)
201         cls._register_attribute(i)
202         cls._register_attribute(l)
203         cls._register_attribute(m)
204         cls._register_attribute(o)
205         cls._register_attribute(P)
206         cls._register_attribute(q)
207         cls._register_attribute(r)
208         cls._register_attribute(t)
209         cls._register_attribute(T)
210         cls._register_attribute(continuous)
211         cls._register_attribute(print_timestamp)
212
213     def __init__(self, ec, guid):
214         super(LinuxUdpTest, self).__init__(ec, guid)
215         self._home = "udptest-%s" % self.guid
216
217     def deploy(self):
218         if not self.get("command"):
219             self.set("command", self._start_command)
220
221         if not self.get("sources"):
222             self.set("sources", self._sources)
223
224         if not self.get("install"):
225             self.set("install", self._install)
226
227         if not self.get("build"):
228             self.set("build", self._build)
229
230         if not self.get("env"):
231             self.set("env", self._environment)
232
233         if not self.get("depends"):
234             self.set("depends", self._depends)
235
236         super(LinuxUdpTest, self).deploy()
237
238     def upload_start_command(self):
239
240         super(LinuxUdpTest, self).upload_start_command()
241
242         if self.get("s") == True:
243             # We want to make sure the server is running
244             # before the client starts.
245             # Run the command as a bash script in background,
246             # in the host ( but wait until the command has
247             # finished to continue )
248             self._run_in_background()
249     
250     def start(self):
251         if self.get("s") == True:
252             # Server is already running
253             if self._state == ResourceState.READY:
254                 command = self.get("command")
255                 self.info("Starting command '%s'" % command)
256
257                 self._start_time = tnow()
258                 self._state = ResourceState.STARTED
259             else:
260                 msg = " Failed to execute command '%s'" % command
261                 self.error(msg, out, err)
262                 self._state = ResourceState.FAILED
263                 raise RuntimeError, msg
264         else:
265             super(LinuxUdpTest, self).start()
266  
267     @property
268     def _start_command(self):
269         args = []
270         if self.get("continuous") == True:
271             args.append("while true; do ")
272
273         if self.get("printTimestamp") == True:
274             args.append("""echo "`date +'%Y%m%d%H%M%S'`";""")
275
276         if self.get("s") == True:
277             args.append("udpserver")
278         else:
279             args.append("udptest")
280
281         if self.get("p"):
282             args.append("-p %d" % self.get("p"))
283         if self.get("a") == True:
284             args.append("-a")
285         if self.get("A"):
286             args.append("-A %d" % self.get("A"))
287         if self.get("b"):
288             args.append("-b %d" % self.get("b"))
289         if self.get("B"):
290             args.append("-B %d" % self.get("B"))
291         if self.get("c") == True:
292             args.append("-c")
293         if self.get("d"):
294             args.append("-d %d" % self.get("d"))
295         if self.get("e") == True:
296             args.append("-e")
297         if self.get("g") == True:
298             args.append("-g")
299         if self.get("target"):
300             args.append("-h %s" % self.get("target"))
301         if self.get("i") == True:
302             args.append("-i")
303         if self.get("l"):
304             args.append("-l %d" % self.get("l"))
305         if self.get("m"):
306             args.append("-m %d" % self.get("m"))
307         if self.get("o"):
308             args.append("-o %d" % self.get("o"))
309         if self.get("P"):
310             args.append("-P %d" % self.get("P"))
311         if self.get("q"):
312             args.append("-q %s" % self.get("q"))
313         if self.get("r"):
314             args.append("-r %d" % self.get("r"))
315         if self.get("t"):
316             args.append("-t %d" % self.get("t"))
317         if self.get("T"):
318             args.append("-T %d" % self.get("T"))
319
320         if self.get("continuous") == True:
321             args.append("; done ")
322
323         command = " ".join(args)
324
325         return command
326
327     @property
328     def _sources(self):
329         return "http://hpcbench.sourceforge.net/udp.tar.gz"
330
331     @property
332     def _depends(self):
333         return "gcc make"
334
335     @property
336     def _build(self):
337         sources = self.get("sources").split(" ")[0]
338         sources = os.path.basename(sources)
339
340         return (
341             # Evaluate if ccnx binaries are already installed
342             " ( "
343                 " test -f ${BIN}/udptest && "
344                 " echo 'binaries found, nothing to do' "
345             " ) || ( "
346             # If not, untar and build
347                 " ( "
348                     " mkdir -p ${SRC}/udptest && "
349                     " tar xf ${SRC}/%(sources)s --strip-components=1 -C ${SRC}/udptest "
350                  " ) && "
351                     "cd ${SRC}/udptest && "
352                     # Just execute and silence warnings...
353                     " ( make ) "
354              " )") % ({ 'sources': sources,
355                  })
356
357     @property
358     def _install(self):
359         return (
360             # Evaluate if ccnx binaries are already installed
361             " ( "
362                 " test -f ${BIN}/udptest && "
363                 " echo 'binaries found, nothing to do' "
364             " ) || ( "
365             # If not, install
366                 "  mv ${SRC}/udptest ${BIN} "
367             " )")
368
369     @property
370     def _environment(self):
371         return "PATH=$PATH:${BIN}/udptest"
372
373     def valid_connection(self, guid):
374         # TODO: Validate!
375         return True
376