Merge branch 'master' into funcaspect
[plcapi.git] / aspects / funcaspects.py
1 #!/usr/bin/python
2 import os
3 import datetime
4
5 from PLC.Config import Config
6 from PLC.Interfaces import Interface, Interfaces
7 from PLC.InterfaceTags import InterfaceTag, InterfaceTags
8 from PLC.Keys import Key, Keys
9
10 # For PLC 4.3
11 try:
12     from PLC.Methods.GetSliceFamily import GetSliceFamily
13 except ImportError:
14     pass
15
16 from PLC.NodeGroups import NodeGroup, NodeGroups
17 from PLC.NodeTags import NodeTag, NodeTags
18 from PLC.Nodes import Node, Nodes
19 from PLC.Persons import Person, Persons
20 from PLC.SliceTags import SliceTag, SliceTags
21 from PLC.Slices import Slice, Slices
22 from PLC.TagTypes import TagTypes
23
24 from pyaspects.meta import MetaAspect
25
26 import func.overlord.client
27
28 def absorb_exception(function_name):
29     def _wrapper(*args, **kwargs):
30         try:
31             return function_name(*args, **kwargs)
32         except:
33             return None
34     return _wrapper
35
36
37 class BaseFunc(object):
38
39     def __init__(self):
40         self.log = open("/var/log/funcaspect/plc_slice_calls.log", "a")
41         #self.log = None
42
43         self.interface_id = None
44         self.node_ids = None
45         self.person = None
46         self.person_name_or_id = None
47         self.slice = None
48         self.slice_ids = None
49         self.slice_name_or_id = None
50         self.tag = None
51         self.tag_name_or_id = None
52         self.tag_value = None
53
54     def logit(self, call, args, kwargs, data, slice):
55         if not self.log: return
56
57         self.log.write("%s : args: %s  kwargs: %s\n" % (call, args, kwargs))
58         self.log.write("data: %s\n" % data)
59         self.log.write("%s\n\n" % slice)
60         self.log.flush()
61
62     @absorb_exception
63     def get_slice(self, api, slice_id_or_name):
64         slice_filter = {}
65         try: # if integer
66             slice_filter["slice_id"] = int(str(slice_id_or_name))
67         except ValueError:
68             # we have a string
69             slice_filter["name"] = slice_id_or_name
70         slice = Slices(api, slice_filter = slice_filter)[0]
71         return slice
72
73     @absorb_exception
74     def get_node_tag(self, api, node_id_or_name):
75         tag_filter = {}
76         try: # if integer
77             tag_filter["node_tag_id"] = int(str(node_id_or_name))
78         except ValueError:
79             # we have a string
80             tag_filter["tagname"] = node_id_or_name
81         tag = NodeTags(api, node_tag_filter = tag_filter)[0]
82         return tag
83
84     @absorb_exception
85     def get_person(self, api, person_id_or_name):
86         person_filter = {}
87         try: # if integer
88             person_filter["person_id"] = int(str(person_id_or_name))
89         except ValueError:
90             # we have a string
91             person_filter["email"] = person_id_or_name
92         person = Persons(api, person_filter = person_filter)[0]
93         return person
94
95     @absorb_exception
96     def get_interface(self, api, interface_id):
97         return Interfaces(api, interface_filter = {"interface_id": interface_id})
98
99     @absorb_exception
100     def get_interfaces(self, api, node_id):
101         return Interfaces(api, interface_filter = {"node_id": node_id})
102
103     @absorb_exception
104     def get_slice_family(self, api, slice_id_or_name):
105         # For PLC 4.3
106         try:
107             return GetSliceFamily(api).call(api, slice_id_or_name)
108         except NameError:
109             return "planetlab-f8-i386"
110
111     @absorb_exception
112     def get_slice_tag(self, api, tag_id_or_name):
113         tag_filter = {}
114         try: # if integer
115             tag_filter["slice_tag_id"] = int(str(tag_id_or_name))
116         except ValueError:
117             # we have a string
118             tag_filter["tagname"] = tag_id_or_name
119         tag = SliceTags(api, slice_tag_filter = tag_filter)[0]
120         return tag
121
122     @absorb_exception
123     def get_tag_type(self, api, type_id_or_name):
124         tag_filter = {}
125         try: # if integer
126             tag_filter["tag_type_id"] = int(str(type_id_or_name))
127         except ValueError:
128             # we have a string
129             tag_filter["tagname"] = type_id_or_name
130         tag = TagTypes(api, tag_type_filter = tag_filter)[0]
131         return tag
132
133     @absorb_exception
134     def get_node_hostname(self, api, node_id_or_hostname):
135         node_filter = {}
136         try: # if integer
137             node_filter["node_id"] = int(str(node_id_or_hostname))
138         except ValueError:
139             # we have a string
140             node_filter["hostname"] = node_id_or_hostname
141         node = Nodes(api, node_filter = node_filter)[0]
142         return node["hostname"]
143
144     @absorb_exception
145     def get_slice_tags(self, api, slice_id):
146         return SliceTags(api, slice_tag_filter = {"slice_id": slice_id})
147
148     @absorb_exception
149     def get_slice_tags_with_tag_type(self, api, tag_type_id):
150         return SliceTags(api, slice_tag_filter = {"tag_type_id": tag_type_id})
151
152     @absorb_exception
153     def get_person_keys(self, api, person_ids):
154         return Keys(api, key_filter = {"person_id": person_ids})
155
156     @absorb_exception
157     def get_node_tags(self, api, node_id):
158         return NodeTags(api, node_tag_filter = {"node_id": node_id})
159
160     @absorb_exception
161     def get_interface_tags(self, api, interface_id):
162         return InterfaceTags(api, interface_tag_filter = {"interface_id": interface_id})
163
164     @absorb_exception
165     def get_node_groups(self, api, nodegroup_id):
166         return NodeGroups(api, nodegroup_filter = {"nodegroup_id": nodegroup_id})
167
168     def add_slice_to_node(self, slice, node, family, tags, keys):
169         pass
170
171     def delete_slice_from_node(self, slice, node):
172         pass
173
174     def add_person_to_slice(self, slice, node, person, value):
175         pass
176
177     def delete_person_from_slice(self, slice, node, person, value):
178         pass
179
180     def add_slice_tag(self, slice, node, tag, value):
181         pass
182
183     def add_node_tag(self, node, tag, value):
184         pass
185
186     def add_interface(self, node, value):
187         pass
188
189     def delete_interface(self, node, value):
190         pass
191
192     def delete_node_tag(self, node, tag, value):
193         pass
194
195     def delete_slice_tag(self, slice, node, tag, value):
196         pass
197
198     def update_node_tag(self, node, tag, value):
199         pass
200
201     def update_slice_tag(self, slice, node, tag, value):
202         pass
203
204     # aspect method which assigns the required variables
205     def before(self, wobj, data, *args, **kwargs):
206         api_method_name = wobj.name
207
208         if api_method_name == "AddSliceToNodes" or api_method_name == "DeleteSliceFromNodes":
209             self.slice_name_or_id = args[1]
210             self.node_ids = args[2]
211         elif api_method_name == "AddPersonToSlice" or api_method_name == "DeletePersonFromSlice":
212             self.person_name_or_id = args[1]
213             self.slice_name_or_id = args[2]
214
215         elif api_method_name == "AddSliceTag":
216             self.slice_name_or_id = args[1]
217             self.tag_name_or_id = args[2]
218             self.tag_value = args[3]
219         elif api_method_name == "DeleteSliceTag":
220             self.tag_name_or_id = args[1]
221             # keep it in memory
222             self.tag = self.get_slice_tag(wobj.api, self.tag_name_or_id)
223             self.slice = self.get_slice(wobj.api, self.tag["slice_id"])
224
225         elif api_method_name == "AddNodeTag":
226             self.node_ids = [args[1]]
227             self.tag_name_or_id = args[2]
228             self.tag_value = args[3]
229         elif api_method_name == "DeleteNodeTag":
230             self.tag_name_or_id = args[1]
231             # keep it in memory
232             self.tag = self.get_node_tag(wobj.api, self.tag_name_or_id)
233         elif api_method_name == "UpdateSliceTag" or api_method_name == "UpdateNodeTag":
234             self.tag_name_or_id = args[1]
235             self.tag_value = args[2]
236
237         elif api_method_name == "AddInterface" or api_method_name == "UpdateInterface":
238             self.node_ids = [args[1]]
239         elif api_method_name == "DeleteInterface":
240             self.interface_id = args[1]
241
242         elif api_method_name == "DeleteSlice":
243             self.slice_name_or_id = args[1]
244         elif api_method_name == "DeletePerson":
245             self.person_name_or_id = args[1]
246             # keep it in memory
247             self.person = self.get_person(wobj.api, self.person_name_or_id)
248         elif api_method_name == "DeleteTagType":
249             self.tag_name_or_id = args[1]
250             # keep it in memory
251             tag_type = self.get_tag_type(wobj.api, self.tag_name_or_id)[0]["tag_type_id"]
252             self.slice_ids = [slice_ids["slice_id"] for slice_ids in self.get_slice_tags_with_tag_type(wobj.api, tag_type)]
253             self.slice_ids = list(set(self.slice_ids))
254             # Node/NodeGroups ???
255             #GetNodeTags
256             #GetInterfaceTags
257         else: # ignore the rest
258             return
259
260         if self.slice_name_or_id != None:
261             self.slice = self.get_slice(wobj.api, self.slice_name_or_id)
262
263 #        self.logit(wobj.name, args, kwargs, data, slice)
264
265     # aspect method
266     def after(self, wobj, data, *args, **kwargs):
267         #if data.has_key("method_return_value") and data['method_return_value'] > 0:
268         #    # return value 1 means that API call was successful, we can go on.
269         #    pass
270         #else:
271         #    return
272
273         api_method_name = wobj.name
274
275         # assign globals to locals
276         interface_id = self.interface_id
277         node_ids = self.node_ids
278         person_name_or_id = self.person_name_or_id
279         slice = self.slice
280         tag = self.tag
281         person = self.person
282         tag_name_or_id = self.tag_name_or_id
283         tag_value = self.tag_value
284
285         if api_method_name == "AddSliceToNodes":
286             slice_tags = self.get_slice_tags(wobj.api, slice["slice_id"])
287             slice_keys = self.get_person_keys(wobj.api, slice["person_ids"])
288             slice_family = self.get_slice_family(wobj.api, slice["slice_id"])
289             for node_id in node_ids:
290                 node_hostname = self.get_node_hostname(wobj.api, node_id)
291                 self.add_slice_to_node(slice["name"], node_hostname, slice_family, slice_tags, slice_keys)
292         elif api_method_name == "DeleteSliceFromNodes":
293             for node_id in node_ids:
294                 node_hostname = self.get_node_hostname(wobj.api, node_id)
295                 self.delete_slice_from_node(slice["name"], node_hostname)
296
297         elif api_method_name == "AddPersonToSlice":
298             person = self.get_person(wobj.api, person_name_or_id)
299             keys = self.get_person_keys(wobj.api, slice["person_ids"])
300             keys += self.get_person_keys(wobj.api, person["person_id"])
301             for node_id in slice["node_ids"]:
302                 node_hostname = self.get_node_hostname(wobj.api, node_id)
303                 self.add_person_to_slice(slice["name"], node_hostname, person["email"], keys)
304         elif api_method_name == "DeletePersonFromSlice":
305             person = self.get_person(wobj.api, person_name_or_id)
306             keys = self.get_person_keys(wobj.api, slice["person_ids"])
307             keys.remove(self.get_person_keys(wobj.api, slice["person_ids"])[0])
308             for node_id in slice["node_ids"]:
309                 node_hostname = self.get_node_hostname(wobj.api, node_id)
310                 self.delete_person_from_slice(slice["name"], node_hostname, person["email"], keys)
311
312         elif api_method_name == "AddSliceTag":
313             tag = self.get_tag_type(wobj.api, tag_name_or_id)
314
315             if len(args) == 4:
316                 node_ids = slice["node_ids"]
317             elif len(args) == 5:
318                 node_ids = [args[4]]
319             else:
320                 node_groups = self.get_node_groups(wobj.api, args[5])
321                 node_ids = set.intersection(set(node_groups[0]["node_ids"]), set(slice["node_ids"]))
322
323             for node_id in node_ids:
324                 node_hostname = self.get_node_hostname(wobj.api, node_id)
325                 self.add_slice_tag(slice["name"], node_hostname, tag["tagname"], tag_value)
326         elif api_method_name == "DeleteSliceTag":
327             slice = self.get_slice(wobj.api, tag["slice_id"])
328             for node_id in slice["node_ids"]:
329                 node_hostname = self.get_node_hostname(wobj.api, node_id)
330                 self.delete_slice_tag(slice["name"], node_hostname, tag["tagname"], tag["value"])
331         elif api_method_name == "UpdateSliceTag":
332             tag = self.get_slice_tag(wobj.api, tag_name_or_id)
333             slice = self.get_slice(wobj.api, tag["slice_id"])
334             for node_id in slice["node_ids"]:
335                 node_hostname = self.get_node_hostname(wobj.api, tag["node_id"])
336                 self.update_slice_tag(slice, node_hostname, tag["tagname"], tag_value)
337
338         elif api_method_name == "AddNodeTag":
339             tag = self.get_tag_type(wobj.api, tag_name_or_id)
340             for node_id in node_ids:
341                 node_hostname = self.get_node_hostname(wobj.api, node_id)
342                 self.add_node_tag(node_hostname, tag["tagname"], tag_value)
343         elif api_method_name == "DeleteNodeTag":
344             node_hostname = self.get_node_hostname(wobj.api, tag["node_id"])
345             self.delete_node_tag(node_hostname, tag["tagname"], tag["value"])
346         elif api_method_name == "UpdateNodeTag":
347             tag = self.get_node_tag(wobj.api, tag_name_or_id)
348             for node_id in [tag["node_id"]]:
349                 node_hostname = self.get_node_hostname(wobj.api, tag["node_id"])
350                 self.update_node_tag(node_hostname, tag["tagname"], tag_value)
351
352         elif api_method_name == "AddInterface" or api_method_name == "UpdateInterface":
353             for node_id in node_ids:
354                 node_hostname = self.get_node_hostname(wobj.api, node_id)
355                 node_interfaces = self.get_interfaces(wobj.api, node_id)
356                 for node_interface in node_interfaces:
357                     #FIXME: Requires pyplnet changes
358                     interface_tags = self.get_interface_tags(wobj.api, node_interface["interface_tag_ids"])
359                     node_interface["interface_tags"] = interface_tags
360                 self.add_interface(node_hostname, node_interfaces)
361 #        elif api_method_name == "DeleteInterface":
362 #            node_interface =  self.get_interface(wobj.api, interface_id)
363 #            for node_id in node_interface["node_id"]:
364 #                node_hostname = self.get_node_hostname(wobj.api, node_id)
365 #                node_interfaces = self.get_interfaces(wobj.api, node_id)
366 #                for node_interface in node_interfaces:
367 #                    #FIXME: Requires pyplnet changes
368 #                    interface_tags = self.get_interface_tags(wobj.api, node_interface["interface_tag_ids"])
369 #                    node_interface["interface_tags"] = interface_tags
370 #                self.delete_interface(node_hostname, node_interfaces)
371
372         elif api_method_name == "DeleteSlice":
373             for node_id in slice["node_ids"]:
374                 node_hostname = self.get_node_hostname(wobj.api, node_id)
375                 self.delete_slice_from_node(slice["name"], node_hostname)
376         elif api_method_name == "DeletePerson":
377         #FIXME: Role
378             slice_ids = person["slice_ids"]
379             for slice_id in slice_ids:
380                 slice = self.get_slice(wobj.api, slice_id)
381                 keys = self.get_person_keys(wobj.api, slice["person_ids"])
382                 for node_id in slice["node_ids"]:
383                     node_hostname = self.get_node_hostname(wobj.api, node_id)
384                     self.delete_person_from_slice(slice["name"], node_hostname, person["email"], keys)
385         elif api_method_name == "DeleteTagType":
386         #FIXME: NodeGroups etc.
387             for slice in self.slice_ids:
388                 slice = self.get_slice(wobj.api, tag["slice_id"])
389                 for node_id in slice["node_ids"]:
390                     node_hostname = self.get_node_hostname(wobj.api, node_id)
391                     self.delete_slice_tag(slice["name"], node_hostname, tag["tagname"], tag["value"])
392
393 #        self.logit(wobj.name, args, kwargs, data, slice)
394
395 class FuncAspect_class(BaseFunc):
396     __metaclass__ = MetaAspect
397     name = "funcaspect_class"
398
399     #node_list = func.overlord.client.Client("*").list_minions()
400     #FIXME: Only control following nodes
401     node_list = ["planetlab-01.cs.princeton.edu", "planetlab-02.cs.princeton.edu", "planetlab-04.cs.princeton.edu", "planetlab-05.cs.princeton.edu"]
402
403     client = None
404
405     def __init__(self):
406         BaseFunc.__init__(self)
407
408     def write_to_log(self, line):
409         if not self.log: return
410
411         date = datetime.datetime.now().strftime("%d/%m/%y %H:%M")
412         self.log.write("%s - %s" % (date, line))
413         self.log.flush()
414
415     def ping(self, node):
416         try:
417             self.client = func.overlord.client.Client(node, timeout = 10)
418         except:
419             self.client = None
420             return False
421
422         if self.client.test.ping()[node]:
423             self.client = func.overlord.client.Client(node, timeout = 10, async = True)
424             return True
425
426         self.client = None
427         return False
428
429     def add_slice_to_node(self, slice, node, family, tags, keys):
430         self.write_to_log("Func: AddSlice: %s toNode: %s Family: %s\n" % (slice, node, family))
431
432         if node in self.node_list:
433             self.increment_revision_for_node(node)
434             if self.ping(node):
435                 self.client.nm.AddSliceToNode(slice, tags, keys)
436             else:
437                 self.write_to_log("Func: (AddSlice)Cannot access to node: %s" % node)
438
439 #        if self.ping(node):
440 #             self.client.nm.AddSliceToNode(slice, interfaces, family, tags, keys)
441 #        else:
442 #             AddToQueue
443
444     def delete_slice_from_node(self, slice, node):
445         self.write_to_log("Func: DeleteSlice: %s FromNode: %s\n" % (slice, node))
446
447         if node in self.node_list:
448             self.increment_revision_for_node(node)
449             if self.ping(node):
450                 self.client.nm.DeleteSliceFromNode(slice)
451             else:
452                 self.write_to_log("Func: (DeleteSlice)Cannot access to node: %s" % node)
453
454 #        if self.pingnode(node):
455 #             self.client.nm.DeleteSliceFromNode(slice)
456 #        else:
457 #             AddToQueue
458
459     def add_person_to_slice(self, slice, node, person, value):
460         self.write_to_log("Func: AddPerson: %s ToSlice: %s onNode: %s\n" % (person, slice, node))
461
462         if node in self.node_list:
463             self.increment_revision_for_node(node)
464             if self.ping(node):
465                 self.client.nm.AddPersonToSlice(slice, value)
466             else:
467                 self.write_to_log("Func: (AddPersonToSlice)Cannot access to node: %s" % node)
468
469 #        if self.ping(node):
470 #             self.client.nm.AddPersonToSlice(slice, value)
471 #        else:
472 #             AddToQueue
473
474     def delete_person_from_slice(self, slice, node, person, value):
475         self.write_to_log("Func: DeletePerson: %s FromSlice: %s onNode: %s\n" % (person, slice, node))
476
477         if node in self.node_list:
478             self.increment_revision_for_node(node)
479             if self.ping(node):
480                 self.client.nm.DeletePersonFromSlice(slice, value)
481             else:
482                 self.write_to_log("Func: (DeletePersonFromSlice)Cannot access to node: %s" % node)
483
484 #        if self.ping(node):
485 #             self.client.nm.DeletePersonFromSlice(slice, value)
486 #        else:
487 #             AddToQueue
488
489     def add_slice_tag(self, slice, node, tag, value):
490         self.write_to_log("Func: AddSliceTag: %s Value: %s onSlice:%s onNode: %s\n" % (tag, value, slice, node))
491
492         if node in self.node_list:
493             self.increment_revision_for_node(node)
494             if self.ping(node):
495                 self.client.nm.AddSliceTag(slice, tag, value)
496             else:
497                 self.write_to_log("Func: (AddSliceTag)Cannot access to node: %s" % node)
498
499 #        if self.ping(node):
500 #             self.client.nm.AddSliceTag(slice, tag, value)
501 #        else:
502 #             AddToQueue
503
504     def delete_slice_tag(self, slice, node, tag, value):
505         self.write_to_log("Func: DeleteSliceTag: %s Value: %s onSlice:%s onNode: %s\n" % (tag, value, slice, node))
506
507         if node in self.node_list:
508             self.increment_revision_for_node(node)
509             if self.ping(node):
510                 self.client.nm.DeleteSliceTag(slice, tag, value)
511             else:
512                 self.write_to_log("Func: (DeleteSliceTag)Cannot access to node: %s" % node)
513
514 #        if self.ping(node):
515 #             self.client.nm.DeleteSliceTag(slice, tag, value)
516 #        else:
517 #             AddToQueue
518
519     def update_slice_tag(self, slice, node, tag, value):
520         self.write_to_log("Func: UpdateSliceTag: %s Value: %s toSlice: %s onNode: %s\n" % (tag, value, slice, node))
521
522 #        client = func.overlord.client.Client(node, timeout=5, async=True)
523 #        if self.ping(node):
524 #             self.client.nm.UpdateSliceTag(slice, tag, value)
525 #        else:
526 #             AddToQueue
527
528     def add_node_tag(self, node, tag, value):
529         self.write_to_log("Func: AddNodeTag: %s Value: %s toNode: %s\n" % (tag, value, node))
530
531 #        if self.ping(node):
532 #             self.client.nm.AddNodeTag(tag, value)
533 #        else:
534 #             AddToQueue
535
536     def delete_node_tag(self, node, tag, value):
537         self.write_to_log("Func: DeleteNodeTag: %s Value: %s fromNode: %s\n" % (tag, value, node))
538
539 #        if self.ping(node):
540 #             self.client.nm.DeleteSliceTag(tag, value)
541 #        else:
542 #             AddToQueue
543
544     def update_node_tag(self, node, tag, value):
545         self.write_to_log("Func: UpdateNodeTag: %s Value: %s toNode: %s\n" % (tag, value, node))
546
547 #        if self.ping(node):
548 #             self.client.nm.UpdateNodeTag(tag, value)
549 #        else:
550 #             AddToQueue
551
552     def add_interface(self, node, value):
553         self.write_to_log("Func: AddInterface: %s toNode: %s\n" % (len(value), node))
554
555 #        if self.ping(node):
556 #             self.client.nm.AddInterface(value)
557 #        else:
558 #             AddToQueue
559
560     def delete_interface(self, node, value):
561         self.write_to_log("Func: DeleteInterface: %s toNode: %s\n" % (len(value), node))
562
563 #        if self.ping(node):
564 #             self.client.nm.DeleteInterface(value)
565 #        else:
566 #             AddToQueue
567
568     @absorb_exception
569     def increment_revision_for_node(self, node):
570         filename = "/var/www/html/func/%s" % node
571         value = 0
572
573         if os.path.exists(filename):
574             f = open(filename, "r")
575             value = int(f.read().strip())
576             f.close()
577
578         f = open(filename, "w")
579         value += 1
580         f.write("%d" % int(value))
581         f.close()
582
583     def before(self, wobj, data, *args, **kwargs):
584         BaseFunc.before(self, wobj, data, *args, **kwargs)
585
586     def after(self, wobj, data, *args, **kwargs):
587         BaseFunc.after(self, wobj, data, *args, **kwargs)
588
589 FuncAspect = FuncAspect_class