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 version 2 as
8 # published by the Free Software Foundation;
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.
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/>.
18 # Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
20 from nepi.execution.ec import ExperimentController
22 from nepi.resources.planetlab.node import PlanetlabNode
23 from nepi.resources.planetlab.plcapi import PLCAPI, PLCAPIFactory
25 from test_utils import skipIfNotPLCredentials
30 import multiprocessing
32 class DummyEC(ExperimentController):
35 def create_node(ec, username, pl_user=None, pl_password=None, pl_url=None,
36 hostname=None, country=None, operatingSystem=None,
37 minBandwidth=None, minCpu=None,
38 architecture=None, city=None, ip=None):
40 node = ec.register_resource("planetlab::Node")
43 ec.set(node, "username", username)
45 ec.set(node, "pluser", pl_user)
47 ec.set(node, "plpassword", pl_password)
49 ec.set(node, "plcApiUrl", pl_url)
52 ec.set(node, "hostname", hostname)
54 ec.set(node, "country", country)
56 ec.set(node, "operatingSystem", operatingSystem)
58 iec.set(node, "minBandwidth", minBandwidth)
60 ec.set(node, "minCpu", minCpu)
62 ec.set(node, "architecture", architecture)
64 ec.set(node, "city", city)
66 ec.set(node, "ip", ip)
68 ec.set(node, "cleanExperiment", True)
69 ec.set(node, "cleanProcesses", True)
73 class PLNodeFactoryTestCase(unittest.TestCase):
75 def test_creation_phase(self):
76 self.assertEqual(PlanetlabNode._rtype, "planetlab::Node")
77 self.assertEqual(len(PlanetlabNode._attributes), 32)
79 class PLNodeTestCase(unittest.TestCase):
81 This tests use inria_nepi slice, from the test instance of MyPLC
82 nepiplc.pl.sophia.inria.fr. This test can fail if the user running
83 the test does not have a user in this instance of MyPLC or is not
84 added to the inria_nepi slice.
89 self.username = 'inria_nepi'
90 self.pl_user = os.environ.get("PL_USER")
91 self.pl_password = os.environ.get("PL_PASS")
92 self.pl_url = "nepiplc.pl.sophia.inria.fr"
93 commonapi=PLCAPIFactory.get_api(self.pl_user, self.pl_password,
95 commonapi.add_slice_nodes(self.username, ['nepi2.pl.sophia.inria.fr'])
96 commonapi._reserved = set()
97 commonapi._blacklist = set()
99 @skipIfNotPLCredentials
100 def test_plapi(self):
102 Check that the api to discover and reserve resources is well
103 instanciated, and is an instance of PLCAPI. Check that using
104 the same credentials, the same object of the api is used.
106 node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
107 pl_password=self.pl_password, pl_url=self.pl_url,
108 architecture="x86_64")
110 plnode_rm1 = self.ec.get_resource(node1)
111 hostname = plnode_rm1.get("hostname")
112 self.assertIsNone(hostname)
114 self.assertIsNone(plnode_rm1._node_to_provision)
116 api1 = plnode_rm1.plapi
117 self.assertIsInstance(api1, PLCAPI)
118 self.assertEqual(len(api1.reserved()), 0)
119 self.assertEqual(len(api1.blacklisted()), 0)
121 node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
122 pl_password=self.pl_password, pl_url=self.pl_url,
123 architecture="x86_64")
125 plnode_rm2 = self.ec.get_resource(node2)
126 api2 = plnode_rm2.plapi
127 self.assertEqual(api1, api2)
129 # Set hostname attribute in order for the shutdown method not to fail
130 plnode_rm1._set_hostname_attr(3)
131 plnode_rm2._set_hostname_attr(3)
133 def test_no_plcredentials(self):
135 Check that if no PL credentials are set, the PlanetlabNode skip the
136 discover and provision for the node.
138 node = create_node(self.ec, self.username, hostname='nepi2.pl.sophia.inria.fr')
139 plnode_rm = self.ec.get_resource(node)
141 plnode_rm.do_discover()
142 plnode_rm.do_provision()
144 self.assertIsNone(plnode_rm._node_to_provision)
146 @skipIfNotPLCredentials
147 def test_discover_inslice(self):
149 This test uses the fact that the node nepi2.pl.sophia.inria.fr is already in
150 the slice and match the constraints OS Fedora12 and arch x86_64.
151 Check nepi2.pl.sophia.inria.fr is alive if the test fails.
152 The node_id of nepi2.pl.sophia.inria.fr is 3.
154 node = create_node(self.ec, self.username, pl_user=self.pl_user,
155 pl_password=self.pl_password, pl_url=self.pl_url, architecture="x86_64",
156 operatingSystem="f12")
158 plnode_rm = self.ec.get_resource(node)
160 hostname = plnode_rm.get("hostname")
161 self.assertIsNone(hostname)
163 plnode_rm.do_discover()
164 self.assertEqual(plnode_rm._node_to_provision, 3)
166 # Set hostname attribute in order for the shutdown method not to fail
167 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
169 @skipIfNotPLCredentials
170 def test_discover_not_inslice(self):
172 This test checks that if the node is not in the slice, anyway the
173 discover method picks one that match constraints outside from the
176 node = create_node(self.ec, self.username, pl_user=self.pl_user,
177 pl_password=self.pl_password, pl_url=self.pl_url, country="France",
178 operatingSystem="f12")
180 plnode_rm = self.ec.get_resource(node)
181 plnode_rm.do_discover()
184 self.assertIn(plnode_rm._node_to_provision, result)
185 self.assertIsNot(plnode_rm.plapi.reserved(), set())
187 # Set hostname attribute in order for the shutdown method not to fail
188 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
190 @skipIfNotPLCredentials
191 def test_discover_hostname(self):
193 This test checks that if the user specify the hostname, only that node
196 node = create_node(self.ec, self.username, pl_user=self.pl_user,
197 pl_password=self.pl_password, pl_url=self.pl_url,
198 hostname="nepi2.pl.sophia.inria.fr")
200 plnode_rm = self.ec.get_resource(node)
201 plnode_rm.do_discover()
203 self.assertEqual(plnode_rm._node_to_provision, 3)
204 self.assertEqual(plnode_rm.plapi.reserved(), set([3]))
206 @skipIfNotPLCredentials
207 def test_discover_ip(self):
209 This test checks that if the user specify the ip, only that node
212 node = create_node(self.ec, self.username, pl_user=self.pl_user,
213 pl_password=self.pl_password, pl_url=self.pl_url,
216 plnode_rm = self.ec.get_resource(node)
217 plnode_rm.do_discover()
219 self.assertEqual(plnode_rm._node_to_provision, 3)
220 self.assertEqual(plnode_rm.plapi.reserved(), set([3]))
221 self.assertEqual(plnode_rm.get("hostname"), "nepi2.pl.sophia.inria.fr")
223 @skipIfNotPLCredentials
224 def test_discover_with_ranges(self):
226 Checks that defining max or min attributes, the discover method works.
228 node = create_node(self.ec, self.username, pl_user=self.pl_user,
229 pl_password=self.pl_password, pl_url=self.pl_url, minCpu=50)
231 plnode_rm = self.ec.get_resource(node)
232 plnode_rm.do_discover()
235 self.assertIn(plnode_rm._node_to_provision, result)
236 self.assertIsNot(plnode_rm.plapi.reserved(), set())
238 # Set hostname attribute in order for the shutdown method not to fail
239 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
241 @skipIfNotPLCredentials
242 def test_blacklist_nodes(self):
244 Test that if the node is malfunctioning it gets blacklisted, the node
245 nepi1.pl.sophia.inria.fr is used, if the test fails, check that the
246 result of the plcapi query is actually empty.
248 node = create_node(self.ec, self.username, pl_user=self.pl_user,
249 pl_password=self.pl_password, pl_url=self.pl_url,
250 hostname="nepi1.pl.sophia.inria.fr")
252 plnode_rm = self.ec.get_resource(node)
253 self.assertEqual(plnode_rm.plapi.blacklisted(), set())
255 # check that the node is actually malfunctioning
256 api = plnode_rm.plapi
257 filters = {'boot_state': 'boot', 'node_type': 'regular',
258 'hostname': 'nepi1.pl.sophia.inria.fr', 'run_level': 'boot',
259 '>last_contact': int(time.time()) - 2*3600}
260 node_id = api.get_nodes(filters, fields=['node_id'])
263 with self.assertRaises(RuntimeError):
264 plnode_rm.do_discover()
265 self.assertEqual(plnode_rm.plapi.blacklisted(), set([1]))
267 @skipIfNotPLCredentials
268 def test_provision_node_inslice(self):
270 Check provision of the node nepi2.pl.sophia.inria.fr.
272 node = create_node(self.ec, self.username, pl_user=self.pl_user,
273 pl_password=self.pl_password, pl_url=self.pl_url,
274 architecture="x86_64", operatingSystem="f12")
276 plnode_rm = self.ec.get_resource(node)
277 self.assertEqual(len(plnode_rm.plapi.blacklisted()), 0)
278 self.assertEqual(len(plnode_rm.plapi.reserved()), 0)
280 plnode_rm.do_discover()
281 plnode_rm.do_provision()
282 ip = plnode_rm.get("ip")
283 self.assertEqual(ip, "138.96.116.32")
284 self.assertEqual(len(plnode_rm.plapi.reserved()), 1)
286 @skipIfNotPLCredentials
287 def test_provision_node_not_inslice(self):
289 Check provision of one of the nodes f12, nodes:
290 'nepi3.pl.sophia.inria.fr'
291 'nepi5.pl.sophia.inria.fr'
293 node = create_node(self.ec, self.username, pl_user=self.pl_user,
294 pl_password=self.pl_password, pl_url=self.pl_url, operatingSystem="f12",
297 plnode_rm = self.ec.get_resource(node)
298 self.assertEqual(plnode_rm.plapi.blacklisted(), set())
299 self.assertEqual(plnode_rm.plapi.reserved(), set())
301 plnode_rm.do_discover()
302 plnode_rm.do_provision()
303 ip = plnode_rm.get("ip")
305 result = ["138.96.116.33","138.96.116.35"]
306 self.assertIn(ip, result)
308 @skipIfNotPLCredentials
309 def test_provision_more_than_available(self):
311 Check that if the user wants to provision 3 nodes in Paris, he
312 gets RuntimeError, there are only 2 nodes with city=Paris.
314 node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
315 pl_password=self.pl_password, pl_url=self.pl_url,
316 city="Paris", operatingSystem="f12")
318 plnode_rm1 = self.ec.get_resource(node1)
319 plnode_rm1.do_discover()
320 plnode_rm1.do_provision()
322 node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
323 pl_password=self.pl_password, pl_url=self.pl_url,
324 city="Paris", operatingSystem="f12")
326 plnode_rm2 = self.ec.get_resource(node2)
327 plnode_rm2.do_discover()
328 plnode_rm2.do_provision()
330 node3 = create_node(self.ec, self.username, pl_user=self.pl_user,
331 pl_password=self.pl_password, pl_url=self.pl_url,
332 city="Paris", operatingSystem="f12")
334 plnode_rm3 = self.ec.get_resource(node3)
335 with self.assertRaises(RuntimeError):
336 plnode_rm3.do_discover()
337 with self.assertRaises(RuntimeError):
338 plnode_rm3.do_provision()
340 host1 = plnode_rm1.get('hostname')
342 plnode_rm3._set_hostname_attr(host1)
344 @skipIfNotPLCredentials
345 def test_concurrence(self):
347 Test with the nodes being discover and provision at the same time.
348 The deploy should fail as the test before, there aren't 4 nodes of
349 that carachteristics.
351 node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
352 pl_password=self.pl_password, pl_url=self.pl_url,
353 architecture="x86_64", operatingSystem="f12")
355 node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
356 pl_password=self.pl_password, pl_url=self.pl_url,
357 architecture="x86_64", operatingSystem="f12")
359 node3 = create_node(self.ec, self.username, pl_user=self.pl_user,
360 pl_password=self.pl_password, pl_url=self.pl_url,
361 architecture="x86_64", operatingSystem="f12")
363 node4 = create_node(self.ec, self.username, pl_user=self.pl_user,
364 pl_password=self.pl_password, pl_url=self.pl_url,
365 architecture="x86_64", operatingSystem="f12")
368 self.ec.wait_deployed([node1, node2, node3, node4])
369 failure_level = self.ec._fm._failure_level
370 self.assertEqual(failure_level, 2)
376 if __name__ == '__main__':