Registries/Aggregates are accessed through api object now
[sfa.git] / sfa / plc / nodes.py
1 ### $Id$
2 ### $URL$
3
4 import os
5 import time
6 import datetime
7 import sys
8 import traceback
9
10 from sfa.util.namespace import *
11 from sfa.util.rspec import *
12 from sfa.util.specdict import * 
13 from sfa.util.faults import *
14 from sfa.util.storage import *
15 from sfa.util.debug import log
16 from sfa.util.rspec import *
17 from sfa.util.specdict import * 
18 from sfa.util.policy import Policy
19
20 class Nodes(SimpleStorage):
21
22     def __init__(self, api, ttl = 1, origin_hrn=None):
23         self.api = api
24         self.ttl = ttl
25         self.threshold = None
26         path = self.api.config.SFA_DATA_DIR
27         filename = ".".join([self.api.interface, self.api.hrn, "nodes"])
28         filepath = path + os.sep + filename
29         self.nodes_file = filepath
30         SimpleStorage.__init__(self, self.nodes_file)
31         self.policy = Policy(api)
32         self.load()
33         self.origin_hrn = origin_hrn
34
35
36     def refresh(self):
37         """
38         Update the cached list of nodes
39         """
40
41         # Reload components list
42         now = datetime.datetime.now()
43         if not self.has_key('threshold') or not self.has_key('timestamp') or \
44            now > datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['threshold'], self.api.time_format))): 
45             if self.api.interface in ['aggregate']:
46                 self.refresh_nodes_aggregate()
47             elif self.api.interface in ['slicemgr']:
48                 self.refresh_nodes_smgr()
49
50     def refresh_nodes_aggregate(self):
51         rspec = RSpec()
52         rspec.parseString(self.get_rspec())
53         
54         # filter nodes according to policy
55         blist = self.policy['node_blacklist']
56         wlist = self.policy['node_whitelist']
57         rspec.filter('NodeSpec', 'name', blacklist=blist, whitelist=wlist)
58
59         # extract ifspecs from rspec to get ips'
60         ips = []
61         ifspecs = rspec.getDictsByTagName('IfSpec')
62         for ifspec in ifspecs:
63             if ifspec.has_key('addr') and ifspec['addr']:
64                 ips.append(ifspec['addr'])
65
66         # extract nodespecs from rspec to get dns names
67         hostnames = []
68         nodespecs = rspec.getDictsByTagName('NodeSpec')
69         for nodespec in nodespecs:
70             if nodespec.has_key('name') and nodespec['name']:
71                 hostnames.append(nodespec['name'])
72
73         # update timestamp and threshold
74         timestamp = datetime.datetime.now()
75         hr_timestamp = timestamp.strftime(self.api.time_format)
76         delta = datetime.timedelta(hours=self.ttl)
77         threshold = timestamp + delta
78         hr_threshold = threshold.strftime(self.api.time_format)
79
80         node_details = {}
81         node_details['rspec'] = rspec.toxml()
82         node_details['ip'] = ips
83         node_details['dns'] = hostnames
84         node_details['timestamp'] = hr_timestamp
85         node_details['threshold'] = hr_threshold
86         # save state 
87         self.update(node_details)
88         self.write()       
89  
90     def get_rspec_smgr(self, xrn = None):
91         hrn, type = urn_to_hrn(xrn)
92         # convert and threshold to ints
93         if self.has_key('timestamp') and self['timestamp']:
94             hr_timestamp = self['timestamp']
95             timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(hr_timestamp, self.api.time_format)))
96             hr_threshold = self['threshold']
97             threshold = datetime.datetime.fromtimestamp(time.mktime(time.strptime(hr_threshold, self.api.time_format)))
98         else:
99             timestamp = datetime.datetime.now()
100             hr_timestamp = timestamp.strftime(self.api.time_format)
101             delta = datetime.timedelta(hours=self.ttl)
102             threshold = timestamp + delta
103             hr_threshold = threshold.strftime(self.api.time_format)
104
105         start_time = int(timestamp.strftime("%s"))
106         end_time = int(threshold.strftime("%s"))
107         duration = end_time - start_time
108
109         aggregates = self.api.aggregates
110         rspecs = {}
111         networks = []
112         rspec = RSpec()
113         credential = self.api.getCredential()
114         origin_hrn = self.origin_hrn
115         for aggregate in aggregates:
116           if aggregate not in [self.api.auth.client_cred.get_gid_caller().get_hrn()]:
117             try:
118                 # get the rspec from the aggregate
119                 agg_rspec = aggregates[aggregate].get_resources(credential, xrn, origin_hrn)
120                 # extract the netspec from each aggregates rspec
121                 rspec.parseString(agg_rspec)
122                 networks.extend([{'NetSpec': rspec.getDictsByTagName('NetSpec')}])
123             except:
124                 # XX print out to some error log
125                 print >> log, "Error getting resources at aggregate %s" % aggregate
126                 traceback.print_exc(log)
127                 print >> log, "%s" % (traceback.format_exc())
128         # create the rspec dict
129         resources = {'networks': networks, 'start_time': start_time, 'duration': duration}
130         resourceDict = {'RSpec': resources}
131         # convert rspec dict to xml
132         rspec.parseDict(resourceDict)
133         return rspec.toxml()
134
135     def refresh_nodes_smgr(self):
136
137         rspec = RSpec(xml=self.get_rspec_smgr())        
138         # filter according to policy
139         blist = self.policy['node_blacklist']
140         wlist = self.policy['node_whitelist']    
141         rspec.filter('NodeSpec', 'name', blacklist=blist, whitelist=wlist)
142
143         # update timestamp and threshold
144         timestamp = datetime.datetime.now()
145         hr_timestamp = timestamp.strftime(self.api.time_format)
146         delta = datetime.timedelta(hours=self.ttl)
147         threshold = timestamp + delta
148         hr_threshold = threshold.strftime(self.api.time_format)
149
150         nodedict = {'rspec': rspec.toxml(),
151                     'timestamp': hr_timestamp,
152                     'threshold':  hr_threshold}
153
154         self.update(nodedict)
155         self.write()
156
157     def get_rspec(self, xrn = None):
158
159         if self.api.interface in ['slicemgr']:
160             return self.get_rspec_smgr(xrn)
161         elif self.api.interface in ['aggregate']:
162             return self.get_rspec_aggregate(xrn)     
163
164     def get_rspec_aggregate(self, xrn = None):
165         """
166         Get resource information from PLC
167         """
168         hrn, type = urn_to_hrn(xrn)
169         slicename = None
170         # Get the required nodes
171         if not hrn:
172             nodes = self.api.plshell.GetNodes(self.api.plauth, {'peer_id': None})
173             try:  linkspecs = self.api.plshell.GetLinkSpecs() # if call is supported
174             except:  linkspecs = []
175         else:
176             slicename = hrn_to_pl_slicename(hrn)
177             slices = self.api.plshell.GetSlices(self.api.plauth, [slicename])
178             if not slices:
179                 nodes = []
180             else:
181                 slice = slices[0]
182                 node_ids = slice['node_ids']
183                 nodes = self.api.plshell.GetNodes(self.api.plauth, {'peer_id': None, 'node_id': node_ids})
184
185         # Filter out whitelisted nodes
186         public_nodes = lambda n: n.has_key('slice_ids_whitelist') and not n['slice_ids_whitelist']
187             
188         # ...only if they are not already assigned to this slice.
189         if (not slicename):        
190             nodes = filter(public_nodes, nodes)
191
192         # Get all network interfaces
193         interface_ids = []
194         for node in nodes:
195             # The field name has changed in plcapi 4.3
196             if self.api.plshell_version in ['4.2']:
197                 interface_ids.extend(node['nodenetwork_ids'])
198             elif self.api.plshell_version in ['4.3']:
199                 interface_ids.extend(node['interface_ids'])
200             else:
201                 raise SfaAPIError, "Unsupported plcapi version ", \
202                                  self.api.plshell_version
203
204         if self.api.plshell_version in ['4.2']:
205             interfaces = self.api.plshell.GetNodeNetworks(self.api.plauth, interface_ids)
206         elif self.api.plshell_version in ['4.3']:
207             interfaces = self.api.plshell.GetInterfaces(self.api.plauth, interface_ids)
208         else:
209             raise SfaAPIError, "Unsupported plcapi version ", \
210                                 self.api.plshell_version 
211         interface_dict = {}
212         for interface in interfaces:
213             if self.api.plshell_version in ['4.2']:
214                 interface_dict[interface['nodenetwork_id']] = interface
215             elif self.api.plshell_version in ['4.3']:
216                 interface_dict[interface['interface_id']] = interface
217             else:
218                 raise SfaAPIError, "Unsupported plcapi version", \
219                                     self.api.plshell_version 
220
221         # join nodes with thier interfaces
222         for node in nodes:
223             node['interfaces'] = []
224             if self.api.plshell_version in ['4.2']:
225                 for nodenetwork_id in node['nodenetwork_ids']:
226                     node['interfaces'].append(interface_dict[nodenetwork_id])
227             elif self.api.plshell_version in ['4.3']:
228                 for interface_id in node['interface_ids']:
229                     node['interfaces'].append(interface_dict[interface_id])
230             else:
231                 raise SfaAPIError, "Unsupported plcapi version", \
232                                     self.api.plshell_version
233
234         # convert and threshold to ints
235         if self.has_key('timestamp') and self['timestamp']:
236             timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['timestamp'], self.api.time_format)))
237             threshold = datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['threshold'], self.api.time_format)))
238         else:
239             timestamp = datetime.datetime.now()
240             delta = datetime.timedelta(hours=self.ttl)
241             threshold = timestamp + delta
242
243         start_time = int(timestamp.strftime("%s"))
244         end_time = int(threshold.strftime("%s"))
245         duration = end_time - start_time
246
247         # create the plc dict
248         networks = [{'nodes': nodes,
249                      'name': self.api.hrn,
250                      'start_time': start_time,
251                      'duration': duration}]
252         if not hrn:
253             networks[0]['links'] = linkspecs
254         resources = {'networks': networks, 'start_time': start_time, 'duration': duration}
255
256         # convert the plc dict to an rspec dict
257         resourceDict = RSpecDict(resources)
258         # convert the rspec dict to xml
259         rspec = RSpec()
260         rspec.parseDict(resourceDict)
261         return rspec.toxml()
262