3 from sfa.util.faults import MissingSfaInfo, UnknownSfaType, \
4 RecordNotFound, SfaNotImplemented, SliverDoesNotExist, SearchFailed, \
5 UnsupportedOperation, Forbidden
6 from sfa.util.sfalogging import logger
7 from sfa.util.defaultdict import defaultdict
8 from sfa.util.sfatime import utcparse, datetime_to_string, datetime_to_epoch
9 from sfa.util.xrn import Xrn, hrn_to_urn, get_leaf
10 from sfa.util.cache import Cache
12 # one would think the driver should not need to mess with the SFA db, but..
13 from sfa.storage.model import RegRecord, SliverAllocation
14 from sfa.trust.credential import Credential
16 # used to be used in get_ticket
17 #from sfa.trust.sfaticket import SfaTicket
18 from sfa.rspecs.version_manager import VersionManager
19 from sfa.rspecs.rspec import RSpec
21 # the driver interface, mostly provides default behaviours
22 from sfa.managers.driver import Driver
23 from sfa.planetlab.plshell import PlShell
24 import sfa.planetlab.peers as peers
25 from sfa.planetlab.plaggregate import PlAggregate
26 from sfa.planetlab.plslices import PlSlices
27 from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, xrn_to_hostname, top_auth, hash_loginbase
30 def list_to_dict(recs, key):
32 convert a list of dictionaries into a dictionary keyed on the
33 specified dictionary key
35 return dict ( [ (rec[key],rec) for rec in recs ] )
38 # PlShell is just an xmlrpc serverproxy where methods
39 # can be sent as-is; it takes care of authentication
40 # from the global config
42 class PlDriver (Driver):
44 # the cache instance is a class member so it survives across incoming requests
47 def __init__ (self, api):
48 Driver.__init__ (self, api)
50 self.shell = PlShell (config)
52 if config.SFA_AGGREGATE_CACHING:
53 if PlDriver.cache is None:
54 PlDriver.cache = Cache()
55 self.cache = PlDriver.cache
57 def sliver_to_slice_xrn(self, xrn):
58 sliver_id_parts = Xrn(xrn).get_sliver_id_parts()
61 filter['slice_id'] = int(sliver_id_parts[0])
63 fliter['name'] = sliver_id_parts[0]
64 slices = self.shell.GetSlices(filter)
66 raise Forbidden("Unable to locate slice record for sliver: %s" % xrn)
68 slice_xrn = PlXrn(auth=self.hrn, slicename=slice['name'])
71 def check_sliver_credentials(self, creds, urns):
72 # build list of cred object hrns
75 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
76 slice_cred_names.append(PlXrn(xrn=slice_cred_hrn).pl_slicename())
78 # look up slice name of slivers listed in urns arg
81 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
83 slice_ids.append(int(sliver_id_parts[0]))
88 raise Forbidden("sliver urn not provided")
90 slices = self.shell.GetSlices(slice_ids)
91 sliver_names = [slice['name'] for slice in slices]
93 # make sure we have a credential for every specified sliver ierd
94 for sliver_name in sliver_names:
95 if sliver_name not in slice_cred_names:
96 msg = "Valid credential not found for target: %s" % sliver_name
99 ########################################
100 ########## registry oriented
101 ########################################
103 def augment_records_with_testbed_info (self, sfa_records):
104 return self.fill_record_info (sfa_records)
107 def register (self, sfa_record, hrn, pub_key):
108 type = sfa_record['type']
109 pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
111 if type == 'authority':
112 sites = self.shell.GetSites({'peer_id': None, 'login_base': pl_record['login_base']})
114 # xxx when a site gets registered through SFA we need to set its max_slices
115 if 'max_slices' not in pl_record:
116 pl_record['max_slices']=2
117 pointer = self.shell.AddSite(pl_record)
118 self.shell.SetSiteHrn(int(pointer), hrn)
120 pointer = sites[0]['site_id']
122 elif type == 'slice':
123 acceptable_fields=['url', 'instantiation', 'name', 'description']
124 for key in pl_record.keys():
125 if key not in acceptable_fields:
127 slices = self.shell.GetSlices({'peer_id': None, 'name': pl_record['name']})
129 if not pl_record.get('url', None) or not pl_record.get('description', None):
130 pl_record['url'] = hrn
131 pl_record['description'] = hrn
133 pointer = self.shell.AddSlice(pl_record)
134 self.shell.SetSliceHrn(int(pointer), hrn)
136 pointer = slices[0]['slice_id']
139 persons = self.shell.GetPersons({'peer_id': None, 'email': sfa_record['email']})
141 for key in ['first_name','last_name']:
142 if key not in sfa_record: sfa_record[key]='*from*sfa*'
143 # AddPerson does not allow everything to be set
144 can_add = ['first_name', 'last_name', 'title','email', 'password', 'phone', 'url', 'bio']
145 add_person_dict=dict ( [ (k,sfa_record[k]) for k in sfa_record if k in can_add ] )
146 pointer = self.shell.AddPerson(add_person_dict)
147 self.shell.SetPersonHrn(int(pointer), hrn)
149 pointer = persons[0]['person_id']
151 if 'enabled' in sfa_record and sfa_record['enabled']:
152 self.shell.UpdatePerson(pointer, {'enabled': sfa_record['enabled']})
153 # add this person to the site
154 login_base = get_leaf(sfa_record['authority'])
155 self.shell.AddPersonToSite(pointer, login_base)
157 # What roles should this user have?
159 if 'roles' in sfa_record:
160 # if specified in xml, but only low-level roles
161 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
162 # at least user if no other cluse could be found
166 self.shell.AddRoleToPerson(role, pointer)
169 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
172 login_base = PlXrn(xrn=sfa_record['authority'],type='authority').pl_login_base()
173 nodes = self.shell.GetNodes({'peer_id': None, 'hostname': pl_record['hostname']})
175 pointer = self.shell.AddNode(login_base, pl_record)
176 self.shell.SetNodeHrn(int(pointer), hrn)
178 pointer = nodes[0]['node_id']
183 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
184 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
185 pointer = old_sfa_record['pointer']
186 type = old_sfa_record['type']
187 new_key_pointer = None
189 # new_key implemented for users only
190 if new_key and type not in [ 'user' ]:
191 raise UnknownSfaType(type)
193 if (type == "authority"):
194 self.shell.UpdateSite(pointer, new_sfa_record)
195 self.shell.SetSiteHrn(pointer, hrn)
197 elif type == "slice":
198 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
199 if 'name' in pl_record:
200 pl_record.pop('name')
201 self.shell.UpdateSlice(pointer, pl_record)
202 self.shell.SetSliceHrn(pointer, hrn)
205 # SMBAKER: UpdatePerson only allows a limited set of fields to be
206 # updated. Ideally we should have a more generic way of doing
207 # this. I copied the field names from UpdatePerson.py...
209 all_fields = new_sfa_record
210 for key in all_fields.keys():
211 if key in ['first_name', 'last_name', 'title', 'email',
212 'password', 'phone', 'url', 'bio', 'accepted_aup',
214 update_fields[key] = all_fields[key]
215 # when updating a user, we always get a 'email' field at this point
216 # this is because 'email' is a native field in the RegUser object...
217 if 'email' in update_fields and not update_fields['email']:
218 del update_fields['email']
219 self.shell.UpdatePerson(pointer, update_fields)
220 self.shell.SetPersonHrn(pointer, hrn)
223 # must check this key against the previous one if it exists
224 persons = self.shell.GetPersons({'peer_id': None, 'person_id': pointer}, ['key_ids'])
226 keys = person['key_ids']
227 keys = self.shell.GetKeys(person['key_ids'])
231 if new_key == key['key']:
233 new_key_pointer = key['key_id']
236 new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
239 self.shell.UpdateNode(pointer, new_sfa_record)
241 return (pointer, new_key_pointer)
245 def remove (self, sfa_record):
246 type=sfa_record['type']
247 pointer=sfa_record['pointer']
249 persons = self.shell.GetPersons({'peer_id': None, 'person_id': pointer})
250 # only delete this person if he has site ids. if he doesnt, it probably means
251 # he was just removed from a site, not actually deleted
252 if persons and persons[0]['site_ids']:
253 self.shell.DeletePerson(pointer)
254 elif type == 'slice':
255 if self.shell.GetSlices({'peer_id': None, 'slice_id': pointer}):
256 self.shell.DeleteSlice(pointer)
258 if self.shell.GetNodes({'peer_id': None, 'node_id': pointer}):
259 self.shell.DeleteNode(pointer)
260 elif type == 'authority':
261 if self.shell.GetSites({'peer_id': None, 'site_id': pointer}):
262 self.shell.DeleteSite(pointer)
271 # Convert SFA fields to PLC fields for use when registering or updating
272 # registry record in the PLC database
275 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
280 pl_record["name"] = hrn_to_pl_slicename(hrn)
281 if "instantiation" in sfa_record:
282 pl_record['instantiation']=sfa_record['instantiation']
284 pl_record["instantiation"] = "plc-instantiated"
285 if "url" in sfa_record:
286 pl_record["url"] = sfa_record["url"]
287 if "description" in sfa_record:
288 pl_record["description"] = sfa_record["description"]
289 if "expires" in sfa_record:
290 date = utcparse(sfa_record['expires'])
291 expires = datetime_to_epoch(date)
292 pl_record["expires"] = expires
295 if not "hostname" in pl_record:
296 # fetch from sfa_record
297 if "hostname" not in sfa_record:
298 raise MissingSfaInfo("hostname")
299 pl_record["hostname"] = sfa_record["hostname"]
300 if "model" in sfa_record:
301 pl_record["model"] = sfa_record["model"]
303 pl_record["model"] = "geni"
305 elif type == "authority":
306 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
307 if "name" not in sfa_record:
308 pl_record["name"] = hrn
309 if "abbreviated_name" not in sfa_record:
310 pl_record["abbreviated_name"] = hrn
311 if "enabled" not in sfa_record:
312 pl_record["enabled"] = True
313 if "is_public" not in sfa_record:
314 pl_record["is_public"] = True
319 def fill_record_info(self, records):
321 Given a (list of) SFA record, fill in the PLC specific
322 and SFA specific fields in the record.
324 if not isinstance(records, list):
327 self.fill_record_pl_info(records)
328 self.fill_record_hrns(records)
329 self.fill_record_sfa_info(records)
332 def fill_record_pl_info(self, records):
334 Fill in the planetlab specific fields of a SFA record. This
335 involves calling the appropriate PLC method to retrieve the
336 database record for the object.
338 @param record: record to fill in field (in/out param)
341 node_ids, site_ids, slice_ids = [], [], []
342 person_ids, key_ids = [], []
343 type_map = {'node': node_ids, 'authority': site_ids,
344 'slice': slice_ids, 'user': person_ids}
346 for record in records:
347 for type in type_map:
348 if type == record['type']:
349 type_map[type].append(record['pointer'])
352 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
354 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids})
355 nodes = list_to_dict(node_list, 'node_id')
357 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids})
358 sites = list_to_dict(site_list, 'site_id')
360 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids})
361 slices = list_to_dict(slice_list, 'slice_id')
363 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids})
364 persons = list_to_dict(person_list, 'person_id')
365 for person in persons:
366 key_ids.extend(persons[person]['key_ids'])
368 pl_records = {'node': nodes, 'authority': sites,
369 'slice': slices, 'user': persons}
372 key_list = self.shell.GetKeys(key_ids)
373 keys = list_to_dict(key_list, 'key_id')
376 for record in records:
377 # records with pointer==-1 do not have plc info.
378 # for example, the top level authority records which are
379 # authorities, but not PL "sites"
380 if record['pointer'] == -1:
383 for type in pl_records:
384 if record['type'] == type:
385 if record['pointer'] in pl_records[type]:
386 record.update(pl_records[type][record['pointer']])
389 if record['type'] == 'user':
390 if 'key_ids' not in record:
391 logger.info("user record has no 'key_ids' - need to import from myplc ?")
393 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
394 record['keys'] = pubkeys
398 def fill_record_hrns(self, records):
400 convert pl ids to hrns
404 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
405 for record in records:
406 if 'site_id' in record:
407 site_ids.append(record['site_id'])
408 if 'site_ids' in record:
409 site_ids.extend(record['site_ids'])
410 if 'person_ids' in record:
411 person_ids.extend(record['person_ids'])
412 if 'slice_ids' in record:
413 slice_ids.extend(record['slice_ids'])
414 if 'node_ids' in record:
415 node_ids.extend(record['node_ids'])
418 slices, persons, sites, nodes = {}, {}, {}, {}
420 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids}, ['site_id', 'login_base'])
421 sites = list_to_dict(site_list, 'site_id')
423 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids}, ['person_id', 'email'])
424 persons = list_to_dict(person_list, 'person_id')
426 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids}, ['slice_id', 'name'])
427 slices = list_to_dict(slice_list, 'slice_id')
429 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids}, ['node_id', 'hostname'])
430 nodes = list_to_dict(node_list, 'node_id')
432 # convert ids to hrns
433 for record in records:
434 # get all relevant data
435 type = record['type']
436 pointer = record['pointer']
442 if 'site_id' in record:
443 site = sites[record['site_id']]
444 login_base = site['login_base']
445 record['site'] = ".".join([auth_hrn, login_base])
446 if 'person_ids' in record:
447 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
448 if person_id in persons]
449 usernames = [email.split('@')[0] for email in emails]
450 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
451 record['persons'] = person_hrns
452 if 'slice_ids' in record:
453 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
454 if slice_id in slices]
455 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
456 record['slices'] = slice_hrns
457 if 'node_ids' in record:
458 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
460 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
461 record['nodes'] = node_hrns
462 if 'site_ids' in record:
463 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
465 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
466 record['sites'] = site_hrns
468 if 'expires' in record:
469 date = utcparse(record['expires'])
470 datestring = datetime_to_string(date)
471 record['expires'] = datestring
475 def fill_record_sfa_info(self, records):
477 def startswith(prefix, values):
478 return [value for value in values if value.startswith(prefix)]
483 for record in records:
484 person_ids.extend(record.get("person_ids", []))
485 site_ids.extend(record.get("site_ids", []))
486 if 'site_id' in record:
487 site_ids.append(record['site_id'])
489 # get all pis from the sites we've encountered
490 # and store them in a dictionary keyed on site_id
493 pi_filter = {'peer_id': None, '|roles': ['pi'], '|site_ids': site_ids}
494 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
496 # we will need the pi's hrns also
497 person_ids.append(pi['person_id'])
499 # we also need to keep track of the sites these pis
501 for site_id in pi['site_ids']:
502 if site_id in site_pis:
503 site_pis[site_id].append(pi)
505 site_pis[site_id] = [pi]
507 # get sfa records for all records associated with these records.
508 # we'll replace pl ids (person_ids) with hrns from the sfa records
511 # get the registry records
512 person_list, persons = [], {}
513 person_list = self.api.dbsession().query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
514 # create a hrns keyed on the sfa record's pointer.
515 # Its possible for multiple records to have the same pointer so
516 # the dict's value will be a list of hrns.
517 persons = defaultdict(list)
518 for person in person_list:
519 persons[person.pointer].append(person)
522 pl_person_list, pl_persons = [], {}
523 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
524 pl_persons = list_to_dict(pl_person_list, 'person_id')
527 for record in records:
528 # skip records with no pl info (top level authorities)
529 #if record['pointer'] == -1:
532 type = record['type']
533 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
534 if (type == "slice"):
535 # all slice users are researchers
536 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
538 record['researcher'] = []
539 for person_id in record.get('person_ids', []):
540 hrns = [person.hrn for person in persons[person_id]]
541 record['researcher'].extend(hrns)
543 # pis at the slice's site
544 if 'site_id' in record and record['site_id'] in site_pis:
545 pl_pis = site_pis[record['site_id']]
546 pi_ids = [pi['person_id'] for pi in pl_pis]
547 for person_id in pi_ids:
548 hrns = [person.hrn for person in persons[person_id]]
549 record['PI'].extend(hrns)
550 record['geni_creator'] = record['PI']
552 elif (type.startswith("authority")):
554 logger.info("fill_record_sfa_info - authority xherex")
555 if record['pointer'] != -1:
557 record['operator'] = []
559 for pointer in record.get('person_ids', []):
560 if pointer not in persons or pointer not in pl_persons:
561 # this means there is not sfa or pl record for this user
563 hrns = [person.hrn for person in persons[pointer]]
564 roles = pl_persons[pointer]['roles']
566 record['PI'].extend(hrns)
568 record['operator'].extend(hrns)
570 record['owner'].extend(hrns)
571 # xxx TODO: OrganizationName
572 elif (type == "node"):
573 sfa_info['dns'] = record.get("hostname", "")
574 # xxx TODO: URI, LatLong, IP, DNS
576 elif (type == "user"):
577 logger.info('setting user.email')
578 sfa_info['email'] = record.get("email", "")
579 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
580 sfa_info['geni_certificate'] = record['gid']
581 # xxx TODO: PostalAddress, Phone
582 record.update(sfa_info)
586 # plcapi works by changes, compute what needs to be added/deleted
587 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
588 # hard-wire the code for slice/user for now, could be smarter if needed
589 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
590 subject=self.shell.GetSlices (subject_id)[0]
591 current_target_ids = subject['person_ids']
592 add_target_ids = list ( set (target_ids).difference(current_target_ids))
593 del_target_ids = list ( set (current_target_ids).difference(target_ids))
594 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
595 for target_id in add_target_ids:
596 self.shell.AddPersonToSlice (target_id,subject_id)
597 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
598 for target_id in del_target_ids:
599 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
600 self.shell.DeletePersonFromSlice (target_id, subject_id)
601 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
602 # due to the plcapi limitations this means essentially adding pi role to all people in the list
603 # it's tricky to remove any pi role here, although it might be desirable
604 persons = self.shell.GetPersons ({'peer_id': None, 'person_id': target_ids})
605 for person in persons:
606 if 'pi' not in person['roles']:
607 self.shell.AddRoleToPerson('pi',person['person_id'])
609 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
612 ########################################
613 ########## aggregate oriented
614 ########################################
616 def testbed_name (self): return "myplc"
618 def aggregate_version (self):
621 # first 2 args are None in case of resource discovery
622 def list_resources (self, version=None, options={}):
623 aggregate = PlAggregate(self)
624 rspec = aggregate.list_resources(version=version, options=options)
627 def describe(self, urns, version, options={}):
628 aggregate = PlAggregate(self)
629 return aggregate.describe(urns, version=version, options=options)
631 def status (self, urns, options={}):
632 aggregate = PlAggregate(self)
633 desc = aggregate.describe(urns, version='GENI 3')
634 status = {'geni_urn': desc['geni_urn'],
635 'geni_slivers': desc['geni_slivers']}
638 def allocate (self, urn, rspec_string, expiration, options={}):
640 aggregate = PlAggregate(self)
641 slices = PlSlices(self)
642 peer = slices.get_peer(xrn.get_hrn())
643 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
645 users = options.get('geni_users', [])
647 slice_record = users[0].get('slice_record', {})
650 rspec = RSpec(rspec_string)
651 requested_attributes = rspec.version.get_slice_attributes()
653 # ensure site record exists
654 site = slices.verify_site(xrn.hrn, slice_record, peer, sfa_peer, options=options)
655 # ensure slice record exists
656 slice = slices.verify_slice(xrn.hrn, slice_record, peer, sfa_peer, expiration=expiration, options=options)
657 # ensure person records exists
658 persons = slices.verify_persons(xrn.hrn, slice, users, peer, sfa_peer, options=options)
659 # ensure slice attributes exists
660 slices.verify_slice_attributes(slice, requested_attributes, options=options)
662 # add/remove slice from nodes
663 request_nodes = rspec.version.get_nodes_with_slivers()
664 nodes = slices.verify_slice_nodes(urn, slice, request_nodes, peer)
666 # add/remove links links
667 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
670 rspec_requested_leases = rspec.version.get_leases()
671 leases = slices.verify_slice_leases(slice, rspec_requested_leases, peer)
673 # handle MyPLC peer association.
674 # only used by plc and ple.
675 slices.handle_peer(site, slice, None, peer)
677 return aggregate.describe([xrn.get_urn()], version=rspec.version)
679 def provision(self, urns, options={}):
681 slices = PlSlices(self)
682 aggregate = PlAggregate(self)
683 slivers = aggregate.get_slivers(urns)
685 peer = slices.get_peer(slice['hrn'])
686 sfa_peer = slices.get_sfa_peer(slice['hrn'])
687 users = options.get('geni_users', [])
688 persons = slices.verify_persons(slice['hrn'], slice, users, peer, sfa_peer, options=options)
689 slices.handle_peer(None, None, persons, peer)
690 # update sliver allocation states and set them to geni_provisioned
691 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
692 dbsession=self.api.dbsession()
693 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',dbsession)
694 version_manager = VersionManager()
695 rspec_version = version_manager.get_version(options['geni_rspec_version'])
696 return self.describe(urns, rspec_version, options=options)
698 def delete(self, urns, options={}):
699 # collect sliver ids so we can update sliver allocation states after
700 # we remove the slivers.
701 aggregate = PlAggregate(self)
702 slivers = aggregate.get_slivers(urns)
704 slice_id = slivers[0]['slice_id']
705 slice_name = slivers[0]['name']
708 for sliver in slivers:
709 node_ids.append(sliver['node_id'])
710 sliver_ids.append(sliver['sliver_id'])
713 leases = self.shell.GetLeases({'name': slice_name})
714 leases_ids = [lease['lease_id'] for lease in leases ]
716 # determine if this is a peer slice
717 # xxx I wonder if this would not need to use PlSlices.get_peer instead
718 # in which case plc.peers could be deprecated as this here
719 # is the only/last call to this last method in plc.peers
720 #slice_hrn = PlXrn(auth=self.hrn, slice_name).get_hrn()
721 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
722 peer = peers.get_peer(self, slice_hrn)
725 self.shell.UnBindObjectFromPeer('slice', slice_id, peer)
727 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
728 if len(leases_ids) > 0:
729 self.shell.DeleteLeases(leases_ids)
731 # delete sliver allocation states
732 dbsession=self.api.dbsession()
733 SliverAllocation.delete_allocations(sliver_ids,dbsession)
736 self.shell.BindObjectToPeer('slice', slice_id, peer, slice['peer_slice_id'])
738 # prepare return struct
740 for sliver in slivers:
742 {'geni_sliver_urn': sliver['sliver_id'],
743 'geni_allocation_status': 'geni_unallocated',
744 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
747 def renew (self, urns, expiration_time, options={}):
748 aggregate = PlAggregate(self)
749 slivers = aggregate.get_slivers(urns)
751 raise SearchFailed(urns)
753 requested_time = utcparse(expiration_time)
754 record = {'expires': int(datetime_to_epoch(requested_time))}
755 self.shell.UpdateSlice(slice['slice_id'], record)
756 description = self.describe(urns, 'GENI 3', options)
757 return description['geni_slivers']
760 def perform_operational_action (self, urns, action, options={}):
761 # MyPLC doesn't support operational actions. Lets pretend like it
762 # supports start, but reject everything else.
763 action = action.lower()
764 if action not in ['geni_start']:
765 raise UnsupportedOperation(action)
767 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
768 description = self.describe(urns, 'GENI 3', options)
769 for sliver in description['geni_slivers']:
770 if sliver['geni_operational_status'] == 'geni_pending_allocation':
771 raise UnsupportedOperation(action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
773 # Perform Operational Action Here
776 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
779 # set the 'enabled' tag to 0
780 def shutdown (self, xrn, options={}):
781 hrn, _ = urn_to_hrn(xrn)
782 top_auth_hrn = top_auth(hrn)
783 site_hrn = '.'.join(hrn.split('.')[:-1])
784 slice_part = hrn.split('.')[-1]
785 if top_auth_hrn == self.driver.hrn:
786 login_base = slice_hrn.split('.')[-2][:12]
788 login_base = hash_loginbase(site_hrn)
790 slicename = '_'.join([login_base, slice_part])
792 slices = self.shell.GetSlices({'peer_id': None, 'name': slicename}, ['slice_id'])
794 raise RecordNotFound(slice_hrn)
795 slice_id = slices[0]['slice_id']
796 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
798 self.shell.AddSliceTag(slice_id, 'enabled', '0')
799 elif slice_tags[0]['value'] != "0":
800 tag_id = slice_tags[0]['slice_tag_id']
801 self.shell.UpdateSliceTag(tag_id, '0')