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