Adapt to new signature of TestbedController.set/get
[nepi.git] / test / testbeds / planetlab / execute.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import getpass
5 from nepi.util.constants import STATUS_FINISHED
6 from nepi.testbeds import planetlab
7 import os
8 import shutil
9 import tempfile
10 import time
11 import unittest
12 import re
13 import test_util
14
15 class PlanetLabExecuteTestCase(unittest.TestCase):
16     def setUp(self):
17         self.root_dir = tempfile.mkdtemp()
18         
19     def tearDown(self):
20         shutil.rmtree(self.root_dir)
21
22     def make_instance(self):
23         testbed_version = "01"
24         instance = planetlab.TestbedController(testbed_version)
25         slicename = "inria_nepi12"
26         pl_user, pl_pwd = test_util.pl_auth()
27         
28         instance.defer_configure("homeDirectory", self.root_dir)
29         instance.defer_configure("slice", slicename)
30         instance.defer_configure("sliceSSHKey", "/user/%s/home/.ssh/id_rsa_planetlab" % (getpass.getuser(),))
31         instance.defer_configure("authUser", pl_user)
32         instance.defer_configure("authPass", pl_pwd)
33         
34         return instance
35
36     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
37     def test_simple(self):
38         instance = self.make_instance()
39         
40         instance.defer_create(2, "Node")
41         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
42         instance.defer_create(3, "Node")
43         instance.defer_create_set(3, "hostname", "onelab10.pl.sophia.inria.fr")
44         instance.defer_create(4, "NodeInterface")
45         instance.defer_connect(2, "devs", 4, "node")
46         instance.defer_create(5, "NodeInterface")
47         instance.defer_connect(3, "devs", 5, "node")
48         instance.defer_create(6, "Internet")
49         instance.defer_connect(4, "inet", 6, "devs")
50         instance.defer_connect(5, "inet", 6, "devs")
51         instance.defer_create(7, "Application")
52         instance.defer_create_set(7, "command", "ping -qc1 {#[GUID-5].addr[0].[Address]#}")
53         instance.defer_add_trace(7, "stdout")
54         instance.defer_add_trace(7, "stderr")
55         instance.defer_connect(7, "node", 2, "apps")
56
57         comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
58
59 --- .* ping statistics ---
60 1 packets transmitted, 1 received, 0% packet loss, time \d*ms.*
61 """
62
63         try:
64             instance.do_setup()
65             instance.do_create()
66             instance.do_connect_init()
67             instance.do_connect_compl()
68             instance.do_preconfigure()
69             
70             # Manually replace netref
71             instance.set(7, "command",
72                 instance.get(7, "command")
73                     .replace("{#[GUID-5].addr[0].[Address]#}", 
74                         instance.get_address(5, 0, "Address") )
75             )
76
77             instance.do_configure()
78             
79             instance.start()
80             while instance.status(7) != STATUS_FINISHED:
81                 time.sleep(0.5)
82             ping_result = instance.trace(7, "stdout") or ""
83             instance.stop()
84         finally:
85             instance.shutdown()
86
87         # asserts at the end, to make sure there's proper cleanup
88         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
89             "Unexpected trace:\n" + ping_result)
90         
91     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
92     def test_depends(self):
93         instance = self.make_instance()
94         
95         instance.defer_create(2, "Node")
96         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
97         instance.defer_create(3, "NodeInterface")
98         instance.defer_connect(2, "devs", 3, "node")
99         instance.defer_create(4, "Internet")
100         instance.defer_connect(3, "inet", 4, "devs")
101         instance.defer_create(5, "Application")
102         instance.defer_create_set(5, "command", "gfortran --version")
103         instance.defer_create_set(5, "depends", "gcc-gfortran")
104         instance.defer_add_trace(5, "stdout")
105         instance.defer_add_trace(5, "stderr")
106         instance.defer_connect(5, "node", 2, "apps")
107
108         try:
109             instance.do_setup()
110             instance.do_create()
111             instance.do_connect_init()
112             instance.do_connect_compl()
113             instance.do_preconfigure()
114             instance.do_configure()
115             
116             instance.start()
117             while instance.status(5) != STATUS_FINISHED:
118                 time.sleep(0.5)
119             ping_result = instance.trace(5, "stdout") or ""
120             comp_result = r".*GNU Fortran \(GCC\).*"
121             instance.stop()
122         finally:
123             instance.shutdown()
124
125         # asserts at the end, to make sure there's proper cleanup
126         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
127             "Unexpected trace:\n" + ping_result)
128         
129     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
130     def test_build(self):
131         instance = self.make_instance()
132         
133         instance.defer_create(2, "Node")
134         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
135         instance.defer_create(3, "NodeInterface")
136         instance.defer_connect(2, "devs", 3, "node")
137         instance.defer_create(4, "Internet")
138         instance.defer_connect(3, "inet", 4, "devs")
139         instance.defer_create(10, "Application")
140         instance.defer_create_set(10, "command", "./consts")
141         instance.defer_create_set(10, "buildDepends", "gcc")
142         instance.defer_create_set(10, "build", "gcc ${SOURCES}/consts.c -o consts")
143         instance.defer_create_set(10, "install", "cp consts ${SOURCES}/consts")
144         instance.defer_create_set(10, "sources", os.path.join(os.path.dirname(planetlab.__file__),'scripts','consts.c'))
145         instance.defer_add_trace(10, "stdout")
146         instance.defer_add_trace(10, "stderr")
147         instance.defer_connect(10, "node", 2, "apps")
148
149         comp_result = \
150 r""".*ETH_P_ALL = 0x[0-9a-fA-F]{8}
151 ETH_P_IP = 0x[0-9a-fA-F]{8}
152 TUNSETIFF = 0x[0-9a-fA-F]{8}
153 IFF_NO_PI = 0x[0-9a-fA-F]{8}
154 IFF_TAP = 0x[0-9a-fA-F]{8}
155 IFF_TUN = 0x[0-9a-fA-F]{8}
156 IFF_VNET_HDR = 0x[0-9a-fA-F]{8}
157 TUN_PKT_STRIP = 0x[0-9a-fA-F]{8}
158 IFHWADDRLEN = 0x[0-9a-fA-F]{8}
159 IFNAMSIZ = 0x[0-9a-fA-F]{8}
160 IFREQ_SZ = 0x[0-9a-fA-F]{8}
161 FIONREAD = 0x[0-9a-fA-F]{8}.*
162 """
163
164         try:
165             instance.do_setup()
166             instance.do_create()
167             instance.do_connect_init()
168             instance.do_connect_compl()
169             instance.do_preconfigure()
170             instance.do_configure()
171             
172             instance.start()
173             while instance.status(10) != STATUS_FINISHED:
174                 time.sleep(0.5)
175             ping_result = instance.trace(10, "stdout") or ""
176             instance.stop()
177         finally:
178             instance.shutdown()
179
180         # asserts at the end, to make sure there's proper cleanup
181         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
182             "Unexpected trace:\n" + ping_result)
183         
184     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
185     def test_simple_vsys(self):
186         instance = self.make_instance()
187         
188         instance.defer_create(2, "Node")
189         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
190         instance.defer_create_set(2, "emulation", True) # require emulation
191         instance.defer_create(3, "NodeInterface")
192         instance.defer_connect(2, "devs", 3, "node")
193         instance.defer_create(4, "Internet")
194         instance.defer_connect(3, "inet", 4, "devs")
195         instance.defer_create(5, "TunInterface")
196         instance.defer_add_address(5, "192.168.2.2", 24, False)
197         instance.defer_connect(2, "devs", 5, "node")
198         instance.defer_create(6, "Application")
199         instance.defer_create_set(6, "command", """
200 set -e
201 netconfig help > /dev/null
202 test -e /vsys/vif_up.in > /dev/null
203 test -e /vsys/vif_up.out > /dev/null
204 test -e /vsys/fd_tuntap.control > /dev/null
205 echo 'OKIDOKI'
206 """)
207         instance.defer_create_set(6, "sudo", True) # only sudo has access to /vsys
208         instance.defer_add_trace(6, "stdout")
209         instance.defer_add_trace(6, "stderr")
210         instance.defer_connect(6, "node", 2, "apps")
211
212         try:
213             instance.do_setup()
214             instance.do_create()
215             instance.do_connect_init()
216             instance.do_connect_compl()
217             instance.do_preconfigure()
218             instance.do_configure()
219             
220             instance.start()
221             while instance.status(6) != STATUS_FINISHED:
222                 time.sleep(0.5)
223             test_result = (instance.trace(6, "stdout") or "").strip()
224             comp_result = "OKIDOKI"
225             instance.stop()
226         finally:
227             instance.shutdown()
228
229         # asserts at the end, to make sure there's proper cleanup
230         self.assertEqual(comp_result, test_result)
231
232     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
233     def test_emulation(self):
234         instance = self.make_instance()
235         
236         instance.defer_create(2, "Node")
237         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
238         instance.defer_create_set(2, "emulation", True) # require emulation
239         instance.defer_create(3, "NodeInterface")
240         instance.defer_connect(2, "devs", 3, "node")
241         instance.defer_create(4, "Internet")
242         instance.defer_connect(3, "inet", 4, "devs")
243         instance.defer_create(7, "NetPipe")
244         instance.defer_create_set(7, "mode", "CLIENT")
245         instance.defer_create_set(7, "portList", "80")
246         instance.defer_create_set(7, "bwOut", 12.0/1024.0) # 12kbps
247         instance.defer_create_set(7, "bwIn", 64.0/1024.0) # 64kbps
248         instance.defer_create_set(7, "plrOut", 0.01) # 1% plr outbound - high loss
249         instance.defer_create_set(7, "plrIn", 0.001) # 0.1% plr inbound - regular loss
250         instance.defer_create_set(7, "delayOut", int(1500 * 8 / (12.0/1024.0) / 1000)) # tx delay at 12kbps in ms
251         instance.defer_create_set(7, "delayIn", int(1500 * 8 / (64.0/1024.0) / 1000)) # rx delay at 64kbps in ms
252         instance.defer_add_trace(7, "netpipeStats")
253         instance.defer_connect(2, "pipes", 7, "node")
254         instance.defer_create(8, "Application")
255         instance.defer_create_set(8, "command", "time wget -q -O /dev/null http://www.google.com/") # Fetch ~10kb
256         instance.defer_add_trace(8, "stdout")
257         instance.defer_add_trace(8, "stderr")
258         instance.defer_connect(8, "node", 2, "apps")
259
260         try:
261             instance.do_setup()
262             instance.do_create()
263             instance.do_connect_init()
264             instance.do_connect_compl()
265             instance.do_preconfigure()
266             instance.do_configure()
267             
268             instance.start()
269             while instance.status(8) != STATUS_FINISHED:
270                 time.sleep(0.5)
271             test_result = (instance.trace(8, "stderr") or "").strip()
272             comp_result = r".*real\s*(?P<min>[0-9]+)m(?P<sec>[0-9]+[.][0-9]+)s.*"
273             netpipe_stats = instance.trace(7, "netpipeStats")
274             
275             instance.stop()
276         finally:
277             instance.shutdown()
278
279         # asserts at the end, to make sure there's proper cleanup
280         match = re.match(comp_result, test_result, re.MULTILINE)
281         self.assertTrue(match, "Unexpected output: %s" % (test_result,))
282         
283         minutes = int(match.group("min"))
284         seconds = float(match.group("sec"))
285         self.assertTrue((minutes * 60 + seconds) > 1.0, "Emulation not effective: %s" % (test_result,))
286
287         self.assertTrue(netpipe_stats, "Unavailable netpipe stats")
288
289     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
290     def test_tun_emulation_requirement(self):
291         instance = self.make_instance()
292         
293         instance.defer_create(2, "Node")
294         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
295         instance.defer_create(3, "NodeInterface")
296         instance.defer_connect(2, "devs", 3, "node")
297         instance.defer_create(4, "Internet")
298         instance.defer_connect(3, "inet", 4, "devs")
299         instance.defer_create(5, "TunInterface")
300         instance.defer_add_address(5, "192.168.2.2", 24, False)
301         instance.defer_connect(2, "devs", 5, "node")
302         instance.defer_create(6, "Application")
303         instance.defer_create_set(6, "command", "false")
304         instance.defer_add_trace(6, "stdout")
305         instance.defer_add_trace(6, "stderr")
306         instance.defer_connect(6, "node", 2, "apps")
307
308         try:
309             instance.do_setup()
310             instance.do_create()
311             instance.do_connect_init()
312             instance.do_connect_compl()
313             instance.do_preconfigure()
314             instance.do_configure()
315             self.fail("Usage of TUN without emulation should fail")
316         except Exception,e:
317             pass
318
319     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
320     def test_tun_ping(self):
321         instance = self.make_instance()
322         
323         instance.defer_create(2, "Node")
324         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
325         instance.defer_create_set(2, "emulation", True) # require emulation
326         instance.defer_create(3, "Node")
327         instance.defer_create_set(3, "hostname", "onelab10.pl.sophia.inria.fr")
328         instance.defer_create_set(3, "emulation", True) # require emulation
329         instance.defer_create(4, "NodeInterface")
330         instance.defer_connect(2, "devs", 4, "node")
331         instance.defer_create(5, "Internet")
332         instance.defer_connect(4, "inet", 5, "devs")
333         instance.defer_create(6, "NodeInterface")
334         instance.defer_connect(3, "devs", 6, "node")
335         instance.defer_connect(6, "inet", 5, "devs")
336         instance.defer_create(7, "TunInterface")
337         instance.defer_add_address(7, "192.168.2.2", 24, False)
338         instance.defer_connect(2, "devs", 7, "node")
339         instance.defer_create(8, "TunInterface")
340         instance.defer_add_address(8, "192.168.2.3", 24, False)
341         instance.defer_connect(3, "devs", 8, "node")
342         instance.defer_connect(7, "tcp", 8, "tcp")
343         instance.defer_create(9, "Application")
344         instance.defer_create_set(9, "command", "ping -qc1 {#[GUID-8].addr[0].[Address]#}")
345         instance.defer_add_trace(9, "stdout")
346         instance.defer_add_trace(9, "stderr")
347         instance.defer_connect(9, "node", 2, "apps")
348
349         comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
350
351 --- .* ping statistics ---
352 1 packets transmitted, 1 received, 0% packet loss, time \d*ms.*
353 """
354
355         try:
356             instance.do_setup()
357             instance.do_create()
358             instance.do_connect_init()
359             instance.do_connect_compl()
360             instance.do_preconfigure()
361             
362             # Manually replace netref
363             instance.set(9, "command",
364                 instance.get(9, "command")
365                     .replace("{#[GUID-8].addr[0].[Address]#}", 
366                         instance.get_address(8, 0, "Address") )
367             )
368             
369             instance.do_configure()
370             
371             instance.start()
372             while instance.status(9) != STATUS_FINISHED:
373                 time.sleep(0.5)
374             ping_result = instance.trace(9, "stdout") or ""
375             instance.stop()
376         finally:
377             instance.shutdown()
378
379         # asserts at the end, to make sure there's proper cleanup
380         self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
381             "Unexpected trace:\n" + ping_result)
382
383     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
384     def test_nepi_depends(self):
385         instance = self.make_instance()
386         
387         instance.defer_create(2, "Node")
388         instance.defer_create_set(2, "hostname", "onelab11.pl.sophia.inria.fr")
389         instance.defer_create(3, "NodeInterface")
390         instance.defer_connect(2, "devs", 3, "node")
391         instance.defer_create(4, "Internet")
392         instance.defer_connect(3, "inet", 4, "devs")
393         instance.defer_create(5, "NepiDependency")
394         instance.defer_connect(5, "node", 2, "deps")
395         instance.defer_create(12, "Application")
396         instance.defer_connect(12, "node", 2, "apps")
397         instance.defer_create_set(12, "command", "python -c 'import nepi'")
398         instance.defer_add_trace(12, "stderr")
399
400         try:
401             instance.do_setup()
402             instance.do_create()
403             instance.do_connect_init()
404             instance.do_connect_compl()
405             instance.do_preconfigure()
406             instance.do_configure()
407             
408             instance.start()
409             while instance.status(12) != STATUS_FINISHED:
410                 time.sleep(0.5)
411             ping_result = (instance.trace(12, "stderr") or "").strip()
412             instance.stop()
413         finally:
414             instance.shutdown()
415         
416         # asserts at the end, to make sure there's proper cleanup
417         self.assertEqual(ping_result, "")
418         
419
420 if __name__ == '__main__':
421     unittest.main()
422