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
29 import multiprocessing
31 class DummyEC(ExperimentController):
34 def create_node(ec, username, pl_user, pl_password, hostname=None, country=None,
35 operatingSystem=None, minBandwidth=None, minCpu=None):
37 node = ec.register_resource("PlanetlabNode")
40 ec.set(node, "username", username)
42 ec.set(node, "pluser", pl_user)
44 ec.set(node, "plpassword", pl_password)
47 ec.set(node, "hostname", hostname)
49 ec.set(node, "country", country)
51 ec.set(node, "operatingSystem", operatingSystem)
53 iec.set(node, "minBandwidth", minBandwidth)
55 ec.set(node, "minCpu", minCpu)
57 ec.set(node, "cleanHome", True)
58 ec.set(node, "cleanProcesses", True)
62 class PLNodeFactoryTestCase(unittest.TestCase):
64 def test_creation_phase(self):
65 self.assertEquals(PlanetlabNode.rtype(), "PlanetlabNode")
66 self.assertEquals(len(PlanetlabNode._attributes), 29)
69 class PLNodeTestCase(unittest.TestCase):
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.
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/"
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.
90 node1 = create_node(self.ec, self.username, self.pl_user,
91 self.pl_password, country="France")
93 plnode_rm1 = self.ec.get_resource(node1)
94 hostname = plnode_rm1.get("hostname")
95 self.assertIsNone(hostname)
97 self.assertIsNone(plnode_rm1._node_to_provision)
99 api1 = plnode_rm1.plapi
100 self.assertIsInstance(api1, PLCAPI)
101 self.assertEquals(len(api1.reserved()), 0)
102 self.assertEquals(len(api1.blacklisted()), 0)
104 node2 = create_node(self.ec, self.username, self.pl_user,
105 self.pl_password, country="France")
107 plnode_rm2 = self.ec.get_resource(node2)
108 api2 = plnode_rm2.plapi
109 self.assertEquals(api1, api2)
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)
115 def test_discover_inslice(self):
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.
121 node = create_node(self.ec, self.username, self.pl_user,
122 self.pl_password, country="France", operatingSystem="f12")
124 plnode_rm = self.ec.get_resource(node)
126 hostname = plnode_rm.get("hostname")
127 self.assertIsNone(hostname)
130 self.assertEquals(plnode_rm._node_to_provision, 7057)
132 # Set hostname attribute in order for the shutdown method not to fail
133 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
135 def test_discover_not_inslice(self):
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
141 node = create_node(self.ec, self.username, self.pl_user,
142 self.pl_password, country="France", operatingSystem="f14")
144 plnode_rm = self.ec.get_resource(node)
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())
151 # Set hostname attribute in order for the shutdown method not to fail
152 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
154 def test_discover_hostname(self):
156 This test checks that if the user specify the hostname, only that node
159 node = create_node(self.ec, self.username, self.pl_user,
160 self.pl_password, hostname="planetlab1.sics.se")
162 plnode_rm = self.ec.get_resource(node)
165 self.assertEquals(plnode_rm._node_to_provision, 14871)
166 self.assertEquals(plnode_rm.plapi.reserved(), set([14871]))
168 def test_discover_with_ranges(self):
170 Checks that defining max or min attributes, the discover method works.
172 node = create_node(self.ec, self.username, self.pl_user,
173 self.pl_password, minCpu=50) #minBandwidth=500)
175 plnode_rm = self.ec.get_resource(node)
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())
183 # Set hostname attribute in order for the shutdown method not to fail
184 plnode_rm._set_hostname_attr(plnode_rm._node_to_provision)
186 def test_blacklist_nodes(self):
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.
192 node = create_node(self.ec, self.username, self.pl_user,
193 self.pl_password, hostname="planetlab-1a.ics.uci.edu")
195 plnode_rm = self.ec.get_resource(node)
196 self.assertEquals(plnode_rm.plapi.blacklisted(), set())
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',
203 node_id = api.get_nodes(filters, fields=['node_id'])
206 with self.assertRaises(RuntimeError):
208 self.assertEquals(plnode_rm.plapi.blacklisted(), set([14871]))
210 def test_provision_node_inslice(self):
212 Check provision of the node planetlab2.utt.fr.
214 node = create_node(self.ec, self.username, self.pl_user,
215 self.pl_password, country="France", operatingSystem="f12")
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)
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)
227 def test_provision_node_not_inslice(self):
229 Check provision of one of the nodes f14 France, nodes:
230 node1pl.planet-lab.telecom-lille1.eu
232 node2pl.planet-lab.telecom-lille1.eu
234 node = create_node(self.ec, self.username, self.pl_user,
235 self.pl_password, country="France", operatingSystem="f14")
237 plnode_rm = self.ec.get_resource(node)
238 self.assertEquals(plnode_rm.plapi.blacklisted(), set())
239 self.assertEquals(plnode_rm.plapi.reserved(), set())
242 plnode_rm.provision()
243 ip = plnode_rm.get("ip")
245 result = ["194.167.254.18","132.227.62.123","194.167.254.19"]
246 self.assertIn(ip, result)
248 def test_provision_more_than_available(self):
250 Check that if the user wants to provision 4 nodes with fedora 14, he
251 gets RuntimeError, there are only 3 nodes f14.
253 node1 = create_node(self.ec, self.username, self.pl_user,
254 self.pl_password, country="France", operatingSystem="f14")
256 plnode_rm1 = self.ec.get_resource(node1)
257 plnode_rm1.discover()
258 plnode_rm1.provision()
260 node2 = create_node(self.ec, self.username, self.pl_user,
261 self.pl_password, country="France", operatingSystem="f14")
263 plnode_rm2 = self.ec.get_resource(node2)
264 plnode_rm2.discover()
265 plnode_rm2.provision()
267 node3 = create_node(self.ec, self.username, self.pl_user,
268 self.pl_password, country="France", operatingSystem="f14")
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()
276 node4 = create_node(self.ec, self.username, self.pl_user,
277 self.pl_password, country="France", operatingSystem="f14")
279 plnode_rm4 = self.ec.get_resource(node4)
280 with self.assertRaises(RuntimeError):
281 plnode_rm4.discover()
283 host1 = plnode_rm1.get('hostname')
285 plnode_rm3._set_hostname_attr(host1)
286 plnode_rm4._set_hostname_attr(host1)
288 def test_concurrence(self):
290 Test with the nodes being discover and provision at the same time.
292 node1 = create_node(self.ec, self.username, self.pl_user,
293 self.pl_password, country="France", operatingSystem="f14")
295 node2 = create_node(self.ec, self.username, self.pl_user,
296 self.pl_password, country="France", operatingSystem="f14")
298 node3 = create_node(self.ec, self.username, self.pl_user,
299 self.pl_password, country="France", operatingSystem="f14")
301 node4 = create_node(self.ec, self.username, self.pl_user,
302 self.pl_password, country="France", operatingSystem="f14")
305 self.ec.wait_finished([node1, node2, node3, node4])
306 state = self.ec.ecstate
307 self.assertEquals(state, 2)
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()
317 if __name__ == '__main__':