2 # -*- coding: utf-8 -*-
6 from nepi.core.design import ExperimentDescription, FactoriesProvider
7 from nepi.core.execute import ExperimentController
8 from nepi.util import proxy
9 from nepi.util.constants import DeploymentConfiguration as DC
19 class PlanetLabIntegrationTestCase(unittest.TestCase):
20 testbed_id = "planetlab"
21 slicename = "inria_nepi"
22 slicehrn = "nepi.inria.nepi"
23 plchost = "nepiplc.pl.sophia.inria.fr"
25 host1 = "nepi1.pl.sophia.inria.fr"
26 host2 = "nepi2.pl.sophia.inria.fr"
27 host3 = "nepi3.pl.sophia.inria.fr"
28 host4 = "nepi5.pl.sophia.inria.fr"
30 port_base = 2000 + (os.getpid() % 1000) * 13
33 self.root_dir = tempfile.mkdtemp()
34 self.__class__.port_base = self.port_base + 100
38 shutil.rmtree(self.root_dir)
42 shutil.rmtree(self.root_dir)
44 def make_experiment_desc(self, use_sfa = False):
45 testbed_id = self.testbed_id
46 slicename = self.slicename
47 plchost = self.plchost
48 pl_ssh_key = os.environ.get(
50 "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
51 pl_user, pl_pwd = test_util.pl_auth()
53 exp_desc = ExperimentDescription()
54 pl_provider = FactoriesProvider(testbed_id)
55 pl_desc = exp_desc.add_testbed_description(pl_provider)
56 pl_desc.set_attribute_value("homeDirectory", self.root_dir)
57 pl_desc.set_attribute_value("slice", slicename)
58 pl_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
59 pl_desc.set_attribute_value("authUser", pl_user)
60 pl_desc.set_attribute_value("authPass", pl_pwd)
61 pl_desc.set_attribute_value("plcHost", plchost)
62 pl_desc.set_attribute_value("tapPortBase", self.port_base)
63 pl_desc.set_attribute_value("p2pDeployment", False) # it's interactive, we don't want it in tests
64 pl_desc.set_attribute_value("dedicatedSlice", True)
65 pl_desc.set_attribute_value("plLogLevel", "DEBUG")
67 pl_desc.set_attribute_value("sfa", True)
68 pl_desc.set_attribute_value("sliceHrn", self.slicehrn)
70 return pl_desc, exp_desc
72 def _test_simple(self, daemonize_testbed, controller_access_configuration,
73 environ = None, use_sfa = False):
74 pl, exp = self.make_experiment_desc(use_sfa)
76 node1 = pl.create("Node")
77 node2 = pl.create("Node")
78 node1.set_attribute_value("hostname", self.host1)
79 node2.set_attribute_value("hostname", self.host2)
80 iface1 = pl.create("NodeInterface")
81 iface2 = pl.create("NodeInterface")
82 iface2.set_attribute_value("label", "node2iface")
83 inet = pl.create("Internet")
84 node1.connector("devs").connect(iface1.connector("node"))
85 node2.connector("devs").connect(iface2.connector("node"))
86 iface1.connector("inet").connect(inet.connector("devs"))
87 iface2.connector("inet").connect(inet.connector("devs"))
88 app = pl.create("Application")
89 app.set_attribute_value("command", "ping -qc1 {#[node2iface].addr[0].[Address]#}")
90 app.enable_trace("stdout")
91 app.connector("node").connect(node1.connector("apps"))
94 pl.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON)
95 inst_root_dir = os.path.join(self.root_dir, "instance")
96 os.mkdir(inst_root_dir)
97 pl.set_attribute_value(DC.ROOT_DIRECTORY, inst_root_dir)
98 pl.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL)
101 pl.set_attribute_value(DC.DEPLOYMENT_ENVIRONMENT_SETUP, environ)
105 if controller_access_configuration:
106 controller = proxy.create_experiment_controller(xml,
107 controller_access_configuration)
109 controller = ExperimentController(xml, self.root_dir)
113 while not controller.is_finished(app.guid):
115 ping_result = controller.trace(app.guid, "stdout")
116 comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
118 --- .* ping statistics ---
119 1 packets transmitted, 1 received, 0% packet loss, time \d*ms.*
121 self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
122 "Unexpected trace:\n" + ping_result)
129 traceback.print_exc()
131 controller.shutdown()
134 traceback.print_exc()
136 def _test_spanning_deployment(self, use_sfa = False):
137 pl, exp = self.make_experiment_desc(use_sfa)
139 pl.set_attribute_value("p2pDeployment", True) # we do want it here - even if interactive
141 from nepi.testbeds import planetlab as plpackage
143 nodes = [ pl.create("Node") for i in xrange(4) ]
144 ifaces = [ pl.create("NodeInterface") for node in nodes ]
145 inet = pl.create("Internet")
146 for node, iface in zip(nodes,ifaces):
147 node.connector("devs").connect(iface.connector("node"))
148 iface.connector("inet").connect(inet.connector("devs"))
152 app = pl.create("Application")
153 app.set_attribute_value("command", "./consts")
154 app.set_attribute_value("buildDepends", "gcc")
155 app.set_attribute_value("build", "gcc ${SOURCES}/consts.c -o consts")
156 app.set_attribute_value("install", "cp consts ${SOURCES}/consts")
157 app.set_attribute_value("sources", os.path.join(
158 os.path.dirname(plpackage.__file__),'scripts','consts.c'))
159 app.enable_trace("stdout")
160 app.enable_trace("stderr")
161 app.enable_trace("buildlog")
162 node.connector("apps").connect(app.connector("node"))
166 r""".*ETH_P_ALL = 0x[0-9a-fA-F]{8}
167 ETH_P_IP = 0x[0-9a-fA-F]{8}
168 TUNGETIFF = 0x[0-9a-fA-F]{8}
169 TUNSETIFF = 0x[0-9a-fA-F]{8}
170 IFF_NO_PI = 0x[0-9a-fA-F]{8}
171 IFF_TAP = 0x[0-9a-fA-F]{8}
172 IFF_TUN = 0x[0-9a-fA-F]{8}
173 IFF_VNET_HDR = 0x[0-9a-fA-F]{8}
174 TUN_PKT_STRIP = 0x[0-9a-fA-F]{8}
175 IFHWADDRLEN = 0x[0-9a-fA-F]{8}
176 IFNAMSIZ = 0x[0-9a-fA-F]{8}
177 IFREQ_SZ = 0x[0-9a-fA-F]{8}
178 FIONREAD = 0x[0-9a-fA-F]{8}.*
181 comp_build = r".*(Identity added|gcc).*"
185 controller = ExperimentController(xml, self.root_dir)
188 while not all(controller.is_finished(app.guid) for app in apps):
192 app_result = controller.trace(app.guid, "stdout") or ""
193 self.assertTrue(re.match(comp_result, app_result, re.MULTILINE),
194 "Unexpected trace:\n" + app_result)
196 build_result = controller.trace(app.guid, "buildlog") or ""
197 self.assertTrue(re.match(comp_build, build_result, re.MULTILINE | re.DOTALL),
198 "Unexpected trace:\n" + build_result)
205 traceback.print_exc()
207 controller.shutdown()
210 traceback.print_exc()
212 def _test_recover(self, daemonize_testbed, controller_access_configuration,
213 environ = None, use_sfa = False):
214 pl, exp = self.make_experiment_desc(use_sfa)
216 pl.set_attribute_value(DC.RECOVERY_POLICY, DC.POLICY_RECOVER)
218 node1 = pl.create("Node")
219 node2 = pl.create("Node")
220 node1.set_attribute_value("hostname", self.host1)
221 node2.set_attribute_value("hostname", self.host2)
223 iface1 = pl.create("NodeInterface")
224 iface2 = pl.create("NodeInterface")
225 inet = pl.create("Internet")
226 node1.connector("devs").connect(iface1.connector("node"))
227 node2.connector("devs").connect(iface2.connector("node"))
228 iface1.connector("inet").connect(inet.connector("devs"))
229 iface2.connector("inet").connect(inet.connector("devs"))
231 tap1 = pl.create("TapInterface")
232 tap2 = pl.create("TapInterface")
233 node1.connector("devs").connect(tap1.connector("node"))
234 node2.connector("devs").connect(tap2.connector("node"))
235 tap1.connector("udp").connect(tap2.connector("udp"))
237 tap1ip = tap1.add_address()
238 tap1ip.set_attribute_value("Address", "192.168.2.2")
239 tap1ip.set_attribute_value("NetPrefix", 24)
240 tap1ip.set_attribute_value("Broadcast", False)
242 tap2ip = tap2.add_address()
243 tap2ip.set_attribute_value("Address", "192.168.2.3")
244 tap2ip.set_attribute_value("NetPrefix", 24)
245 tap2ip.set_attribute_value("Broadcast", False)
247 app = pl.create("Application")
248 app.set_attribute_value("command", "ping -qc10 192.168.2.3")
249 app.enable_trace("stdout")
250 app.connector("node").connect(node1.connector("apps"))
252 if daemonize_testbed:
253 pl.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON)
254 inst_root_dir = os.path.join(self.root_dir, "instance")
255 os.mkdir(inst_root_dir)
256 pl.set_attribute_value(DC.ROOT_DIRECTORY, inst_root_dir)
257 pl.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL)
260 pl.set_attribute_value(DC.DEPLOYMENT_ENVIRONMENT_SETUP, environ)
264 if controller_access_configuration:
265 controller = proxy.create_experiment_controller(xml,
266 controller_access_configuration)
268 controller = ExperimentController(xml, self.root_dir)
273 # purposedly break connection
277 if controller_access_configuration:
278 controller_access_configuration.set_attribute_value(
280 controller = proxy.create_experiment_controller(None,
281 controller_access_configuration)
283 controller = ExperimentController(None, self.root_dir)
286 while not controller.is_finished(app.guid):
288 ping_result = controller.trace(app.guid, "stdout")
289 comp_result = r"""PING .* \(.*\) \d*\(\d*\) bytes of data.
291 --- .* ping statistics ---
292 10 packets transmitted, 10 received, 0% packet loss, time \d*ms.*
294 self.assertTrue(re.match(comp_result, ping_result, re.MULTILINE),
295 "Unexpected trace:\n" + ping_result)
298 if controller is not None:
303 traceback.print_exc()
305 controller.shutdown()
308 traceback.print_exc()
310 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
311 def test_simple(self):
313 daemonize_testbed = False,
314 controller_access_configuration = None)
316 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
317 def test_simple_sfa(self):
319 daemonize_testbed = False,
320 controller_access_configuration = None,
323 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
324 @test_util.skipUnless(os.environ.get('NEPI_FULL_TESTS','').lower() in ('1','yes','true','on'),
325 "Test is interactive, requires NEPI_FULL_TESTS=yes")
326 def test_spanning_deployment(self):
327 self._test_spanning_deployment()
329 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
330 @test_util.skipUnless(os.environ.get('NEPI_FULL_TESTS','').lower() in ('1','yes','true','on'),
331 "Test is interactive, requires NEPI_FULL_TESTS=yes")
332 def test_spanning_deployment_sfa(self):
333 self._test_spanning_deployment(use_sfa = True)
335 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
336 def test_simple_daemonized(self):
337 access_config = proxy.AccessConfiguration({
338 DC.DEPLOYMENT_MODE : DC.MODE_DAEMON,
339 DC.ROOT_DIRECTORY : self.root_dir,
340 DC.LOG_LEVEL : DC.DEBUG_LEVEL,
344 daemonize_testbed = False,
345 controller_access_configuration = access_config)
347 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
348 def test_simple_daemonized_sfa(self):
349 access_config = proxy.AccessConfiguration({
350 DC.DEPLOYMENT_MODE : DC.MODE_DAEMON,
351 DC.ROOT_DIRECTORY : self.root_dir,
352 DC.LOG_LEVEL : DC.DEBUG_LEVEL,
356 daemonize_testbed = False,
357 controller_access_configuration = access_config,
360 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
361 def test_z_simple_ssh(self): # _z_ cause we want it last - it messes up the process :(
362 # Recreate environment
363 environ = ' ; '.join( map("export %s=%r".__mod__, os.environ.iteritems()) )
365 env = test_util.test_environment()
367 access_config = proxy.AccessConfiguration({
368 DC.DEPLOYMENT_MODE : DC.MODE_DAEMON,
369 DC.ROOT_DIRECTORY : self.root_dir,
370 DC.LOG_LEVEL : DC.DEBUG_LEVEL,
371 DC.DEPLOYMENT_COMMUNICATION : DC.ACCESS_SSH,
372 DC.DEPLOYMENT_PORT : env.port,
374 DC.DEPLOYMENT_ENVIRONMENT_SETUP : environ,
378 daemonize_testbed = False,
379 controller_access_configuration = access_config,
382 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
383 def test_recover(self):
385 daemonize_testbed = False,
386 controller_access_configuration = None)
388 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
389 def test_recover_sfa(self):
391 daemonize_testbed = False,
392 controller_access_configuration = None,
395 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
396 def test_recover_daemonized(self):
397 access_config = proxy.AccessConfiguration({
398 DC.DEPLOYMENT_MODE : DC.MODE_DAEMON,
399 DC.ROOT_DIRECTORY : self.root_dir,
400 DC.LOG_LEVEL : DC.DEBUG_LEVEL,
404 daemonize_testbed = False,
405 controller_access_configuration = access_config)
407 @test_util.skipUnless(test_util.pl_auth() is not None, "Test requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)")
408 def test_recover_daemonized_sfa(self):
409 access_config = proxy.AccessConfiguration({
410 DC.DEPLOYMENT_MODE : DC.MODE_DAEMON,
411 DC.ROOT_DIRECTORY : self.root_dir,
412 DC.LOG_LEVEL : DC.DEBUG_LEVEL,
416 daemonize_testbed = False,
417 controller_access_configuration = access_config,
421 if __name__ == '__main__':