Adding tuncahnnel and pl-vif-tunnconnect scripts
[nepi.git] / test / execution / resource.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: Alina Quereilhac <alina.quereilhac@inria.fr>
20
21
22 from nepi.execution.attribute import Attribute
23 from nepi.execution.ec import ExperimentController 
24 from nepi.execution.resource import ResourceManager, ResourceState, clsinit, \
25         ResourceAction
26
27 import random
28 import time
29 import unittest
30
31 @clsinit
32 class MyResource(ResourceManager):
33     _rtype = "MyResource"
34
35     @classmethod
36     def _register_attributes(cls):
37         cool_attr = Attribute("my_attr", "is a really nice attribute!")
38         cls._register_attribute(cool_attr)
39
40     def __init__(self, ec, guid):
41         super(MyResource, self).__init__(ec, guid)
42
43 @clsinit
44 class AnotherResource(ResourceManager):
45     _rtype = "AnotherResource"
46
47     def __init__(self, ec, guid):
48         super(AnotherResource, self).__init__(ec, guid)
49
50
51 class Channel(ResourceManager):
52     _rtype = "Channel"
53
54     def __init__(self, ec, guid):
55         super(Channel, self).__init__(ec, guid)
56
57     def deploy(self):
58         time.sleep(1)
59         super(Channel, self).deploy()
60         self.logger.debug(" -------- DEPLOYED ------- ")
61        
62 class Interface(ResourceManager):
63     _rtype = "Interface"
64
65     def __init__(self, ec, guid):
66         super(Interface, self).__init__(ec, guid)
67
68     def deploy(self):
69         node = self.get_connected(Node.rtype())[0]
70         chan = self.get_connected(Channel.rtype())[0]
71
72         if node.state < ResourceState.PROVISIONED:
73             self.ec.schedule("0.5s", self.deploy)
74         elif chan.state < ResourceState.READY:
75             self.ec.schedule("0.5s", self.deploy)
76         else:
77             time.sleep(2)
78             super(Interface, self).deploy()
79             self.logger.debug(" -------- DEPLOYED ------- ")
80
81 class Node(ResourceManager):
82     _rtype = "Node"
83
84     def __init__(self, ec, guid):
85         super(Node, self).__init__(ec, guid)
86
87     def deploy(self):
88         if self.state == ResourceState.NEW:
89             self.discover()
90             self.provision()
91             self.logger.debug(" -------- PROVISIONED ------- ")
92             self.ec.schedule("3s", self.deploy)
93         elif self.state == ResourceState.PROVISIONED:
94             ifaces = self.get_connected(Interface.rtype())
95             for rm in ifaces:
96                 if rm.state < ResourceState.READY:
97                     self.ec.schedule("0.5s", self.deploy)
98                     return 
99
100             super(Node, self).deploy()
101             self.logger.debug(" -------- DEPLOYED ------- ")
102
103 class Application(ResourceManager):
104     _rtype = "Application"
105
106     def __init__(self, ec, guid):
107         super(Application, self).__init__(ec, guid)
108
109     def deploy(self):
110         node = self.get_connected(Node.rtype())[0]
111         if node.state < ResourceState.READY:
112             self.ec.schedule("0.5s", self.deploy)
113         else:
114             time.sleep(random.random() * 5)
115             super(Application, self).deploy()
116             self.logger.debug(" -------- DEPLOYED ------- ")
117
118     def start(self):
119         super(Application, self).start()
120         time.sleep(random.random() * 5)
121         self._state = ResourceState.FINISHED
122    
123
124 class ResourceFactoryTestCase(unittest.TestCase):
125     def test_add_resource_factory(self):
126         from nepi.execution.resource import ResourceFactory
127
128         ResourceFactory._resource_types = dict()
129         ResourceFactory.register_type(MyResource)
130         ResourceFactory.register_type(AnotherResource)
131
132         self.assertEquals(MyResource.rtype(), "MyResource")
133         self.assertEquals(len(MyResource._attributes), 1)
134
135         self.assertEquals(ResourceManager.rtype(), "Resource")
136         self.assertEquals(len(ResourceManager._attributes), 0)
137
138         self.assertEquals(AnotherResource.rtype(), "AnotherResource")
139         self.assertEquals(len(AnotherResource._attributes), 0)
140
141         self.assertEquals(len(ResourceFactory.resource_types()), 2)
142         
143         # restore factory state for other tests
144         from nepi.execution.resource import populate_factory
145         ResourceFactory._resource_types = dict()
146         populate_factory()
147
148 class ResourceManagerTestCase(unittest.TestCase):
149     def test_register_condition(self):
150         ec = ExperimentController()
151         rm = ResourceManager(ec, 15)
152
153         group = [1,3,5,7]
154         rm.register_condition(ResourceAction.START, group,
155                 ResourceState.STARTED)
156
157         group = [10,8]
158         rm.register_condition(ResourceAction.START,
159                 group, ResourceState.STARTED, time = "10s")
160
161         waiting_for = []
162         conditions = rm.conditions.get(ResourceAction.START)
163         for (group, state, time) in conditions:
164             waiting_for.extend(group)
165
166         self.assertEquals(waiting_for, [1, 3, 5, 7, 10, 8])
167
168         group = [1, 2, 3, 4, 6]
169         rm.unregister_condition(group)
170
171         waiting_for = []
172         conditions = rm.conditions.get(ResourceAction.START)
173         for (group, state, time) in conditions:
174             waiting_for.extend(group)
175
176         self.assertEquals(waiting_for, [5, 7, 10, 8])
177
178     def test_deploy_in_order(self):
179         """
180         Test scenario: 2 applications running one on 1 node each. 
181         Nodes are connected to Interfaces which are connected
182         through a channel between them.
183
184          - Application needs to wait until Node is ready to be ready
185          - Node needs to wait until Interface is ready to be ready
186          - Interface needs to wait until Node is provisioned to be ready
187          - Interface needs to wait until Channel is ready to be ready
188          - The channel doesn't wait for any other resource to be ready
189
190         """
191         from nepi.execution.resource import ResourceFactory
192         
193         ResourceFactory.register_type(Application)
194         ResourceFactory.register_type(Node)
195         ResourceFactory.register_type(Interface)
196         ResourceFactory.register_type(Channel)
197
198         ec = ExperimentController()
199
200         app1 = ec.register_resource("Application")
201         app2 = ec.register_resource("Application")
202         node1 = ec.register_resource("Node")
203         node2 = ec.register_resource("Node")
204         iface1 = ec.register_resource("Interface")
205         iface2 = ec.register_resource("Interface")
206         chan = ec.register_resource("Channel")
207
208         ec.register_connection(app1, node1)
209         ec.register_connection(app2, node2)
210         ec.register_connection(iface1, node1)
211         ec.register_connection(iface2, node2)
212         ec.register_connection(iface1, chan)
213         ec.register_connection(iface2, chan)
214
215         ec.deploy()
216
217         guids = [app1, app2]
218         ec.wait_finished(guids)
219
220         ec.shutdown()
221
222         rmapp1 = ec.get_resource(app1)
223         rmapp2 = ec.get_resource(app2)
224         rmnode1 = ec.get_resource(node1)
225         rmnode2 = ec.get_resource(node2)
226         rmiface1 = ec.get_resource(iface1)
227         rmiface2 = ec.get_resource(iface2)
228         rmchan = ec.get_resource(chan)
229
230         ## Validate deploy order
231         # - Application needs to wait until Node is ready to be ready
232         self.assertTrue(rmnode1.ready_time < rmapp1.ready_time)
233         self.assertTrue(rmnode2.ready_time < rmapp2.ready_time)
234
235          # - Node needs to wait until Interface is ready to be ready
236         self.assertTrue(rmnode1.ready_time > rmiface1.ready_time)
237         self.assertTrue(rmnode2.ready_time > rmiface2.ready_time)
238
239          # - Interface needs to wait until Node is provisioned to be ready
240         self.assertTrue(rmnode1.provision_time < rmiface1.ready_time)
241         self.assertTrue(rmnode2.provision_time < rmiface2.ready_time)
242
243          # - Interface needs to wait until Channel is ready to be ready
244         self.assertTrue(rmchan.ready_time < rmiface1.ready_time)
245         self.assertTrue(rmchan.ready_time < rmiface2.ready_time)
246
247     def test_concurrency(self):
248         from nepi.execution.resource import ResourceFactory
249         
250         ResourceFactory.register_type(Application)
251         ResourceFactory.register_type(Node)
252         ResourceFactory.register_type(Interface)
253         ResourceFactory.register_type(Channel)
254
255         ec = ExperimentController()
256
257         node = ec.register_resource("Node")
258
259         apps = list()
260         for i in xrange(1000):
261             app = ec.register_resource("Application")
262             ec.register_connection(app, node)
263             apps.append(app)
264
265         ec.deploy()
266
267         ec.wait_finished(apps)
268         
269         self.assertTrue(ec.state(node) == ResourceState.STARTED)
270         self.assertTrue(
271                all([ec.state(guid) == ResourceState.FINISHED \
272                 for guid in apps])
273                 )
274
275         ec.shutdown()
276
277     def test_start_with_condition(self):
278         # TODO!!!
279         pass
280     
281     def test_stop_with_condition(self):
282         # TODO!!!
283         pass
284
285     def test_set_with_condition(self):
286         # TODO!!!
287         pass
288
289
290 if __name__ == '__main__':
291     unittest.main()
292