Made automatic proxy reconnection more robust
[nepi.git] / test / testbeds / planetlab / integration.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import getpass
5 from nepi.core.design import ExperimentDescription, FactoriesProvider
6 from nepi.core.execute import ExperimentController
7 from nepi.util import proxy
8 from nepi.util.constants import DeploymentConfiguration as DC
9 import os
10 import shutil
11 import tempfile
12 import test_util
13 import time
14 import unittest
15 import re
16 import sys
17
18 class PlanetLabIntegrationTestCase(unittest.TestCase):
19     testbed_id = "planetlab"
20     slicename = "inria_nepi"
21     plchost = "nepiplc.pl.sophia.inria.fr"
22     
23     host1 = "nepi1.pl.sophia.inria.fr"
24     host2 = "nepi2.pl.sophia.inria.fr"
25     host3 = "nepi3.pl.sophia.inria.fr"
26     host4 = "nepi5.pl.sophia.inria.fr"
27
28     def setUp(self):
29         self.root_dir = tempfile.mkdtemp()
30
31     def tearDown(self):
32         return
33         try:
34             shutil.rmtree(self.root_dir)
35         except:
36             # retry
37             time.sleep(0.1)
38             shutil.rmtree(self.root_dir)
39
40     def make_experiment_desc(self):
41         testbed_id = self.testbed_id
42         slicename = self.slicename
43         plchost = self.plchost
44         pl_ssh_key = os.environ.get(
45             "PL_SSH_KEY",
46             "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
47         pl_user, pl_pwd = test_util.pl_auth()
48
49         exp_desc = ExperimentDescription()
50         pl_provider = FactoriesProvider(testbed_id)
51         pl_desc = exp_desc.add_testbed_description(pl_provider)
52         pl_desc.set_attribute_value("homeDirectory", self.root_dir)
53         pl_desc.set_attribute_value("slice", slicename)
54         pl_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
55         pl_desc.set_attribute_value("authUser", pl_user)
56         pl_desc.set_attribute_value("authPass", pl_pwd)
57         pl_desc.set_attribute_value("plcHost", plchost)
58         
59         return pl_desc, exp_desc
60     
61     def _test_simple(self, daemonize_testbed, controller_access_configuration):
62         pl, exp = self.make_experiment_desc()
63         
64         node1 = pl.create("Node")
65         node2 = pl.create("Node")
66         node1.set_attribute_value("hostname", self.host1)
67         node2.set_attribute_value("hostname", self.host2)
68         iface1 = pl.create("NodeInterface")
69         iface2 = pl.create("NodeInterface")
70         iface2.set_attribute_value("label", "node2iface")
71         inet = pl.create("Internet")
72         node1.connector("devs").connect(iface1.connector("node"))
73         node2.connector("devs").connect(iface2.connector("node"))
74         iface1.connector("inet").connect(inet.connector("devs"))
75         iface2.connector("inet").connect(inet.connector("devs"))
76         app = pl.create("Application")
77         app.set_attribute_value("command", "ping -qc1 {#[node2iface].addr[0].[Address]#}")
78         app.enable_trace("stdout")
79         app.connector("node").connect(node1.connector("apps"))
80
81         if daemonize_testbed:
82             pl.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON)
83             inst_root_dir = os.path.join(self.root_dir, "instance")
84             os.mkdir(inst_root_dir)
85             pl.set_attribute_value(DC.ROOT_DIRECTORY, inst_root_dir)
86             pl.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL)
87
88         if controller_access_configuration:
89             controller = proxy.create_experiment_controller(xml, 
90                 controller_access_configuration)
91         else:
92             controller = ExperimentController(xml, self.root_dir)
93         
94         try:
95             controller.start()
96             while not controller.is_finished(app.guid):
97                 time.sleep(0.5)
98             ping_result = controller.trace(app.guid, "stdout")
99             comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
100
101 --- .* ping statistics ---
102 1 packets transmitted, 1 received, 0% packet loss, time \d*ms.*
103 """
104             self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
105                 "Unexpected trace:\n" + ping_result)
106         
107         finally:
108             controller.stop()
109             controller.shutdown()
110
111     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
112     def test_spanning_deployment(self):
113         pl, exp = self.make_experiment_desc()
114         
115         from nepi.testbeds import planetlab as plpackage
116         
117         nodes = [ pl.create("Node") for i in xrange(4) ]
118         ifaces = [ pl.create("NodeInterface") for node in nodes ]
119         inet = pl.create("Internet")
120         for node, iface in zip(nodes,ifaces):
121             node.connector("devs").connect(iface.connector("node"))
122             iface.connector("inet").connect(inet.connector("devs"))
123         
124         apps = []
125         for node in nodes:
126             app = pl.create("Application")
127             app.set_attribute_value("command", "./consts")
128             app.set_attribute_value("buildDepends", "gcc")
129             app.set_attribute_value("build", "gcc ${SOURCES}/consts.c -o consts")
130             app.set_attribute_value("install", "cp consts ${SOURCES}/consts")
131             app.set_attribute_value("sources", os.path.join(
132                 os.path.dirname(plpackage.__file__),'scripts','consts.c'))
133             app.enable_trace("stdout")
134             app.enable_trace("stderr")
135             app.enable_trace("buildlog")
136             node.connector("apps").connect(app.connector("node"))
137             apps.append(app)
138
139         comp_result = \
140 r""".*ETH_P_ALL = 0x[0-9a-fA-F]{8}
141 ETH_P_IP = 0x[0-9a-fA-F]{8}
142 TUNGETIFF = 0x[0-9a-fA-F]{8}
143 TUNSETIFF = 0x[0-9a-fA-F]{8}
144 IFF_NO_PI = 0x[0-9a-fA-F]{8}
145 IFF_TAP = 0x[0-9a-fA-F]{8}
146 IFF_TUN = 0x[0-9a-fA-F]{8}
147 IFF_VNET_HDR = 0x[0-9a-fA-F]{8}
148 TUN_PKT_STRIP = 0x[0-9a-fA-F]{8}
149 IFHWADDRLEN = 0x[0-9a-fA-F]{8}
150 IFNAMSIZ = 0x[0-9a-fA-F]{8}
151 IFREQ_SZ = 0x[0-9a-fA-F]{8}
152 FIONREAD = 0x[0-9a-fA-F]{8}.*
153 """
154
155         comp_build = r".*(Identity added|gcc).*"
156
157         xml = exp.to_xml()
158
159         controller = ExperimentController(xml, self.root_dir)
160         try:
161             controller.start()
162             while not all(controller.is_finished(app.guid) for app in apps):
163                 time.sleep(0.5)
164             
165             for app in apps:
166                 app_result = controller.trace(app.guid, "stdout") or ""
167                 self.assertTrue(re.match(comp_result, app_result, re.MULTILINE),
168                     "Unexpected trace:\n" + app_result)
169
170                 build_result = controller.trace(app.guid, "buildlog") or ""
171                 self.assertTrue(re.match(comp_build, build_result, re.MULTILINE | re.DOTALL),
172                     "Unexpected trace:\n" + build_result)
173         
174         finally:
175             controller.stop()
176             controller.shutdown()
177
178     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
179     def test_simple(self):
180         self._test_simple(
181             daemonize_testbed = False,
182             controller_access_configuration = None)
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_daemonized(self):
186         access_config = proxy.AccessConfiguration({
187             DC.DEPLOYMENT_MODE : DC.MODE_DAEMON,
188             DC.ROOT_DIRECTORY : self.root_dir,
189         })
190
191         self._test_simple(
192             daemonize_testbed = False,
193             controller_access_configuration = access_config)
194
195     @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
196     def test_simple_ssh(self):
197         env = test_util.test_environment()
198
199         access_config = proxy.AccessConfiguration({
200             DC.DEPLOYMENT_MODE : DC.MODE_DAEMON,
201             DC.ROOT_DIRECTORY : self.root_dir,
202             DC.LOG_LEVEL : DC.DEBUG_LEVEL,
203             DC.DEPLOYMENT_COMMUNICATION : DC.ACCESS_SSH,
204             DC.DEPLOYMENT_PORT : env.port,
205             DC.USE_AGENT : True,
206         })
207
208         self._test_simple(
209             daemonize_testbed = False,
210             controller_access_configuration = access_config)
211         
212
213 if __name__ == '__main__':
214     unittest.main()
215