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