Adding and modifying PlanetlabNode unittests
[nepi.git] / test / resources / planetlab / node.py
1 #!/usr/bin/env python
2 #
3 #    NEPI, a framework to manage network experiments
4 #    Copyright (C) 2013 INRIA
5 #
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.
10 #
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.
15 #
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/>.
18 #
19 # Author: Lucia Guevgeozian <lucia.guevgeozian_odizzio@inria.fr>
20
21 from nepi.execution.ec import ExperimentController
22
23 from nepi.resources.planetlab.node import PlanetlabNode
24 from nepi.resources.planetlab.plcapi import PLCAPI, PLCAPIFactory
25
26 import os
27 import time
28 import unittest
29 import multiprocessing
30
31 class DummyEC(ExperimentController):
32     pass
33
34 def create_node(ec, username, pl_user, pl_password, hostname=None, country=None,
35                 operatingSystem=None, minBandwidth=None, minCpu=None):
36
37     node = ec.register_resource("PlanetlabNode")
38
39     if username:
40         ec.set(node, "username", username)
41     if pl_user:
42         ec.set(node, "pluser", pl_user)
43     if pl_password:
44         ec.set(node, "plpassword", pl_password)
45
46     if hostname:
47         ec.set(node, "hostname", hostname)
48     if country:
49         ec.set(node, "country", country)
50     if operatingSystem:
51         ec.set(node, "operatingSystem", operatingSystem)
52     if minBandwidth:
53         iec.set(node, "minBandwidth", minBandwidth)
54     if minCpu:
55         ec.set(node, "minCpu", minCpu)
56
57     ec.set(node, "cleanHome", True)
58     ec.set(node, "cleanProcesses", True)
59     
60     return node
61
62 class PLNodeFactoryTestCase(unittest.TestCase):
63
64     def test_creation_phase(self):
65         self.assertEquals(PlanetlabNode.rtype(), "PlanetlabNode")
66         self.assertEquals(len(PlanetlabNode._attributes), 29)
67
68
69 class PLNodeTestCase(unittest.TestCase):
70     """
71     This tests use inria_sfatest slice, and planetlab2.utt.fr already added to
72     the slice, and ONLY this one in order for the test not to fail.
73     """
74
75     def setUp(self):
76         self.ec = DummyEC()
77         self.username = "inria_sfatest"
78         self.pl_user = os.environ.get("PL_USER")
79         self.pl_password = os.environ.get("PL_PASS")
80         self.pl_url = "www.planet-lab.eu"
81         self.pl_ptn = "https://%(hostname)s:443/PLCAPI/"
82
83     def test_plapi(self):
84         """
85         Check that the api to discover and reserve resources is well
86         instanciated, and is an instance of PLCAPI. Ignore error while
87         executing the ec.shutdown method, the error is due to the name
88         of the host not being defined yet for this test.
89        """
90         node1 = create_node(self.ec, self.username, self.pl_user, 
91             self.pl_password, country="France")
92
93         plnode_rm1 = self.ec.get_resource(node1)
94         hostname = plnode_rm1.get("hostname")
95         self.assertIsNone(hostname)
96
97         self.assertIsNone(plnode_rm1._node_to_provision)
98
99         api1 = plnode_rm1.plapi
100         self.assertIsInstance(api1, PLCAPI)
101         self.assertEquals(len(api1.reserved()), 0)
102         self.assertEquals(len(api1.blacklisted()), 0)
103
104         node2 = create_node(self.ec, self.username, self.pl_user,   
105             self.pl_password, country="France")
106         
107         plnode_rm2 = self.ec.get_resource(node2)
108         api2 = plnode_rm2.plapi
109         self.assertEquals(api1, api2)
110
111         # Set hostname attribute in order for the shutdown method not to fail
112         plnode_rm1._set_hostname_attr(7057)
113         plnode_rm2._set_hostname_attr(7057)
114
115     def test_discover_inslice(self):
116         """
117         This test uses the fact that the node planetlab2.utt.fr is already in 
118         the slice and match the constraints OS Fedora12 and country France.
119         Check planetlab2.utt.fr is alive if the test fails.
120         """
121         node = create_node(self.ec, self.username, self.pl_user,
122             self.pl_password, country="France", operatingSystem="f12")
123
124         plnode_rm = self.ec.get_resource(node)
125         
126         hostname = plnode_rm.get("hostname")
127         self.assertIsNone(hostname)
128
129         plnode_rm.discover()
130         self.assertEquals(plnode_rm._node_to_provision, 7057)
131
132         # Set hostname attribute in order for the shutdown method not to fail
133         plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)        
134
135     def test_discover_not_inslice(self):
136         """
137         This test checks that if the node is not in the slice, anyway the
138         discover method picks one that match constraints outside from the
139         slice.
140         """
141         node = create_node(self.ec, self.username, self.pl_user,
142             self.pl_password, country="France", operatingSystem="f14")
143
144         plnode_rm = self.ec.get_resource(node)
145         plnode_rm.discover()
146     
147         result = [14281, 1034, 7035] # nodes matching f14 and France
148         self.assertIn(plnode_rm._node_to_provision, result)     
149         self.assertIsNot(plnode_rm.plapi.reserved(), set())
150
151         # Set hostname attribute in order for the shutdown method not to fail
152         plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)        
153
154     def test_discover_hostname(self):
155         """
156         This test checks that if the user specify the hostname, only that node
157         is discovered.
158         """
159         node = create_node(self.ec, self.username, self.pl_user,
160                 self.pl_password, hostname="planetlab1.sics.se")
161
162         plnode_rm = self.ec.get_resource(node)
163         plnode_rm.discover()
164
165         self.assertEquals(plnode_rm._node_to_provision, 14871)
166         self.assertEquals(plnode_rm.plapi.reserved(), set([14871]))
167
168     def test_discover_with_ranges(self):
169         """
170         Checks that defining max or min attributes, the discover method works.
171         """
172         node = create_node(self.ec, self.username, self.pl_user,
173             self.pl_password, minCpu=50) #minBandwidth=500)
174
175         plnode_rm = self.ec.get_resource(node)
176         plnode_rm.discover()
177
178         #result = [15815, 15814, 425, 417, 1054, 1102, 1107, 505, 1031] 
179         result = [425, 15815, 15814, 14842, 427, 41, 14466]
180         self.assertIn(plnode_rm._node_to_provision, result)
181         self.assertIsNot(plnode_rm.plapi.reserved(), set())
182
183         # Set hostname attribute in order for the shutdown method not to fail
184         plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)        
185         
186     def test_blacklist_nodes(self):
187         """
188         Test that if the node is malfunctioning it gets blacklisted, the node
189         planetlab-1a.ics.uci.edu is used, if the test fails, check that the 
190         result of the plcapi query is actually empty.
191         """
192         node = create_node(self.ec, self.username, self.pl_user,
193                 self.pl_password, hostname="planetlab-1a.ics.uci.edu")
194
195         plnode_rm = self.ec.get_resource(node)
196         self.assertEquals(plnode_rm.plapi.blacklisted(), set())
197
198         # check that the node is actually malfunctioning
199         api = plnode_rm.plapi
200         filters = {'boot_state': 'boot', '>last_contact': 1378299413, 
201             'node_type': 'regular', 'hostname': 'planetlab-1a.ics.uci.edu', 
202             'run_level': 'boot'}
203         node_id = api.get_nodes(filters, fields=['node_id'])
204
205         if not node_id:
206             with self.assertRaises(RuntimeError):
207                 plnode_rm.discover()
208                 self.assertEquals(plnode_rm.plapi.blacklisted(), set([14871]))
209
210     def test_provision_node_inslice(self):
211         """
212         Check provision of the node planetlab2.utt.fr.
213         """
214         node = create_node(self.ec, self.username, self.pl_user,
215             self.pl_password, country="France", operatingSystem="f12")
216
217         plnode_rm = self.ec.get_resource(node)
218         self.assertEquals(len(plnode_rm.plapi.blacklisted()), 0)
219         self.assertEquals(len(plnode_rm.plapi.reserved()), 0)
220
221         plnode_rm.discover()
222         plnode_rm.provision()
223         ip = plnode_rm.get("ip")
224         self.assertEquals(ip, "194.254.215.12")
225         self.assertEquals(len(plnode_rm.plapi.reserved()), 1)
226
227     def test_provision_node_not_inslice(self):
228         """
229         Check provision of one of the nodes f14 France, nodes:
230         node1pl.planet-lab.telecom-lille1.eu
231         ple5.ipv6.lip6.fr
232         node2pl.planet-lab.telecom-lille1.eu
233         """
234         node = create_node(self.ec, self.username, self.pl_user,
235             self.pl_password, country="France", operatingSystem="f14")
236
237         plnode_rm = self.ec.get_resource(node)
238         self.assertEquals(plnode_rm.plapi.blacklisted(), set())
239         self.assertEquals(plnode_rm.plapi.reserved(), set())
240
241         plnode_rm.discover()
242         plnode_rm.provision()
243         ip = plnode_rm.get("ip")       
244
245         result = ["194.167.254.18","132.227.62.123","194.167.254.19"] 
246         self.assertIn(ip, result)
247
248     def test_provision_more_than_available(self):
249         """
250         Check that if the user wants to provision 4 nodes with fedora 14, he
251         gets RuntimeError, there are only 3 nodes f14.
252         """
253         node1 = create_node(self.ec, self.username, self.pl_user,
254             self.pl_password, country="France", operatingSystem="f14")
255
256         plnode_rm1 = self.ec.get_resource(node1)
257         plnode_rm1.discover()
258         plnode_rm1.provision()
259
260         node2 = create_node(self.ec, self.username, self.pl_user,
261             self.pl_password, country="France", operatingSystem="f14")
262
263         plnode_rm2 = self.ec.get_resource(node2)
264         plnode_rm2.discover()
265         plnode_rm2.provision()
266
267         node3 = create_node(self.ec, self.username, self.pl_user,
268             self.pl_password, country="France", operatingSystem="f14")
269
270         plnode_rm3 = self.ec.get_resource(node3)
271         with self.assertRaises(RuntimeError):
272             plnode_rm3.discover()
273             with self.assertRaises(RuntimeError):
274                 plnode_rm3.provision()
275         
276         node4 = create_node(self.ec, self.username, self.pl_user,
277             self.pl_password, country="France", operatingSystem="f14")
278
279         plnode_rm4 = self.ec.get_resource(node4)
280         with self.assertRaises(RuntimeError):
281             plnode_rm4.discover()
282
283         host1 = plnode_rm1.get('hostname')
284
285         plnode_rm3._set_hostname_attr(host1)
286         plnode_rm4._set_hostname_attr(host1)
287
288     def test_concurrence(self):
289         """
290         Test with the nodes being discover and provision at the same time.
291         """
292         node1 = create_node(self.ec, self.username, self.pl_user,
293             self.pl_password, country="France", operatingSystem="f14")
294
295         node2 = create_node(self.ec, self.username, self.pl_user,
296             self.pl_password, country="France", operatingSystem="f14")
297
298         node3 = create_node(self.ec, self.username, self.pl_user,
299             self.pl_password, country="France", operatingSystem="f14")
300
301         node4 = create_node(self.ec, self.username, self.pl_user,
302             self.pl_password, country="France", operatingSystem="f14")
303
304         self.ec.deploy()
305         self.ec.wait_finished([node1, node2, node3, node4])
306         state = self.ec.ecstate
307         self.assertEquals(state, 2)
308
309     def tearDown(self):
310         commonapi=PLCAPIFactory.get_api(self.pl_user, self.pl_password,
311             self.pl_url, self.pl_ptn)
312         commonapi._reserved = set()
313         commonapi._blacklist = set()
314         self.ec.shutdown()
315
316
317 if __name__ == '__main__':
318     unittest.main()
319
320
321