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: Alina Quereilhac <alina.quereilhac@inria.fr>
22 from nepi.execution.attribute import Attribute
23 from nepi.execution.ec import ExperimentController
24 from nepi.execution.resource import ResourceManager, ResourceState, clsinit, \
32 class MyResource(ResourceManager):
36 def _register_attributes(cls):
37 cool_attr = Attribute("my_attr", "is a really nice attribute!")
38 cls._register_attribute(cool_attr)
40 def __init__(self, ec, guid):
41 super(MyResource, self).__init__(ec, guid)
44 class AnotherResource(ResourceManager):
45 _rtype = "AnotherResource"
47 def __init__(self, ec, guid):
48 super(AnotherResource, self).__init__(ec, guid)
51 class Channel(ResourceManager):
54 def __init__(self, ec, guid):
55 super(Channel, self).__init__(ec, guid)
59 super(Channel, self).deploy()
60 self.logger.debug(" -------- DEPLOYED ------- ")
62 class Interface(ResourceManager):
65 def __init__(self, ec, guid):
66 super(Interface, self).__init__(ec, guid)
69 node = self.get_connected(Node.rtype())[0]
70 chan = self.get_connected(Channel.rtype())[0]
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)
78 super(Interface, self).deploy()
79 self.logger.debug(" -------- DEPLOYED ------- ")
81 class Node(ResourceManager):
84 def __init__(self, ec, guid):
85 super(Node, self).__init__(ec, guid)
88 if self.state == ResourceState.NEW:
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())
96 if rm.state < ResourceState.READY:
97 self.ec.schedule("0.5s", self.deploy)
100 super(Node, self).deploy()
101 self.logger.debug(" -------- DEPLOYED ------- ")
103 class Application(ResourceManager):
104 _rtype = "Application"
106 def __init__(self, ec, guid):
107 super(Application, self).__init__(ec, guid)
110 node = self.get_connected(Node.rtype())[0]
111 if node.state < ResourceState.READY:
112 self.ec.schedule("0.5s", self.deploy)
114 time.sleep(random.random() * 5)
115 super(Application, self).deploy()
116 self.logger.debug(" -------- DEPLOYED ------- ")
119 super(Application, self).start()
120 time.sleep(random.random() * 5)
121 self._state = ResourceState.FINISHED
124 class ResourceFactoryTestCase(unittest.TestCase):
125 def test_add_resource_factory(self):
126 from nepi.execution.resource import ResourceFactory
128 ResourceFactory._resource_types = dict()
129 ResourceFactory.register_type(MyResource)
130 ResourceFactory.register_type(AnotherResource)
132 self.assertEquals(MyResource.rtype(), "MyResource")
133 self.assertEquals(len(MyResource._attributes), 1)
135 self.assertEquals(ResourceManager.rtype(), "Resource")
136 self.assertEquals(len(ResourceManager._attributes), 0)
138 self.assertEquals(AnotherResource.rtype(), "AnotherResource")
139 self.assertEquals(len(AnotherResource._attributes), 0)
141 self.assertEquals(len(ResourceFactory.resource_types()), 2)
143 # restore factory state for other tests
144 from nepi.execution.resource import populate_factory
145 ResourceFactory._resource_types = dict()
148 class ResourceManagerTestCase(unittest.TestCase):
149 def test_register_condition(self):
150 ec = ExperimentController()
151 rm = ResourceManager(ec, 15)
154 rm.register_condition(ResourceAction.START, group,
155 ResourceState.STARTED)
158 rm.register_condition(ResourceAction.START,
159 group, ResourceState.STARTED, time = "10s")
162 conditions = rm.conditions.get(ResourceAction.START)
163 for (group, state, time) in conditions:
164 waiting_for.extend(group)
166 self.assertEquals(waiting_for, [1, 3, 5, 7, 10, 8])
168 group = [1, 2, 3, 4, 6]
169 rm.unregister_condition(group)
172 conditions = rm.conditions.get(ResourceAction.START)
173 for (group, state, time) in conditions:
174 waiting_for.extend(group)
176 self.assertEquals(waiting_for, [5, 7, 10, 8])
178 def test_deploy_in_order(self):
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.
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
191 from nepi.execution.resource import ResourceFactory
193 ResourceFactory.register_type(Application)
194 ResourceFactory.register_type(Node)
195 ResourceFactory.register_type(Interface)
196 ResourceFactory.register_type(Channel)
198 ec = ExperimentController()
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")
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)
218 ec.wait_finished(guids)
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)
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)
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)
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)
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)
247 def test_concurrency(self):
248 from nepi.execution.resource import ResourceFactory
250 ResourceFactory.register_type(Application)
251 ResourceFactory.register_type(Node)
252 ResourceFactory.register_type(Interface)
253 ResourceFactory.register_type(Channel)
255 ec = ExperimentController()
257 node = ec.register_resource("Node")
260 for i in xrange(1000):
261 app = ec.register_resource("Application")
262 ec.register_connection(app, node)
267 ec.wait_finished(apps)
269 self.assertTrue(ec.state(node) == ResourceState.STARTED)
271 all([ec.state(guid) == ResourceState.FINISHED \
277 def test_start_with_condition(self):
281 def test_stop_with_condition(self):
285 def test_set_with_condition(self):
290 if __name__ == '__main__':