6 from geni.util.misc import *
7 from geni.util.rspec import *
8 from geni.util.specdict import *
9 from geni.util.excep import *
10 from geni.util.storage import *
11 from geni.util.debug import log
12 from geni.util.rspec import *
13 from geni.util.specdict import *
14 from geni.aggregate import Aggregates
15 from geni.util.policy import Policy
17 class Nodes(SimpleStorage):
19 def __init__(self, api, ttl = 1):
23 path = self.api.config.basepath
24 filename = ".".join([self.api.interface, self.api.hrn, "nodes"])
25 filepath = path + os.sep + filename
26 self.nodes_file = filepath
27 SimpleStorage.__init__(self, self.nodes_file)
28 self.policy = Policy(api)
34 Update the cached list of nodes
37 # Reload components list
38 now = datetime.datetime.now()
39 if not self.has_key('threshold') or not self.has_key('timestamp') or \
40 now > datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['threshold'], self.api.time_format))):
41 if self.api.interface in ['aggregate']:
42 self.refresh_nodes_aggregate()
43 elif self.api.interface in ['slicemgr']:
44 self.refresh_nodes_smgr()
47 def refresh_nodes_aggregate(self):
49 rspec.parseString(self.get_rspec())
51 # filter nodes according to policy
52 blist = self.policy['node_blacklist']
53 wlist = self.policy['node_whitelist']
54 rspec.filter('NodeSpec', 'name', blacklist=blist, whitelist=wlist)
56 # extract ifspecs from rspec to get ips'
58 ifspecs = rspec.getDictsByTagName('IfSpec')
59 for ifspec in ifspecs:
60 if ifspec.has_key('addr') and ifspec['addr']:
61 ips.append(ifspec['addr'])
63 # extract nodespecs from rspec to get dns names
65 nodespecs = rspec.getDictsByTagName('NodeSpec')
66 for nodespec in nodespecs:
67 if nodespec.has_key('name') and nodespec['name']:
68 hostnames.append(nodespec['name'])
70 # update timestamp and threshold
71 timestamp = datetime.datetime.now()
72 hr_timestamp = timestamp.strftime(self.api.time_format)
73 delta = datetime.timedelta(hours=self.ttl)
74 threshold = timestamp + delta
75 hr_threshold = threshold.strftime(self.api.time_format)
78 node_details['rspec'] = rspec.toxml()
79 node_details['ip'] = ips
80 node_details['dns'] = hostnames
81 node_details['timestamp'] = hr_timestamp
82 node_details['threshold'] = hr_threshold
84 self.update(node_details)
87 def refresh_nodes_smgr(self):
88 # convert and threshold to ints
89 if self.has_key('timestamp') and self['timestamp']:
90 hr_timestamp = self['timestamp']
91 timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(hr_timestamp, self.api.time_format)))
92 hr_threshold = self['threshold']
93 threshold = datetime.datetime.fromtimestamp(time.mktime(time.strptime(hr_threshold, self.api.time_format)))
95 timestamp = datetime.datetime.now()
96 hr_timestamp = timestamp.strftime(self.api.time_format)
97 delta = datetime.timedelta(hours=self.ttl)
98 threshold = timestamp + delta
99 hr_threshold = threshold.strftime(self.api.time_format)
101 start_time = int(timestamp.strftime("%s"))
102 end_time = int(threshold.strftime("%s"))
103 duration = end_time - start_time
105 aggregates = Aggregates(self.api)
109 credential = self.api.getCredential()
110 for aggregate in aggregates:
112 # get the rspec from the aggregate
113 agg_rspec = aggregates[aggregate].get_resources(credential)
114 # extract the netspec from each aggregates rspec
115 rspec.parseString(agg_rspec)
116 networks.extend([{'NetSpec': rspec.getDictsByTagName('NetSpec')}])
119 # XX print out to some error log
120 print >> log, "Error calling list nodes at aggregate %s" % aggregate
121 # create the rspec dict
122 resources = {'networks': networks, 'start_time': start_time, 'duration': duration}
123 resourceDict = {'Rspec': resources}
124 # convert rspec dict to xml
125 rspec.parseDict(resourceDict)
127 # filter according to policy
128 blist = self.policy['node_blacklist']
129 wlist = self.policy['node_whitelist']
130 rspec.filter('NodeSpec', 'name', blacklist=blist, whitelist=wlist)
132 # update timestamp and threshold
133 timestamp = datetime.datetime.now()
134 hr_timestamp = timestamp.strftime(self.api.time_format)
135 delta = datetime.timedelta(hours=self.ttl)
136 threshold = timestamp + delta
137 hr_threshold = threshold.strftime(self.api.time_format)
139 nodedict = {'rspec': rspec.toxml(),
140 'timestamp': hr_timestamp,
141 'threshold': hr_threshold}
143 self.update(nodedict)
147 def get_rspec(self, hrn = None):
149 Get resource information from PLC
152 # Get the required nodes
154 nodes = self.api.plshell.GetNodes(self.api.plauth, {'peer_id': None})
155 try: linkspecs = self.api.plshell.GetLinkSpecs() # if call is supported
156 except: linkspecs = []
158 slicename = hrn_to_pl_slicename(hrn)
159 slices = self.api.plshell.GetSlices(self.api.plauth, [slicename])
164 node_ids = slice['node_ids']
165 nodes = self.api.plshell.GetNodes(self.api.plauth, {'peer_id': None, 'node_ids': node_ids})
167 # Filter out whitelisted nodes
168 public_nodes = lambda n: n.has_key('slice_ids_whitelist') and not n['slice_ids_whitelist']
169 nodes = filter(public_nodes, nodes)
171 # Get all network interfaces
174 # The field name has changed in plcapi 4.3
175 if self.api.plshell_version in ['4.2']:
176 interface_ids.extend(node['nodenetwork_ids'])
177 elif self.api.plshell_version in ['4.3']:
178 interface_ids.extend(node['interface_ids'])
180 raise GeniAPIError, "Unsupported plcapi version ", \
181 self.api.plshell_version
183 if self.api.plshell_version in ['4.2']:
184 interfaces = self.api.plshell.GetNodeNetworks(self.api.plauth, interface_ids)
185 elif self.api.plshell_version in ['4.3']:
186 interfaces = self.api.plshell.GetInterfaces(self.api.plauth, interface_ids)
188 raise GeniAPIError, "Unsupported plcapi version ", \
189 self.api.plshell_version
191 for interface in interfaces:
192 if self.api.plshell_version in ['4.2']:
193 interface_dict[interface['nodenetwork_id']] = interface
194 elif self.api.plshell_version in ['4.3']:
195 interface_dict[interface['interface_id']] = interface
197 raise GeniAPIError, "Unsupported plcapi version", \
198 self.api.plshell_version
200 # join nodes with thier interfaces
202 node['interfaces'] = []
203 if self.api.plshell_version in ['4.2']:
204 for nodenetwork_id in node['nodenetwork_ids']:
205 node['interfaces'].append(interface_dict[nodenetwork_id])
206 elif self.api.plshell_version in ['4.3']:
207 for interface_id in node['interface_ids']:
208 node['interfaces'].append(interface_dict[interface_id])
210 raise GeniAPIError, "Unsupported plcapi version", \
211 self.api.plshell_version
213 # convert and threshold to ints
214 if self.has_key('timestamp') and self['timestamp']:
215 timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['timestamp'], self.api.time_format)))
216 threshold = datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['threshold'], self.api.time_format)))
218 timestamp = datetime.datetime.now()
219 delta = datetime.timedelta(hours=self.ttl)
220 threshold = timestamp + delta
222 start_time = int(timestamp.strftime("%s"))
223 end_time = int(threshold.strftime("%s"))
224 duration = end_time - start_time
226 # create the plc dict
227 networks = [{'nodes': nodes,
228 'name': self.api.hrn,
229 'start_time': start_time,
230 'duration': duration}]
232 networks[0]['links'] = linkspecs
233 resources = {'networks': networks, 'start_time': start_time, 'duration': duration}
235 # convert the plc dict to an rspec dict
236 resourceDict = RspecDict(resources)
237 # convert the rspec dict to xml
239 rspec.parseDict(resourceDict)