2 from collections import defaultdict
3 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn, get_authority, get_leaf
4 from sfa.util.sfatime import utcparse, datetime_to_string
5 from sfa.util.sfalogging import logger
6 from sfa.util.faults import SliverDoesNotExist
7 from sfa.rspecs.rspec import RSpec
8 from sfa.rspecs.elements.hardware_type import HardwareType
9 from sfa.rspecs.elements.node import NodeElement
10 from sfa.rspecs.elements.link import Link
11 from sfa.rspecs.elements.sliver import Sliver
12 from sfa.rspecs.elements.login import Login
13 from sfa.rspecs.elements.location import Location
14 from sfa.rspecs.elements.interface import Interface
15 from sfa.rspecs.elements.services import ServicesElement
16 from sfa.rspecs.elements.pltag import PLTag
17 from sfa.rspecs.elements.lease import Lease
18 from sfa.rspecs.elements.granularity import Granularity
19 from sfa.rspecs.version_manager import VersionManager
21 from sfa.planetlab.plxrn import PlXrn, hostname_to_urn
22 from sfa.planetlab.vlink import get_tc_rate
23 from sfa.planetlab.topology import Topology
24 from sfa.storage.model import SliverAllocation
31 def __init__(self, driver):
34 def get_nodes(self, options=None):
35 if options is None: options={}
36 filter = {'peer_id': None}
37 geni_available = options.get('geni_available')
38 if geni_available == True:
39 filter['boot_state'] = 'boot'
40 nodes = self.driver.shell.GetNodes(filter)
44 def get_sites(self, filter=None):
45 if filter is None: filter={}
47 for site in self.driver.shell.GetSites(filter):
48 sites[site['site_id']] = site
51 def get_interfaces(self, filter=None):
52 if filter is None: filter={}
54 for interface in self.driver.shell.GetInterfaces(filter):
56 if interface['bwlimit']:
57 interface['bwlimit'] = str(int(interface['bwlimit'])/1000)
58 interfaces[interface['interface_id']] = interface
61 def get_links(self, sites, nodes, interfaces):
65 for (site_id1, site_id2) in topology:
66 site_id1 = int(site_id1)
67 site_id2 = int(site_id2)
69 if not site_id1 in sites or site_id2 not in sites:
71 site1 = sites[site_id1]
72 site2 = sites[site_id2]
74 site1_hrn = self.driver.hrn + '.' + site1['login_base']
75 site2_hrn = self.driver.hrn + '.' + site2['login_base']
77 for s1_node_id in site1['node_ids']:
78 for s2_node_id in site2['node_ids']:
79 if s1_node_id not in nodes or s2_node_id not in nodes:
81 node1 = nodes[s1_node_id]
82 node2 = nodes[s2_node_id]
84 # just get first interface of the first node
85 if1_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node1['node_id']))
86 if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
87 if2_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node2['node_id']))
88 if2_ipv4 = interfaces[node2['interface_ids'][0]]['ip']
90 if1 = Interface({'component_id': if1_xrn.urn, 'ipv4': if1_ipv4} )
91 if2 = Interface({'component_id': if2_xrn.urn, 'ipv4': if2_ipv4} )
94 link = Link({'capacity': '1000000', 'latency': '0', 'packet_loss': '0', 'type': 'ipv4'})
95 link['interface1'] = if1
96 link['interface2'] = if2
97 link['component_name'] = "%s:%s" % (site1['login_base'], site2['login_base'])
98 link['component_id'] = PlXrn(auth=self.driver.hrn, interface=link['component_name']).get_urn()
99 link['component_manager_id'] = hrn_to_urn(self.driver.hrn, 'authority+am')
104 def get_node_tags(self, filter=None):
105 if filter is None: filter={}
107 for node_tag in self.driver.shell.GetNodeTags(filter):
108 node_tags[node_tag['node_tag_id']] = node_tag
111 def get_pl_initscripts(self, filter=None):
112 if filter is None: filter={}
114 filter.update({'enabled': True})
115 for initscript in self.driver.shell.GetInitScripts(filter):
116 pl_initscripts[initscript['initscript_id']] = initscript
117 return pl_initscripts
119 def get_slivers(self, urns, options=None):
120 if options is None: options={}
127 if xrn.type == 'sliver':
128 # id: slice_id-node_id
130 sliver_id_parts = xrn.get_sliver_id_parts()
131 slice_id = int(sliver_id_parts[0])
132 node_id = int(sliver_id_parts[1])
133 slice_ids.add(slice_id)
134 node_ids.append(node_id)
138 slice_hrn = xrn.get_hrn()
141 filter['peer_id'] = None
143 filter['slice_id'] = list(slice_ids)
145 all_slices = self.driver.shell.GetSlices(filter, ['slice_id', 'name', 'hrn', 'person_ids', 'node_ids', 'slice_tag_ids', 'expires'])
147 slices = [slice for slice in all_slices if slice['hrn'] == slice_hrn]
154 slice['hrn'] = slice_hrn
160 person_ids.extend(slice['person_ids'])
162 persons = self.driver.shell.GetPersons(person_ids)
167 for person in persons:
168 key_ids.extend(person['key_ids'])
171 key_list = self.driver.shell.GetKeys(key_ids)
173 keys[key['key_id']] = key
175 # construct user key info
177 for person in persons:
178 person_urn = hrn_to_urn(self.driver.shell.GetPersonHrn(int(person['person_id'])), 'user')
180 'login': slice['name'],
181 'user_urn': person_urn,
182 'keys': [keys[k_id]['key'] for k_id in person['key_ids'] if k_id in keys]
187 node_ids = [node_id for node_id in node_ids if node_id in slice['node_ids']]
188 slice['node_ids'] = node_ids
189 tags_dict = self.get_slice_tags(slice)
190 nodes_dict = self.get_slice_nodes(slice, options)
192 for node in nodes_dict.values():
194 node['tags'] = tags_dict[node['node_id']]
195 sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
196 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
197 node['urn'] = node['sliver_id']
198 node['services_user'] = users
202 def node_to_rspec_node(self, node, sites, interfaces, node_tags, pl_initscripts=None, grain=None, options=None):
203 if pl_initscripts is None: pl_initscripts=[]
204 if options is None: options={}
205 rspec_node = NodeElement()
206 # xxx how to retrieve site['login_base']
207 site=sites[node['site_id']]
208 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
209 rspec_node['component_name'] = node['hostname']
210 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
211 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
212 # do not include boot state (<available> element) in the manifest rspec
213 rspec_node['boot_state'] = node['boot_state']
214 if node['boot_state'] == 'boot':
215 rspec_node['available'] = 'true'
217 rspec_node['available'] = 'false'
219 #distinguish between Shared and Reservable nodes
220 if node['node_type'] == 'reservable':
221 rspec_node['exclusive'] = 'true'
223 rspec_node['exclusive'] = 'false'
225 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
226 HardwareType({'name': 'pc'})]
227 # only doing this because protogeni rspec needs
228 # to advertise available initscripts
229 rspec_node['pl_initscripts'] = pl_initscripts.values()
230 # add site/interface info to nodes.
231 # assumes that sites, interfaces and tags have already been prepared.
232 if site['longitude'] and site['latitude']:
233 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
234 rspec_node['location'] = location
236 granularity = Granularity({'grain': grain})
237 rspec_node['granularity'] = granularity
238 rspec_node['interfaces'] = []
240 for if_id in node['interface_ids']:
241 interface = Interface(interfaces[if_id])
242 interface['ipv4'] = interface['ip']
243 interface['component_id'] = PlXrn(auth=self.driver.hrn,
244 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
245 # interfaces in the manifest need a client id
247 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
248 rspec_node['interfaces'].append(interface)
250 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids'] if tag_id in node_tags]
251 rspec_node['tags'] = tags
254 def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, \
255 pl_initscripts, sliver_allocations):
256 # get the granularity in second for the reservation system
257 grain = self.driver.shell.GetLeaseGranularity()
258 rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
259 # xxx how to retrieve site['login_base']
260 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
261 # remove interfaces from manifest
262 rspec_node['interfaces'] = []
264 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
265 'name': sliver['name'],
266 'type': 'plab-vserver',
268 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
269 if sliver['urn'] in sliver_allocations:
270 rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
271 if sliver_allocations[sliver['urn']].component_id:
272 rspec_node['component_id'] = sliver_allocations[sliver['urn']].component_id
273 rspec_node['slivers'] = [rspec_sliver]
275 # slivers always provide the ssh service
276 login = Login({'authentication': 'ssh-keys',
277 'hostname': sliver['hostname'],
279 'username': sliver['name'],
280 'login': sliver['name']
282 service = ServicesElement({'login': login,
283 'services_user': sliver['services_user']})
284 rspec_node['services'] = [service]
287 def get_slice_tags(self, slice):
289 slice_tag_ids.extend(slice['slice_tag_ids'])
290 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
292 tags_dict = defaultdict(list)
294 tags_dict[tag['node_id']] = tag
297 def get_slice_nodes(self, slice, options=None):
298 if options is None: options={}
300 filter = {'peer_id': None}
302 if slice and slice.get('node_ids'):
303 filter['node_id'] = slice['node_ids']
305 # there are no nodes to look up
307 tags_filter=filter.copy()
308 geni_available = options.get('geni_available')
309 if geni_available == True:
310 filter['boot_state'] = 'boot'
311 nodes = self.driver.shell.GetNodes(filter)
313 nodes_dict[node['node_id']] = node
316 def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations=None):
317 if sliver_allocations is None: sliver_allocations={}
318 if rspec_node['sliver_id'] in sliver_allocations:
319 # set sliver allocation and operational status
320 sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
321 if sliver_allocation:
322 allocation_status = sliver_allocation.allocation_state
323 if allocation_status == 'geni_allocated':
324 op_status = 'geni_pending_allocation'
325 elif allocation_status == 'geni_provisioned':
326 if rspec_node['boot_state'] == 'boot':
327 op_status = 'geni_ready'
329 op_status = 'geni_failed'
331 op_status = 'geni_unknown'
333 allocation_status = 'geni_unallocated'
335 allocation_status = 'geni_unallocated'
336 op_status = 'geni_failed'
338 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
339 'geni_expires': rspec_node['expires'],
340 'geni_allocation_status' : allocation_status,
341 'geni_operational_status': op_status,
346 def get_leases(self, slice=None, options=None):
347 if options is None: options={}
349 now = int(time.time())
351 filter.update({'clip':now})
353 filter.update({'name':slice['name']})
354 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
355 leases = self.driver.shell.GetLeases(filter)
356 grain = self.driver.shell.GetLeaseGranularity()
360 site_ids.append(lease['site_id'])
363 sites_dict = self.get_sites({'site_id': site_ids})
368 rspec_lease = Lease()
370 # xxx how to retrieve site['login_base']
371 site_id=lease['site_id']
372 site=sites_dict[site_id]
374 rspec_lease['component_id'] = hrn_to_urn(self.driver.shell.GetNodeHrn(lease['hostname']), 'node')
375 slice_hrn = self.driver.shell.GetSliceHrn(lease['slice_id'])
376 slice_urn = hrn_to_urn(slice_hrn, 'slice')
377 rspec_lease['slice_id'] = slice_urn
378 rspec_lease['start_time'] = lease['t_from']
379 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
380 rspec_leases.append(rspec_lease)
384 def list_resources(self, version = None, options=None):
385 if options is None: options={}
387 version_manager = VersionManager()
388 version = version_manager.get_version(version)
389 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
390 rspec = RSpec(version=rspec_version, user_options=options)
392 if not options.get('list_leases') or options['list_leases'] != 'leases':
394 nodes = self.get_nodes(options)
400 site_ids.append(node['site_id'])
401 interface_ids.extend(node['interface_ids'])
402 tag_ids.extend(node['node_tag_ids'])
403 nodes_dict[node['node_id']] = node
404 sites = self.get_sites({'site_id': site_ids})
405 interfaces = self.get_interfaces({'interface_id':interface_ids})
406 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
407 pl_initscripts = self.get_pl_initscripts()
408 # convert nodes to rspec nodes
411 rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
412 rspec_nodes.append(rspec_node)
413 rspec.version.add_nodes(rspec_nodes)
416 links = self.get_links(sites, nodes_dict, interfaces)
417 rspec.version.add_links(links)
419 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
420 leases = self.get_leases()
421 rspec.version.add_leases(leases)
425 def describe(self, urns, version=None, options=None):
426 if options is None: options={}
427 version_manager = VersionManager()
428 version = version_manager.get_version(version)
429 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
430 rspec = RSpec(version=rspec_version, user_options=options)
434 slivers = self.get_slivers(urns, options)
436 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
438 rspec_expires = datetime_to_string(utcparse(time.time()))
439 rspec.xml.set('expires', rspec_expires)
441 # lookup the sliver allocations
443 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
444 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
445 sliver_allocations = self.driver.api.dbsession().query(SliverAllocation).filter(constraint)
446 sliver_allocation_dict = {}
447 for sliver_allocation in sliver_allocations:
448 geni_urn = sliver_allocation.slice_urn
449 sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
451 if not options.get('list_leases') or options['list_leases'] != 'leases':
457 for sliver in slivers:
458 site_ids.append(sliver['site_id'])
459 interface_ids.extend(sliver['interface_ids'])
460 tag_ids.extend(sliver['node_tag_ids'])
461 nodes_dict[sliver['node_id']] = sliver
462 sites = self.get_sites({'site_id': site_ids})
463 interfaces = self.get_interfaces({'interface_id':interface_ids})
464 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
465 pl_initscripts = self.get_pl_initscripts()
467 for sliver in slivers:
468 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
470 rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags,
471 pl_initscripts, sliver_allocation_dict)
472 # manifest node element shouldn't contain available attribute
473 rspec_node.pop('available')
474 rspec_nodes.append(rspec_node)
475 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
476 geni_slivers.append(geni_sliver)
477 rspec.version.add_nodes(rspec_nodes)
479 # add sliver defaults
480 #default_sliver = slivers.get(None, [])
482 # default_sliver_attribs = default_sliver.get('tags', [])
483 # for attrib in default_sliver_attribs:
484 # rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
487 links = self.get_links(sites, nodes_dict, interfaces)
488 rspec.version.add_links(links)
490 if not options.get('list_leases') or options['list_leases'] != 'resources':
492 leases = self.get_leases(slivers[0])
493 rspec.version.add_leases(leases)
496 return {'geni_urn': geni_urn,
497 'geni_rspec': rspec.toxml(),
498 'geni_slivers': geni_slivers}