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):
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, "cleanHome", True)
68 ec.set(node, "cleanProcesses", True)
72 class PLNodeFactoryTestCase(unittest.TestCase):
74 def test_creation_phase(self):
75 self.assertEquals(PlanetlabNode._rtype, "PlanetlabNode")
76 self.assertEquals(len(PlanetlabNode._attributes), 30)
78 class PLNodeTestCase(unittest.TestCase):
80 This tests use inria_nepi slice, and already added to
81 the slice, and ONLY this one in order for the test not to fail.
86 self.username = 'inria_nepi'
87 self.pl_user = os.environ.get("PL_USER")
88 self.pl_password = os.environ.get("PL_PASS")
89 self.pl_url = "nepiplc.pl.sophia.inria.fr"
91 @skipIfNotPLCredentials
94 Check that the api to discover and reserve resources is well
95 instanciated, and is an instance of PLCAPI. Ignore error while
96 executing the ec.shutdown method, the error is due to the name
97 of the host not being defined yet for this test.
99 node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
100 pl_password=self.pl_password, pl_url=self.pl_url,
101 architecture="x86_64")
103 plnode_rm1 = self.ec.get_resource(node1)
104 hostname = plnode_rm1.get("hostname")
105 self.assertIsNone(hostname)
107 self.assertIsNone(plnode_rm1._node_to_provision)
109 api1 = plnode_rm1.plapi
110 self.assertIsInstance(api1, PLCAPI)
111 self.assertEquals(len(api1.reserved()), 0)
112 self.assertEquals(len(api1.blacklisted()), 0)
114 node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
115 pl_password=self.pl_password, pl_url=self.pl_url,
116 architecture="x86_64")
118 plnode_rm2 = self.ec.get_resource(node2)
119 api2 = plnode_rm2.plapi
120 self.assertEquals(api1, api2)
122 # Set hostname attribute in order for the shutdown method not to fail
123 plnode_rm1._set_hostname_attr(3)
124 plnode_rm2._set_hostname_attr(3)
126 def test_no_plcredentials(self):
128 Check that if no PL credentials are set, the PlanetlabNode skip the
129 discover and provision for the node.
131 node = create_node(self.ec, self.username, hostname='nepi2.pl.sophia.inria.fr')
132 plnode_rm = self.ec.get_resource(node)
134 plnode_rm.do_discover()
135 plnode_rm.do_provision()
137 self.assertIsNone(plnode_rm._node_to_provision)
139 @skipIfNotPLCredentials
140 def test_discover_inslice(self):
142 This test uses the fact that the node nepi2.pl.sophia.inria.fr is already in
143 the slice and match the constraints OS Fedora12 and arch x86_64.
144 Check nepi2.pl.sophia.inria.fr is alive if the test fails.
146 node = create_node(self.ec, self.username, pl_user=self.pl_user,
147 pl_password=self.pl_password, pl_url=self.pl_url, architecture="x86_64",
148 operatingSystem="f12")
150 plnode_rm = self.ec.get_resource(node)
152 hostname = plnode_rm.get("hostname")
153 self.assertIsNone(hostname)
155 api = plnode_rm.plapi
156 api.add_slice_nodes(self.username, ['nepi2.pl.sophia.inria.fr'])
158 plnode_rm.do_discover()
159 self.assertEquals(plnode_rm._node_to_provision, 3)
161 # Set hostname attribute in order for the shutdown method not to fail
162 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
164 @skipIfNotPLCredentials
165 def test_discover_not_inslice(self):
167 This test checks that if the node is not in the slice, anyway the
168 discover method picks one that match constraints outside from the
171 node = create_node(self.ec, self.username, pl_user=self.pl_user,
172 pl_password=self.pl_password, pl_url=self.pl_url, country="France",
173 operatingSystem="f12")
175 plnode_rm = self.ec.get_resource(node)
176 plnode_rm.do_discover()
179 self.assertIn(plnode_rm._node_to_provision, result)
180 self.assertIsNot(plnode_rm.plapi.reserved(), set())
182 # Set hostname attribute in order for the shutdown method not to fail
183 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
185 @skipIfNotPLCredentials
186 def test_discover_hostname(self):
188 This test checks that if the user specify the hostname, only that node
191 node = create_node(self.ec, self.username, pl_user=self.pl_user,
192 pl_password=self.pl_password, pl_url=self.pl_url,
193 hostname="nepi2.pl.sophia.inria.fr")
195 plnode_rm = self.ec.get_resource(node)
196 plnode_rm.do_discover()
198 self.assertEquals(plnode_rm._node_to_provision, 3)
199 self.assertEquals(plnode_rm.plapi.reserved(), set([3]))
201 @skipIfNotPLCredentials
202 def test_discover_with_ranges(self):
204 Checks that defining max or min attributes, the discover method works.
206 node = create_node(self.ec, self.username, pl_user=self.pl_user,
207 pl_password=self.pl_password, pl_url=self.pl_url, minCpu=50)
209 plnode_rm = self.ec.get_resource(node)
210 plnode_rm.do_discover()
213 self.assertIn(plnode_rm._node_to_provision, result)
214 self.assertIsNot(plnode_rm.plapi.reserved(), set())
216 # Set hostname attribute in order for the shutdown method not to fail
217 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
219 @skipIfNotPLCredentials
220 def test_blacklist_nodes(self):
222 Test that if the node is malfunctioning it gets blacklisted, the node
223 nepi1.pl.sophia.inria.fr is used, if the test fails, check that the
224 result of the plcapi query is actually empty.
226 node = create_node(self.ec, self.username, pl_user=self.pl_user,
227 pl_password=self.pl_password, pl_url=self.pl_url,
228 hostname="nepi1.pl.sophia.inria.fr")
230 plnode_rm = self.ec.get_resource(node)
231 self.assertEquals(plnode_rm.plapi.blacklisted(), set())
233 # check that the node is actually malfunctioning
234 api = plnode_rm.plapi
235 filters = {'boot_state': 'boot', 'node_type': 'regular',
236 'hostname': 'nepi1.pl.sophia.inria.fr', 'run_level': 'boot',
237 '>last_contact': int(time.time()) - 2*3600}
238 node_id = api.get_nodes(filters, fields=['node_id'])
241 with self.assertRaises(RuntimeError):
242 plnode_rm.do_discover()
243 self.assertEquals(plnode_rm.plapi.blacklisted(), set([1]))
245 @skipIfNotPLCredentials
246 def test_provision_node_inslice(self):
248 Check provision of the node nepi2.pl.sophia.inria.fr.
250 node = create_node(self.ec, self.username, pl_user=self.pl_user,
251 pl_password=self.pl_password, pl_url=self.pl_url,
252 architecture="x86_64", operatingSystem="f12")
254 plnode_rm = self.ec.get_resource(node)
255 self.assertEquals(len(plnode_rm.plapi.blacklisted()), 0)
256 self.assertEquals(len(plnode_rm.plapi.reserved()), 0)
258 api = plnode_rm.plapi
259 api.add_slice_nodes(self.username, ['nepi2.pl.sophia.inria.fr'])
261 plnode_rm.do_discover()
262 plnode_rm.do_provision()
263 ip = plnode_rm.get("ip")
264 self.assertEquals(ip, "138.96.116.32")
265 self.assertEquals(len(plnode_rm.plapi.reserved()), 1)
267 @skipIfNotPLCredentials
268 def test_provision_node_not_inslice(self):
270 Check provision of one of the nodes f12, nodes:
271 'nepi3.pl.sophia.inria.fr'
272 'nepi5.pl.sophia.inria.fr'
274 node = create_node(self.ec, self.username, pl_user=self.pl_user,
275 pl_password=self.pl_password, pl_url=self.pl_url, operatingSystem="f12",
278 plnode_rm = self.ec.get_resource(node)
279 self.assertEquals(plnode_rm.plapi.blacklisted(), set())
280 self.assertEquals(plnode_rm.plapi.reserved(), set())
282 api = plnode_rm.plapi
283 api.add_slice_nodes(self.username, ['nepi2.pl.sophia.inria.fr'])
285 plnode_rm.do_discover()
286 plnode_rm.do_provision()
287 ip = plnode_rm.get("ip")
289 result = ["138.96.116.33","138.96.116.35"]
290 self.assertIn(ip, result)
292 # @skipIfNotPLCredentials
293 # def test_provision_more_than_available(self):
295 # Check that if the user wants to provision 3 nodes in Paris, he
296 # gets RuntimeError, there are only 2 nodes with city=Paris.
298 # node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
299 # pl_password=self.pl_password, pl_url=self.pl_url,
300 # city="Paris", operatingSystem="f12")
302 # plnode_rm1 = self.ec.get_resource(node1)
304 # api = plnode_rm.plapi
305 # api.add_slice_nodes(self.username, ['nepi2.pl.sophia.inria.fr'])
307 # plnode_rm1.do_discover()
308 # plnode_rm1.do_provision()
310 # node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
311 # pl_password=self.pl_password, pl_url=self.pl_url,
312 # city="Paris", operatingSystem="f12")
314 # plnode_rm2 = self.ec.get_resource(node2)
315 # plnode_rm2.do_discover()
316 # plnode_rm2.do_provision()
318 # node3 = create_node(self.ec, self.username, pl_user=self.pl_user,
319 # pl_password=self.pl_password, pl_url=self.pl_url,
320 # city="Paris", operatingSystem="f12")
322 # plnode_rm3 = self.ec.get_resource(node3)
323 # with self.assertRaises(RuntimeError):
324 # plnode_rm3.do_discover()
325 # with self.assertRaises(RuntimeError):
326 # plnode_rm3.do_provision()
328 # host1 = plnode_rm1.get('hostname')
330 # plnode_rm3._set_hostname_attr(host1)
332 # @skipIfNotPLCredentials
333 # def test_concurrence(self):
335 # Test with the nodes being discover and provision at the same time.
336 # It should fail as the test before.
338 # node1 = create_node(self.ec, self.username, pl_user=self.pl_user,
339 # pl_password=self.pl_password, pl_url=self.pl_url,
340 # architecture="x86_64", operatingSystem="f12")
342 # node2 = create_node(self.ec, self.username, pl_user=self.pl_user,
343 # pl_password=self.pl_password, pl_url=self.pl_url,
344 # architecture="x86_64", operatingSystem="f12")
346 # node3 = create_node(self.ec, self.username, pl_user=self.pl_user,
347 # pl_password=self.pl_password, pl_url=self.pl_url,
348 # architecture="x86_64", operatingSystem="f12")
350 # node4 = create_node(self.ec, self.username, pl_user=self.pl_user,
351 # pl_password=self.pl_password, pl_url=self.pl_url,
352 # architecture="x86_64", operatingSystem="f12")
355 # self.ec.wait_finished([node1, node2, node3, node4])
356 # state = self.ec.state(node1, hr=True)
357 # self.assertIn(state, ['READY', 'FAILED'])
358 # state = self.ec.state(node2, hr=True)
359 # self.assertIn(state, ['READY', 'FAILED'])
360 # state = self.ec.state(node3, hr=True)
361 # self.assertIn(state, ['READY', 'FAILED'])
362 # state = self.ec.state(node4, hr=True)
363 # self.assertIn(state, ['READY', 'FAILED'])
366 commonapi=PLCAPIFactory.get_api(self.pl_user, self.pl_password,
368 #commonapi.add_slice_nodes(self.username, ['nepi2.pl.sophia.inria.fr'])
369 commonapi._reserved = set()
370 commonapi._blacklist = set()
375 if __name__ == '__main__':