3 # NEPI, a framework to manage network experiments
4 # Copyright (C) 2013 INRIA
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
21 from nepi.execution.ec import ExperimentController
23 from nepi.resources.planetlab.node import PlanetlabNode
24 from nepi.resources.planetlab.plcapi import PLCAPI, PLCAPIFactory
26 from test_utils import skipIfNotPLCredentials
31 import multiprocessing
33 class DummyEC(ExperimentController):
36 def create_node(ec, username, pl_user=None, pl_password=None, pl_url=None,
37 hostname=None, country=None, operatingSystem=None,
38 minBandwidth=None, minCpu=None,
39 architecture=None, city=None, ip=None):
41 node = ec.register_resource("PlanetlabNode")
44 ec.set(node, "username", username)
46 ec.set(node, "pluser", pl_user)
48 ec.set(node, "plpassword", pl_password)
50 ec.set(node, "plcApiUrl", pl_url)
53 ec.set(node, "hostname", hostname)
55 ec.set(node, "country", country)
57 ec.set(node, "operatingSystem", operatingSystem)
59 iec.set(node, "minBandwidth", minBandwidth)
61 ec.set(node, "minCpu", minCpu)
63 ec.set(node, "architecture", architecture)
65 ec.set(node, "city", city)
67 ec.set(node, "ip", ip)
69 ec.set(node, "cleanHome", True)
70 ec.set(node, "cleanProcesses", True)
74 class PLNodeFactoryTestCase(unittest.TestCase):
76 def test_creation_phase(self):
77 self.assertEquals(PlanetlabNode._rtype, "PlanetlabNode")
78 self.assertEquals(len(PlanetlabNode._attributes), 32)
80 class PLNodeTestCase(unittest.TestCase):
82 This tests use inria_nepi slice, from the test instance of MyPLC
83 nepiplc.pl.sophia.inria.fr. This test can fail if the user running
84 the test does not have a user in this instance of MyPLC or is not
85 added to the inria_nepi slice.
90 self.username = 'inria_nepi'
91 self.pl_user = os.environ.get("PL_USER")
92 self.pl_password = os.environ.get("PL_PASS")
93 self.pl_url = "nepiplc.pl.sophia.inria.fr"
94 commonapi=PLCAPIFactory.get_api(self.pl_user, self.pl_password,
96 commonapi.add_slice_nodes(self.username, ['nepi2.pl.sophia.inria.fr'])
97 commonapi._reserved = set()
98 commonapi._blacklist = set()
100 @skipIfNotPLCredentials
101 def test_plapi(self):
103 Check that the api to discover and reserve resources is well
104 instanciated, and is an instance of PLCAPI. Check that using
105 the same credentials, the same object of the api is used.
107 node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
108 pl_password=self.pl_password, pl_url=self.pl_url,
109 architecture="x86_64")
111 plnode_rm1 = self.ec.get_resource(node1)
112 hostname = plnode_rm1.get("hostname")
113 self.assertIsNone(hostname)
115 self.assertIsNone(plnode_rm1._node_to_provision)
117 api1 = plnode_rm1.plapi
118 self.assertIsInstance(api1, PLCAPI)
119 self.assertEquals(len(api1.reserved()), 0)
120 self.assertEquals(len(api1.blacklisted()), 0)
122 node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
123 pl_password=self.pl_password, pl_url=self.pl_url,
124 architecture="x86_64")
126 plnode_rm2 = self.ec.get_resource(node2)
127 api2 = plnode_rm2.plapi
128 self.assertEquals(api1, api2)
130 # Set hostname attribute in order for the shutdown method not to fail
131 plnode_rm1._set_hostname_attr(3)
132 plnode_rm2._set_hostname_attr(3)
134 def test_no_plcredentials(self):
136 Check that if no PL credentials are set, the PlanetlabNode skip the
137 discover and provision for the node.
139 node = create_node(self.ec, self.username, hostname='nepi2.pl.sophia.inria.fr')
140 plnode_rm = self.ec.get_resource(node)
142 plnode_rm.do_discover()
143 plnode_rm.do_provision()
145 self.assertIsNone(plnode_rm._node_to_provision)
147 @skipIfNotPLCredentials
148 def test_discover_inslice(self):
150 This test uses the fact that the node nepi2.pl.sophia.inria.fr is already in
151 the slice and match the constraints OS Fedora12 and arch x86_64.
152 Check nepi2.pl.sophia.inria.fr is alive if the test fails.
153 The node_id of nepi2.pl.sophia.inria.fr is 3.
155 node = create_node(self.ec, self.username, pl_user=self.pl_user,
156 pl_password=self.pl_password, pl_url=self.pl_url, architecture="x86_64",
157 operatingSystem="f12")
159 plnode_rm = self.ec.get_resource(node)
161 hostname = plnode_rm.get("hostname")
162 self.assertIsNone(hostname)
164 plnode_rm.do_discover()
165 self.assertEquals(plnode_rm._node_to_provision, 3)
167 # Set hostname attribute in order for the shutdown method not to fail
168 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
170 @skipIfNotPLCredentials
171 def test_discover_not_inslice(self):
173 This test checks that if the node is not in the slice, anyway the
174 discover method picks one that match constraints outside from the
177 node = create_node(self.ec, self.username, pl_user=self.pl_user,
178 pl_password=self.pl_password, pl_url=self.pl_url, country="France",
179 operatingSystem="f12")
181 plnode_rm = self.ec.get_resource(node)
182 plnode_rm.do_discover()
185 self.assertIn(plnode_rm._node_to_provision, result)
186 self.assertIsNot(plnode_rm.plapi.reserved(), set())
188 # Set hostname attribute in order for the shutdown method not to fail
189 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
191 @skipIfNotPLCredentials
192 def test_discover_hostname(self):
194 This test checks that if the user specify the hostname, only that node
197 node = create_node(self.ec, self.username, pl_user=self.pl_user,
198 pl_password=self.pl_password, pl_url=self.pl_url,
199 hostname="nepi2.pl.sophia.inria.fr")
201 plnode_rm = self.ec.get_resource(node)
202 plnode_rm.do_discover()
204 self.assertEquals(plnode_rm._node_to_provision, 3)
205 self.assertEquals(plnode_rm.plapi.reserved(), set([3]))
207 @skipIfNotPLCredentials
208 def test_discover_ip(self):
210 This test checks that if the user specify the ip, only that node
213 node = create_node(self.ec, self.username, pl_user=self.pl_user,
214 pl_password=self.pl_password, pl_url=self.pl_url,
217 plnode_rm = self.ec.get_resource(node)
218 plnode_rm.do_discover()
220 self.assertEquals(plnode_rm._node_to_provision, 3)
221 self.assertEquals(plnode_rm.plapi.reserved(), set([3]))
222 self.assertEquals(plnode_rm.get("hostname"), "nepi2.pl.sophia.inria.fr")
224 @skipIfNotPLCredentials
225 def test_discover_with_ranges(self):
227 Checks that defining max or min attributes, the discover method works.
229 node = create_node(self.ec, self.username, pl_user=self.pl_user,
230 pl_password=self.pl_password, pl_url=self.pl_url, minCpu=50)
232 plnode_rm = self.ec.get_resource(node)
233 plnode_rm.do_discover()
236 self.assertIn(plnode_rm._node_to_provision, result)
237 self.assertIsNot(plnode_rm.plapi.reserved(), set())
239 # Set hostname attribute in order for the shutdown method not to fail
240 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
242 @skipIfNotPLCredentials
243 def test_blacklist_nodes(self):
245 Test that if the node is malfunctioning it gets blacklisted, the node
246 nepi1.pl.sophia.inria.fr is used, if the test fails, check that the
247 result of the plcapi query is actually empty.
249 node = create_node(self.ec, self.username, pl_user=self.pl_user,
250 pl_password=self.pl_password, pl_url=self.pl_url,
251 hostname="nepi1.pl.sophia.inria.fr")
253 plnode_rm = self.ec.get_resource(node)
254 self.assertEquals(plnode_rm.plapi.blacklisted(), set())
256 # check that the node is actually malfunctioning
257 api = plnode_rm.plapi
258 filters = {'boot_state': 'boot', 'node_type': 'regular',
259 'hostname': 'nepi1.pl.sophia.inria.fr', 'run_level': 'boot',
260 '>last_contact': int(time.time()) - 2*3600}
261 node_id = api.get_nodes(filters, fields=['node_id'])
264 with self.assertRaises(RuntimeError):
265 plnode_rm.do_discover()
266 self.assertEquals(plnode_rm.plapi.blacklisted(), set([1]))
268 @skipIfNotPLCredentials
269 def test_provision_node_inslice(self):
271 Check provision of the node nepi2.pl.sophia.inria.fr.
273 node = create_node(self.ec, self.username, pl_user=self.pl_user,
274 pl_password=self.pl_password, pl_url=self.pl_url,
275 architecture="x86_64", operatingSystem="f12")
277 plnode_rm = self.ec.get_resource(node)
278 self.assertEquals(len(plnode_rm.plapi.blacklisted()), 0)
279 self.assertEquals(len(plnode_rm.plapi.reserved()), 0)
281 plnode_rm.do_discover()
282 plnode_rm.do_provision()
283 ip = plnode_rm.get("ip")
284 self.assertEquals(ip, "138.96.116.32")
285 self.assertEquals(len(plnode_rm.plapi.reserved()), 1)
287 @skipIfNotPLCredentials
288 def test_provision_node_not_inslice(self):
290 Check provision of one of the nodes f12, nodes:
291 'nepi3.pl.sophia.inria.fr'
292 'nepi5.pl.sophia.inria.fr'
294 node = create_node(self.ec, self.username, pl_user=self.pl_user,
295 pl_password=self.pl_password, pl_url=self.pl_url, operatingSystem="f12",
298 plnode_rm = self.ec.get_resource(node)
299 self.assertEquals(plnode_rm.plapi.blacklisted(), set())
300 self.assertEquals(plnode_rm.plapi.reserved(), set())
302 plnode_rm.do_discover()
303 plnode_rm.do_provision()
304 ip = plnode_rm.get("ip")
306 result = ["138.96.116.33","138.96.116.35"]
307 self.assertIn(ip, result)
309 @skipIfNotPLCredentials
310 def test_provision_more_than_available(self):
312 Check that if the user wants to provision 3 nodes in Paris, he
313 gets RuntimeError, there are only 2 nodes with city=Paris.
315 node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
316 pl_password=self.pl_password, pl_url=self.pl_url,
317 city="Paris", operatingSystem="f12")
319 plnode_rm1 = self.ec.get_resource(node1)
320 plnode_rm1.do_discover()
321 plnode_rm1.do_provision()
323 node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
324 pl_password=self.pl_password, pl_url=self.pl_url,
325 city="Paris", operatingSystem="f12")
327 plnode_rm2 = self.ec.get_resource(node2)
328 plnode_rm2.do_discover()
329 plnode_rm2.do_provision()
331 node3 = create_node(self.ec, self.username, pl_user=self.pl_user,
332 pl_password=self.pl_password, pl_url=self.pl_url,
333 city="Paris", operatingSystem="f12")
335 plnode_rm3 = self.ec.get_resource(node3)
336 with self.assertRaises(RuntimeError):
337 plnode_rm3.do_discover()
338 with self.assertRaises(RuntimeError):
339 plnode_rm3.do_provision()
341 host1 = plnode_rm1.get('hostname')
343 plnode_rm3._set_hostname_attr(host1)
345 @skipIfNotPLCredentials
346 def test_concurrence(self):
348 Test with the nodes being discover and provision at the same time.
349 The deploy should fail as the test before, there aren't 4 nodes of
350 that carachteristics.
352 node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
353 pl_password=self.pl_password, pl_url=self.pl_url,
354 architecture="x86_64", operatingSystem="f12")
356 node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
357 pl_password=self.pl_password, pl_url=self.pl_url,
358 architecture="x86_64", operatingSystem="f12")
360 node3 = create_node(self.ec, self.username, pl_user=self.pl_user,
361 pl_password=self.pl_password, pl_url=self.pl_url,
362 architecture="x86_64", operatingSystem="f12")
364 node4 = create_node(self.ec, self.username, pl_user=self.pl_user,
365 pl_password=self.pl_password, pl_url=self.pl_url,
366 architecture="x86_64", operatingSystem="f12")
369 self.ec.wait_deployed([node1, node2, node3, node4])
370 failure_level = self.ec._fm._failure_level
371 self.assertEqual(failure_level, 2)
377 if __name__ == '__main__':