sfiapi small bugfixes.
[nepi.git] / src / nepi / util / sfiapi.py
1 # -*- coding: utf-8 -*-
2
3
4 import logging
5
6 from nepi.util.parser import sfa
7
8 ###
9 # TODO: This API is a mega hack to adapt the sfa interface to the plc interface.
10 #       The right way to implement this would be to make node.py invoke generic 
11 #       methods and to adapt the sfa and plc APIs to provide the reuired 
12 #       data.
13
14 class SFIAPI(object):
15     def __init__(self, slice_id):
16         self._slice_tags = dict()
17         self._slice_nodes = set()
18         self._all_nodes = dict()
19         self._slice_id = slice_id
20
21         self._logger = logging.getLogger('nepi.utils.sfiapi')
22         
23         self.FetchSliceInfo()
24
25     def FetchSliceInfo(self):
26         p = sfa.SFAResourcesParser()
27         import commands
28         xml = commands.getoutput("sfi.py resources")
29         try:
30             self._all_nodes = p.resources_from_xml(xml)
31             xml = commands.getoutput("sfi.py resources %s" % self._slice_id)
32             self._slice_tags, self._slice_nodes = p.slice_info_from_xml(xml)
33         except:
34             self._logger.error("Error in SFA responds: %s", xml)
35             raise
36     
37     def GetSliceNodes(self, slicename):
38         return list(self._slice_nodes)
39
40     def GetNodeInfo(self, node_id):
41         # TODO: thread-unsafe!! sanitize!
42         info = self.GetNodes(node_id)
43         tags = self.GetNodeTags(node_id=node_id, fields=('tagname','value'))
44         return info, tags
45
46     def GetSliceId(self, slicename):
47         return self._slice_id
48
49     def GetSliceVnetSysTag(self, slicename):
50         return self._slice_tags.get('vsys_net')
51
52     def GetNodeTags(self, node_id=None, fields=None, **kw):
53         nodes = self._all_nodes
54         if node_id is not None:
55             node_ids = node_id
56             if not isinstance(node_id, list):
57                 node_ids = [node_ids]
58             nodes = self._FilterByNodeId(nodes, node_ids)
59         else:
60             filters = kw.pop('filters',{})
61             if '|slice_ids' in filters:
62                 nodes = self._FilterByNodeId(nodes, self._slice_nodes)
63                 del filters['|slice_ids']
64             nodes = self._FilterByFilters(nodes, filters)
65         tagnames = kw.pop('tagname',[])
66         return self._GetTagInfo(nodes, tagnames, fields)
67
68     def GetNodes(self, nodeIdOrName=None, fields=[], **kw):
69         #TODO: filter - peer
70         nodes = self._all_nodes
71         if nodeIdOrName is not None:
72             node_ids = nodeIdOrName
73             if not isinstance(nodeIdOrName, list):
74                 node_ids = [node_ids]
75             nodes = self._FilterByNodeId(nodes, node_ids)
76         else:
77             filters = kw.pop('filters',{})
78             if '|slice_ids' in filters:
79                 nodes = self._FilterByNodeId(nodes, self._slice_nodes)
80                 del filters['|slice_ids']
81             # TODO: Remove this!! need to allow filter '>last_contact' !!!
82             for f in ['>last_contact', 'node_type', 'run_level']:
83                 if f in filters:
84                     del filters[f]
85             nodes = self._FilterByFilters(nodes, filters)
86         return self._GetNodeFieldsInfo(nodes, fields)
87     
88     def _FilterByNodeId(self, nodes, node_ids):
89         return dict((k, nodes[k]) for k in node_ids if k in nodes)
90
91     def _FilterByFilters(self, nodes, filters):
92         def has_all_tags(node_id):
93             data = nodes[node_id]
94             for name, value in filters.iteritems():
95                 if name == 'value' or name == 'tagname':
96                     tagname = filters['tagname']
97                     tagval = filters['value']
98                     if data[tagname] != tagval:
99                         return False
100                 elif name == 'node_id':
101                     node_ids = list(value)
102                     if node_id not in node_ids:
103                         return False
104                 else:
105                     #if  (name == '>last_contact' and data['lastcontact'] > value) or \
106                     if (not name in data or data[name] != value):
107                         return False
108             return True
109         return dict((k, value) for k, value in nodes.iteritems() if has_all_tags(k))
110
111     def _GetNodeFieldsInfo(self, nodes, fields):
112         result = list()
113         for k, data in nodes.iteritems():
114             if not fields:
115                 result.append(data)
116                 continue
117             r_data = dict()
118             for f in fields:
119                 if f == "node_id":
120                     value = k
121                 else:
122                     value = data[f]
123                 r_data[f] = value
124             result.append(r_data)
125         return result
126
127     def _GetTagInfo(self, nodes, tagnames, fields):
128         result = list()
129         for k, data in nodes.iteritems():
130             for name, value in data.iteritems():
131                 r_data = dict()
132                 if tagnames and name not in tagnames:
133                     continue
134                 for f in fields:
135                     if f == "node_id":
136                         val = k
137                     if f == "tagname":
138                         val = name
139                     if f == "value":
140                         val = value
141                     r_data[f] = val
142                 result.append(r_data)
143         return result
144
145     def AddSliceNodes(self, slicename, nodes=None):
146         import os, commands, tempfile
147         nodes = set(nodes)
148         nodes.update(self._slice_nodes)
149         nodes_data = dict((k, self._all_nodes[k]) for k in nodes)
150         p = sfa.SFAResourcesParser()
151         xml = p.create_slice_xml(nodes_data, self._slice_tags)
152         fh, fname = tempfile.mkstemp()
153         os.write(fh, xml)
154         os.close(fh)
155         out = commands.getoutput("sfi.py create %s %s" % (self._slice_id, fname))
156         os.remove(fname)
157         #print out
158
159 def sfiapi(slice_id):
160     api = SFIAPI(slice_id)
161     return api
162