Change OMF attributes during runtime
[nepi.git] / src / nepi / testbeds / omf / metadata.py
1 # -*- coding: utf-8 -*-
2
3 import functools
4 import weakref
5
6 from constants import TESTBED_ID, TESTBED_VERSION
7 from nepi.core import metadata
8 from nepi.core.attributes import Attribute
9 from nepi.util import tags, validation
10 from nepi.util.constants import ApplicationStatus as AS, \
11         FactoryCategories as FC, DeploymentConfiguration as DC
12
13 ##############################################################################
14
15 class OmfResource(object):
16     def __init__(self, guid, tc):
17         super(OmfResource, self).__init__()
18         self._tc = weakref.ref(tc)
19         self._guid = guid
20
21     @property
22     def tc(self):
23         return self._tc and self._tc()
24
25     def configure(self):
26         pass
27
28     def start(self):
29         pass
30
31     def stop(self):
32         pass
33
34     def status(self):
35         pass
36
37     def shutdown(self):
38         pass
39
40 ## NODE #######################################################################
41
42 class OmfNode(OmfResource):
43     def __init__(self, guid, tc):
44         super(OmfNode, self).__init__(guid, tc)
45         self.hostname = self.tc._get_parameters(guid)['hostname']
46         self.tc.api.enroll_host(self.hostname)
47
48 ## APPLICATION ################################################################
49
50 class OmfApplication(OmfResource):
51     def __init__(self, guid, tc):
52         super(OmfApplication, self).__init__(guid, tc)
53         node_guids = tc.get_connected(guid, "node", "apps")
54         if len(node_guids) == 0:
55             raise RuntimeError("Can't instantiate interface %d outside node" % guid)
56
57         self._node_guid = node_guids[0] 
58         self.app_id = None
59         self.arguments = None
60         self.path = None
61
62     def start(self):
63         node = self.tc.elements.get(self._node_guid)
64         self.tc.api.execute(node.hostname, 
65                 self.appId, 
66                 self.arguments, 
67                 self.path)
68
69     def status(self):
70         if guid not in testbed_instance.elements.keys():
71             return AS.STATUS_NOT_STARTED
72         return AS.STATUS_RUNNING
73         # TODO!!!!
74         #return AS.STATUS_FINISHED
75
76
77 ## WIFIIFACE ########################################################
78
79 class OmfWifiInterface(OmfResource):
80     def __init__(self, guid, tc):
81         super(OmfWifiInterface, self).__init__(guid, tc)
82         node_guids = tc.get_connected(guid, "node", "devs")
83         if len(node_guids) == 0:
84             raise RuntimeError("Can't instantiate interface %d outside node" % guid)
85
86         self._node_guid = node_guids[0] 
87         self.mode = None
88         self.type = None
89         self.essid = None
90         self.channel = None
91         self.ip = None
92
93     def __setattr__(self, name, value):
94         if name in ["ip", "mode", "type", "essid", "channel"]:
95             node = self.tc.elements.get(self._node_guid)    
96             attribute = "net/w0/%s" % name
97             self._tc().api.configure(node.hostname, attribute, value)
98         else:
99             super(OmfWifiInterface, self).__setattr__(name, value)
100
101 # Factories
102 NODE = "Node"
103 WIFIIFACE = "WifiInterface"
104 CHANNEL = "Channel"
105 OMFAPPLICATION = "OmfApplication"
106
107 def create(factory, testbed_instance, guid):
108     clazz = OmfResource
109     if factory == NODE:
110         clazz = OmfNode
111     elif factory == OMFAPPLICATION:
112         clazz = OmfApplication
113     elif factory == WIFIIFACE:
114         clazz = OmfWifiInterface
115
116     element = clazz(guid, testbed_instance)
117     #import pdb; pdb.set_trace()
118     testbed_instance._elements[guid] = element
119
120 def start(testbed_instance, guid):
121     element = testbed_instance.elements.get(guid)
122     element.start()
123
124 def stop(testbed_instance, guid):
125     element = testbed_instance.elements.get(guid)
126     element.stop()
127
128 def status(testbed_instance, guid):
129     element = testbed_instance.elements.get(guid)
130     return element.status()
131
132 def configure(testbed_instance, guid):
133     element = testbed_instance.elements.get(guid)
134     return element.status()
135
136 ### Factory information ###
137
138 connector_types = dict({
139     "apps": dict({
140                 "help": "Connector from node to applications", 
141                 "name": "apps",
142                 "max": -1, 
143                 "min": 0
144             }),
145     "devs": dict({
146                 "help": "Connector to network interfaces", 
147                 "name": "devs",
148                 "max": -1, 
149                 "min": 0
150             }),
151     "chan": dict({
152                 "help": "Connector from a device to a channel", 
153                 "name": "chan",
154                 "max": 1, 
155                 "min": 1
156             }),
157     "node": dict({
158                 "help": "Connector to a Node", 
159                 "name": "node",
160                 "max": 1, 
161                 "min": 1
162             }),
163    })
164
165 connections = [
166     dict({
167         "from": (TESTBED_ID, NODE, "devs"),
168         "to":   (TESTBED_ID, WIFIIFACE, "node"),
169         "can_cross": False
170     }),
171     dict({
172         "from": (TESTBED_ID, WIFIIFACE, "chan"),
173         "to":   (TESTBED_ID, CHANNEL, "devs"),
174         "can_cross": False
175     }),
176     dict({
177         "from": (TESTBED_ID, NODE, "apps"),
178         "to":   (TESTBED_ID, OMFAPPLICATION, "node"),
179         "can_cross": False
180     }),
181  ]
182
183 attributes = dict({
184     "appId": dict({
185                 "name": "appId",
186                 "help": "Application id",
187                 "type": Attribute.STRING,
188                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
189                 "validation_function": validation.is_string
190             }),
191     "arguments": dict({
192                 "name": "arguments",
193                 "help": "Application arguments",
194                 "type": Attribute.STRING,
195                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
196                 "validation_function": validation.is_string
197             }),
198     "path": dict({
199                 "name": "path",
200                 "help": "Path to binary (e.g '/opt/vlc-1.1.13/vlc')",
201                 "type": Attribute.STRING,
202                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
203                 "validation_function": validation.is_string
204             }),
205     "hostname": dict({
206                 "name": "hostname",
207                 "help": "Hostname for the target OMF node",
208                 "type": Attribute.STRING,
209                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
210                 "validation_function": validation.is_string
211             }),
212     "mode": dict({
213                 "name": "mode",
214                 "help": "Corresponds to the OMF attributes net/w0/mode",
215                 "type": Attribute.STRING,
216                 "flags": Attribute.NoDefaultValue, 
217                 "validation_function": validation.is_string
218             }),
219     "type": dict({
220                 "name": "type",
221                 "help": "Corresponds to the OMF attributes net/w0/type",
222                 "type": Attribute.STRING,
223                 "flags": Attribute.NoDefaultValue, 
224                 "validation_function": validation.is_string
225             }),
226     "channel": dict({
227                 "name": "channel",
228                 "help": "Corresponds to the OMF attributes net/w0/channel",
229                 "type": Attribute.STRING,
230                 "flags": Attribute.NoDefaultValue, 
231                 "validation_function": validation.is_string
232             }),
233     "essid": dict({
234                 "name": "essid",
235                 "help": "Corresponds to the OMF attributes net/w0/essid",
236                 "type": Attribute.STRING,
237                 "flags": Attribute.NoDefaultValue, 
238                 "validation_function": validation.is_string
239             }),
240     "ip": dict({
241                 "name": "ip",
242                 "help": "Corresponds to the OMF attributes net/w0/ip",
243                 "type": Attribute.STRING,
244                 "flags": Attribute.NoDefaultValue, 
245                 "validation_function": validation.is_ip4_address
246             }),
247
248
249
250     })
251
252 traces = dict()
253
254 create_order = [ NODE, WIFIIFACE, CHANNEL, OMFAPPLICATION ]
255 configure_order = [ WIFIIFACE,  NODE, CHANNEL, OMFAPPLICATION ]
256
257 factories_info = dict({
258     NODE: dict({
259             "help": "OMF Node",
260             "category": FC.CATEGORY_NODES,
261             "create_function": functools.partial(create, NODE),
262             "box_attributes": ["hostname"],
263             "connector_types": ["devs", "apps"],
264             "tags": [tags.NODE, tags.ALLOW_ROUTES],
265        }),
266     WIFIIFACE: dict({
267             "help": "Wireless network interface",
268             "category": FC.CATEGORY_DEVICES,
269             "create_function": functools.partial(create, WIFIIFACE),
270             "configure_function": configure,
271             "box_attributes": ["mode", "type", "channel", "essid", "ip"],
272             "connector_types": ["node", "chan"],
273             "tags": [tags.INTERFACE, tags.HAS_ADDRESSES],
274        }),
275     CHANNEL: dict({
276             "help": "Wireless channel",
277             "category": FC.CATEGORY_DEVICES,
278             "create_function": create,
279             "create_function": functools.partial(create, CHANNEL),
280             "box_attributes": ["mode", "type", "channel", "essid"],
281             "connector_types": ["devs"],
282        }),
283     OMFAPPLICATION: dict({
284             "help": "Generic executable command line application",
285             "category": FC.CATEGORY_APPLICATIONS,
286             "create_function": functools.partial(create, OMFAPPLICATION),
287             "start_function": start,
288             "stop_function": stop,
289             "status_function": status,
290             "box_attributes": ["appId", "arguments", "path"],
291             "connector_types": ["node"],
292             "tags": [tags.APPLICATION],
293         }),
294 })
295
296 testbed_attributes = dict({
297     "enable_debug": dict({
298             "name": "enableDebug",
299             "help": "Enable netns debug output",
300             "type": Attribute.BOOL,
301             "value": False,
302             "validation_function": validation.is_bool
303         }),
304     "xmppSlice": dict({
305                 "name": "xmppSlice",
306                 "help": "OMF slice",
307                 "type": Attribute.STRING,
308                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
309                 "validation_function": validation.is_string
310             }),
311     "xmppHost": dict({
312                 "name": "xmppHost",
313                 "help": "OMF XMPP server host",
314                 "type": Attribute.STRING,
315                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
316                 "validation_function": validation.is_string
317             }),
318     "xmppPort": dict({
319                 "name": "xmppPort",
320                 "help": "OMF XMPP service port",
321                 "type": Attribute.INTEGER,
322                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
323                 "validation_function": validation.is_integer
324             }),
325     "xmppPassword": dict({
326                 "name": "xmppPassword",
327                 "help": "OMF XMPP slice password",
328                 "type": Attribute.STRING,
329                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
330                 "validation_function": validation.is_string
331             }),
332     })
333
334 supported_recovery_policies = [
335         DC.POLICY_FAIL,
336     ]
337
338 class MetadataInfo(metadata.MetadataInfo):
339     @property
340     def connector_types(self):
341         return connector_types
342
343     @property
344     def connections(self):
345         return connections
346
347     @property
348     def attributes(self):
349         return attributes
350
351     @property
352     def traces(self):
353         return traces
354
355     @property
356     def create_order(self):
357         return create_order
358
359     @property
360     def configure_order(self):
361         return configure_order
362
363     @property
364     def factories_info(self):
365         return factories_info
366
367     @property
368     def testbed_attributes(self):
369         return testbed_attributes
370
371     @property
372     def testbed_id(self):
373         return TESTBED_ID
374
375     @property
376     def testbed_version(self):
377         return TESTBED_VERSION
378     
379     @property
380     def supported_recover_policies(self):
381         return supported_recovery_policies
382