10 from sfa.util.misc 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 from sfa.server.aggregate import Aggregates
21 class Nodes(SimpleStorage):
23 def __init__(self, api, ttl = 1, origin_gid_caller=None):
27 path = self.api.config.SFA_DATA_DIR
28 filename = ".".join([self.api.interface, self.api.hrn, "nodes"])
29 filepath = path + os.sep + filename
30 self.nodes_file = filepath
31 SimpleStorage.__init__(self, self.nodes_file)
32 self.policy = Policy(api)
34 self.origin_hrn = None
36 self.origin_hrn=origin_gid_caller.get_hrn()
41 Update the cached list of nodes
44 # Reload components list
45 now = datetime.datetime.now()
46 if not self.has_key('threshold') or not self.has_key('timestamp') or \
47 now > datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['threshold'], self.api.time_format))):
48 if self.api.interface in ['aggregate']:
49 self.refresh_nodes_aggregate()
50 elif self.api.interface in ['slicemgr']:
51 self.refresh_nodes_smgr()
53 def refresh_nodes_aggregate(self):
55 rspec.parseString(self.get_rspec())
57 # filter nodes according to policy
58 blist = self.policy['node_blacklist']
59 wlist = self.policy['node_whitelist']
60 rspec.filter('NodeSpec', 'name', blacklist=blist, whitelist=wlist)
62 # extract ifspecs from rspec to get ips'
64 ifspecs = rspec.getDictsByTagName('IfSpec')
65 for ifspec in ifspecs:
66 if ifspec.has_key('addr') and ifspec['addr']:
67 ips.append(ifspec['addr'])
69 # extract nodespecs from rspec to get dns names
71 nodespecs = rspec.getDictsByTagName('NodeSpec')
72 for nodespec in nodespecs:
73 if nodespec.has_key('name') and nodespec['name']:
74 hostnames.append(nodespec['name'])
76 # update timestamp and threshold
77 timestamp = datetime.datetime.now()
78 hr_timestamp = timestamp.strftime(self.api.time_format)
79 delta = datetime.timedelta(hours=self.ttl)
80 threshold = timestamp + delta
81 hr_threshold = threshold.strftime(self.api.time_format)
84 node_details['rspec'] = rspec.toxml()
85 node_details['ip'] = ips
86 node_details['dns'] = hostnames
87 node_details['timestamp'] = hr_timestamp
88 node_details['threshold'] = hr_threshold
90 self.update(node_details)
93 def get_remote_resources(self, hrn = None):
94 # convert and threshold to ints
95 if self.has_key('timestamp') and self['timestamp']:
96 hr_timestamp = self['timestamp']
97 timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(hr_timestamp, self.api.time_format)))
98 hr_threshold = self['threshold']
99 threshold = datetime.datetime.fromtimestamp(time.mktime(time.strptime(hr_threshold, self.api.time_format)))
101 timestamp = datetime.datetime.now()
102 hr_timestamp = timestamp.strftime(self.api.time_format)
103 delta = datetime.timedelta(hours=self.ttl)
104 threshold = timestamp + delta
105 hr_threshold = threshold.strftime(self.api.time_format)
107 start_time = int(timestamp.strftime("%s"))
108 end_time = int(threshold.strftime("%s"))
109 duration = end_time - start_time
111 aggregates = Aggregates(self.api)
115 credential = self.api.getCredential()
116 for aggregate in aggregates:
117 if aggregate not in [self.api.auth.client_cred.get_gid_caller().get_hrn()]:
119 origin_hrn = self.origin_hrn
120 # get the rspec from the aggregate
123 agg_rspec = aggregates[aggregate].get_resources(credential, hrn, request_hash, origin_hrn)
125 arg_list = [credential, hrn]
126 request_hash = self.api.key.compute_hash(arg_list)
127 agg_rspec = aggregates[aggregate].get_resources(credential, hrn, request_hash, origin_hrn)
128 # extract the netspec from each aggregates rspec
129 rspec.parseString(agg_rspec)
130 networks.extend([{'NetSpec': rspec.getDictsByTagName('NetSpec')}])
132 # XX print out to some error log
133 print >> log, "Error getting resources at aggregate %s" % aggregate
134 traceback.print_exc(log)
135 print >> log, "%s" % (traceback.format_exc())
136 # create the rspec dict
137 resources = {'networks': networks, 'start_time': start_time, 'duration': duration}
138 resourceDict = {'RSpec': resources}
139 # convert rspec dict to xml
140 rspec.parseDict(resourceDict)
143 def refresh_nodes_smgr(self):
145 rspec = self.get_remote_resources()
146 # filter according to policy
147 blist = self.policy['node_blacklist']
148 wlist = self.policy['node_whitelist']
149 rspec.filter('NodeSpec', 'name', blacklist=blist, whitelist=wlist)
151 # update timestamp and threshold
152 timestamp = datetime.datetime.now()
153 hr_timestamp = timestamp.strftime(self.api.time_format)
154 delta = datetime.timedelta(hours=self.ttl)
155 threshold = timestamp + delta
156 hr_threshold = threshold.strftime(self.api.time_format)
158 nodedict = {'rspec': rspec.toxml(),
159 'timestamp': hr_timestamp,
160 'threshold': hr_threshold}
162 self.update(nodedict)
165 def get_rspec(self, hrn = None):
167 if self.api.interface in ['slicemgr']:
168 return self.get_rspec_smgr(hrn)
169 elif self.api.interface in ['aggregate']:
170 return self.get_rspec_aggregate(hrn)
172 def get_rspec_smgr(self, hrn = None):
174 rspec = self.get_remote_resources(hrn)
177 def get_rspec_aggregate(self, hrn = None):
179 Get resource information from PLC
183 # Get the required nodes
185 nodes = self.api.plshell.GetNodes(self.api.plauth, {'peer_id': None})
186 try: linkspecs = self.api.plshell.GetLinkSpecs() # if call is supported
187 except: linkspecs = []
189 slicename = hrn_to_pl_slicename(hrn)
190 slices = self.api.plshell.GetSlices(self.api.plauth, [slicename])
195 node_ids = slice['node_ids']
196 nodes = self.api.plshell.GetNodes(self.api.plauth, {'peer_id': None, 'node_id': node_ids})
198 # Filter out whitelisted nodes
199 public_nodes = lambda n: n.has_key('slice_ids_whitelist') and not n['slice_ids_whitelist']
201 # ...only if they are not already assigned to this slice.
203 nodes = filter(public_nodes, nodes)
205 # Get all network interfaces
208 # The field name has changed in plcapi 4.3
209 if self.api.plshell_version in ['4.2']:
210 interface_ids.extend(node['nodenetwork_ids'])
211 elif self.api.plshell_version in ['4.3']:
212 interface_ids.extend(node['interface_ids'])
214 raise GeniAPIError, "Unsupported plcapi version ", \
215 self.api.plshell_version
217 if self.api.plshell_version in ['4.2']:
218 interfaces = self.api.plshell.GetNodeNetworks(self.api.plauth, interface_ids)
219 elif self.api.plshell_version in ['4.3']:
220 interfaces = self.api.plshell.GetInterfaces(self.api.plauth, interface_ids)
222 raise GeniAPIError, "Unsupported plcapi version ", \
223 self.api.plshell_version
225 for interface in interfaces:
226 if self.api.plshell_version in ['4.2']:
227 interface_dict[interface['nodenetwork_id']] = interface
228 elif self.api.plshell_version in ['4.3']:
229 interface_dict[interface['interface_id']] = interface
231 raise GeniAPIError, "Unsupported plcapi version", \
232 self.api.plshell_version
234 # join nodes with thier interfaces
236 node['interfaces'] = []
237 if self.api.plshell_version in ['4.2']:
238 for nodenetwork_id in node['nodenetwork_ids']:
239 node['interfaces'].append(interface_dict[nodenetwork_id])
240 elif self.api.plshell_version in ['4.3']:
241 for interface_id in node['interface_ids']:
242 node['interfaces'].append(interface_dict[interface_id])
244 raise GeniAPIError, "Unsupported plcapi version", \
245 self.api.plshell_version
247 # convert and threshold to ints
248 if self.has_key('timestamp') and self['timestamp']:
249 timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['timestamp'], self.api.time_format)))
250 threshold = datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['threshold'], self.api.time_format)))
252 timestamp = datetime.datetime.now()
253 delta = datetime.timedelta(hours=self.ttl)
254 threshold = timestamp + delta
256 start_time = int(timestamp.strftime("%s"))
257 end_time = int(threshold.strftime("%s"))
258 duration = end_time - start_time
260 # create the plc dict
261 networks = [{'nodes': nodes,
262 'name': self.api.hrn,
263 'start_time': start_time,
264 'duration': duration}]
266 networks[0]['links'] = linkspecs
267 resources = {'networks': networks, 'start_time': start_time, 'duration': duration}
269 # convert the plc dict to an rspec dict
270 resourceDict = RSpecDict(resources)
271 # convert the rspec dict to xml
273 rspec.parseDict(resourceDict)