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 from sfa.planetlab.plaggregate import PlAggregate
25 from sfa.planetlab.plslices import PlSlices
26 from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, xrn_to_hostname, top_auth, hash_loginbase
29 def list_to_dict(recs, key):
31 convert a list of dictionaries into a dictionary keyed on the
32 specified dictionary key
34 return dict ( [ (rec[key],rec) for rec in recs ] )
37 # PlShell is just an xmlrpc serverproxy where methods
38 # can be sent as-is; it takes care of authentication
39 # from the global config
41 class PlDriver (Driver):
43 # the cache instance is a class member so it survives across incoming requests
46 def __init__ (self, api):
47 Driver.__init__ (self, api)
49 self.shell = PlShell (config)
51 if config.SFA_AGGREGATE_CACHING:
52 if PlDriver.cache is None:
53 PlDriver.cache = Cache()
54 self.cache = PlDriver.cache
56 def sliver_to_slice_xrn(self, xrn):
57 sliver_id_parts = Xrn(xrn).get_sliver_id_parts()
60 filter['slice_id'] = int(sliver_id_parts[0])
62 fliter['name'] = sliver_id_parts[0]
63 slices = self.shell.GetSlices(filter)
65 raise Forbidden("Unable to locate slice record for sliver: %s" % xrn)
67 slice_xrn = PlXrn(auth=self.hrn, slicename=slice['name'])
70 def check_sliver_credentials(self, creds, urns):
71 # build list of cred object hrns
74 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
75 slice_cred_names.append(PlXrn(xrn=slice_cred_hrn).pl_slicename())
77 # look up slice name of slivers listed in urns arg
80 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
82 slice_ids.append(int(sliver_id_parts[0]))
87 raise Forbidden("sliver urn not provided")
89 slices = self.shell.GetSlices(slice_ids)
90 sliver_names = [slice['name'] for slice in slices]
92 # make sure we have a credential for every specified sliver ierd
93 for sliver_name in sliver_names:
94 if sliver_name not in slice_cred_names:
95 msg = "Valid credential not found for target: %s" % sliver_name
98 ########################################
99 ########## registry oriented
100 ########################################
102 def augment_records_with_testbed_info (self, sfa_records):
103 return self.fill_record_info (sfa_records)
106 def register (self, sfa_record, hrn, pub_key):
107 type = sfa_record['type']
108 pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
110 if type == 'authority':
111 sites = self.shell.GetSites({'peer_id': None, 'login_base': pl_record['login_base']})
113 # xxx when a site gets registered through SFA we need to set its max_slices
114 if 'max_slices' not in pl_record:
115 pl_record['max_slices']=2
116 pointer = self.shell.AddSite(pl_record)
117 self.shell.SetSiteHrn(int(pointer), hrn)
119 pointer = sites[0]['site_id']
121 elif type == 'slice':
122 acceptable_fields=['url', 'instantiation', 'name', 'description']
123 for key in pl_record.keys():
124 if key not in acceptable_fields:
126 slices = self.shell.GetSlices({'peer_id': None, 'name': pl_record['name']})
128 if not pl_record.get('url', None) or not pl_record.get('description', None):
129 pl_record['url'] = hrn
130 pl_record['description'] = hrn
132 pointer = self.shell.AddSlice(pl_record)
133 self.shell.SetSliceHrn(int(pointer), hrn)
135 pointer = slices[0]['slice_id']
138 persons = self.shell.GetPersons({'peer_id': None, 'email': sfa_record['email']})
140 for key in ['first_name','last_name']:
141 if key not in sfa_record: sfa_record[key]='*from*sfa*'
142 # AddPerson does not allow everything to be set
143 can_add = ['first_name', 'last_name', 'title','email', 'password', 'phone', 'url', 'bio']
144 add_person_dict=dict ( [ (k,sfa_record[k]) for k in sfa_record if k in can_add ] )
145 pointer = self.shell.AddPerson(add_person_dict)
146 self.shell.SetPersonHrn(int(pointer), hrn)
148 pointer = persons[0]['person_id']
150 # enable the person's account
151 self.shell.UpdatePerson(pointer, {'enabled': True})
152 # add this person to the site
153 login_base = get_leaf(sfa_record['authority'])
154 self.shell.AddPersonToSite(pointer, login_base)
156 # What roles should this user have?
158 if 'roles' in sfa_record:
159 # if specified in xml, but only low-level roles
160 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
161 # at least user if no other cluse could be found
165 self.shell.AddRoleToPerson(role, pointer)
168 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
171 login_base = PlXrn(xrn=sfa_record['authority'],type='authority').pl_login_base()
172 nodes = self.shell.GetNodes({'peer_id': None, 'hostname': pl_record['hostname']})
174 pointer = self.shell.AddNode(login_base, pl_record)
175 self.shell.SetNodeHrn(int(pointer), hrn)
177 pointer = nodes[0]['node_id']
182 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
183 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
184 pointer = old_sfa_record['pointer']
185 type = old_sfa_record['type']
186 new_key_pointer = None
188 # new_key implemented for users only
189 if new_key and type not in [ 'user' ]:
190 raise UnknownSfaType(type)
192 if (type == "authority"):
193 self.shell.UpdateSite(pointer, new_sfa_record)
194 self.shell.SetSiteHrn(pointer, hrn)
196 elif type == "slice":
197 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
198 if 'name' in pl_record:
199 pl_record.pop('name')
200 self.shell.UpdateSlice(pointer, pl_record)
201 self.shell.SetSliceHrn(pointer, hrn)
204 # SMBAKER: UpdatePerson only allows a limited set of fields to be
205 # updated. Ideally we should have a more generic way of doing
206 # this. I copied the field names from UpdatePerson.py...
208 all_fields = new_sfa_record
209 for key in all_fields.keys():
210 if key in ['first_name', 'last_name', 'title', 'email',
211 'password', 'phone', 'url', 'bio', 'accepted_aup',
213 update_fields[key] = all_fields[key]
214 # when updating a user, we always get a 'email' field at this point
215 # this is because 'email' is a native field in the RegUser object...
216 if 'email' in update_fields and not update_fields['email']:
217 del update_fields['email']
218 self.shell.UpdatePerson(pointer, update_fields)
219 self.shell.SetPersonHrn(pointer, hrn)
222 # must check this key against the previous one if it exists
223 persons = self.shell.GetPersons({'peer_id': None, 'person_id': pointer}, ['key_ids'])
225 keys = person['key_ids']
226 keys = self.shell.GetKeys(person['key_ids'])
230 if new_key == key['key']:
232 new_key_pointer = key['key_id']
235 new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
238 self.shell.UpdateNode(pointer, new_sfa_record)
240 return (pointer, new_key_pointer)
244 def remove (self, sfa_record):
245 type=sfa_record['type']
246 pointer=sfa_record['pointer']
248 persons = self.shell.GetPersons({'peer_id': None, 'person_id': pointer})
249 # only delete this person if he has site ids. if he doesnt, it probably means
250 # he was just removed from a site, not actually deleted
251 if persons and persons[0]['site_ids']:
252 self.shell.DeletePerson(pointer)
253 elif type == 'slice':
254 if self.shell.GetSlices({'peer_id': None, 'slice_id': pointer}):
255 self.shell.DeleteSlice(pointer)
257 if self.shell.GetNodes({'peer_id': None, 'node_id': pointer}):
258 self.shell.DeleteNode(pointer)
259 elif type == 'authority':
260 if self.shell.GetSites({'peer_id': None, 'site_id': pointer}):
261 self.shell.DeleteSite(pointer)
270 # Convert SFA fields to PLC fields for use when registering or updating
271 # registry record in the PLC database
274 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
279 pl_record["name"] = hrn_to_pl_slicename(hrn)
280 if "instantiation" in sfa_record:
281 pl_record['instantiation']=sfa_record['instantiation']
283 pl_record["instantiation"] = "plc-instantiated"
284 if "url" in sfa_record:
285 pl_record["url"] = sfa_record["url"]
286 if "description" in sfa_record:
287 pl_record["description"] = sfa_record["description"]
288 if "expires" in sfa_record:
289 date = utcparse(sfa_record['expires'])
290 expires = datetime_to_epoch(date)
291 pl_record["expires"] = expires
294 if not "hostname" in pl_record:
295 # fetch from sfa_record
296 if "hostname" not in sfa_record:
297 raise MissingSfaInfo("hostname")
298 pl_record["hostname"] = sfa_record["hostname"]
299 if "model" in sfa_record:
300 pl_record["model"] = sfa_record["model"]
302 pl_record["model"] = "geni"
304 elif type == "authority":
305 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
306 if "name" not in sfa_record:
307 pl_record["name"] = hrn
308 if "abbreviated_name" not in sfa_record:
309 pl_record["abbreviated_name"] = hrn
310 if "enabled" not in sfa_record:
311 pl_record["enabled"] = True
312 if "is_public" not in sfa_record:
313 pl_record["is_public"] = True
318 def fill_record_info(self, records):
320 Given a (list of) SFA record, fill in the PLC specific
321 and SFA specific fields in the record.
323 if not isinstance(records, list):
326 self.fill_record_pl_info(records)
327 self.fill_record_hrns(records)
328 self.fill_record_sfa_info(records)
331 def fill_record_pl_info(self, records):
333 Fill in the planetlab specific fields of a SFA record. This
334 involves calling the appropriate PLC method to retrieve the
335 database record for the object.
337 @param record: record to fill in field (in/out param)
340 node_ids, site_ids, slice_ids = [], [], []
341 person_ids, key_ids = [], []
342 type_map = {'node': node_ids, 'authority': site_ids,
343 'slice': slice_ids, 'user': person_ids}
345 for record in records:
346 for type in type_map:
347 if type == record['type']:
348 type_map[type].append(record['pointer'])
351 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
353 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids})
354 nodes = list_to_dict(node_list, 'node_id')
356 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids})
357 sites = list_to_dict(site_list, 'site_id')
359 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids})
360 slices = list_to_dict(slice_list, 'slice_id')
362 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids})
363 persons = list_to_dict(person_list, 'person_id')
364 for person in persons:
365 key_ids.extend(persons[person]['key_ids'])
367 pl_records = {'node': nodes, 'authority': sites,
368 'slice': slices, 'user': persons}
371 key_list = self.shell.GetKeys(key_ids)
372 keys = list_to_dict(key_list, 'key_id')
375 for record in records:
376 # records with pointer==-1 do not have plc info.
377 # for example, the top level authority records which are
378 # authorities, but not PL "sites"
379 if record['pointer'] == -1:
382 for type in pl_records:
383 if record['type'] == type:
384 if record['pointer'] in pl_records[type]:
385 record.update(pl_records[type][record['pointer']])
388 if record['type'] == 'user':
389 if 'key_ids' not in record:
390 logger.info("user record has no 'key_ids' - need to import from myplc ?")
392 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
393 record['keys'] = pubkeys
397 def fill_record_hrns(self, records):
399 convert pl ids to hrns
403 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
404 for record in records:
405 if 'site_id' in record:
406 site_ids.append(record['site_id'])
407 if 'site_ids' in record:
408 site_ids.extend(record['site_ids'])
409 if 'person_ids' in record:
410 person_ids.extend(record['person_ids'])
411 if 'slice_ids' in record:
412 slice_ids.extend(record['slice_ids'])
413 if 'node_ids' in record:
414 node_ids.extend(record['node_ids'])
417 slices, persons, sites, nodes = {}, {}, {}, {}
419 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids}, ['site_id', 'login_base'])
420 sites = list_to_dict(site_list, 'site_id')
422 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids}, ['person_id', 'email'])
423 persons = list_to_dict(person_list, 'person_id')
425 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids}, ['slice_id', 'name'])
426 slices = list_to_dict(slice_list, 'slice_id')
428 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids}, ['node_id', 'hostname'])
429 nodes = list_to_dict(node_list, 'node_id')
431 # convert ids to hrns
432 for record in records:
433 # get all relevant data
434 type = record['type']
435 pointer = record['pointer']
441 if 'site_id' in record:
442 site = sites[record['site_id']]
443 login_base = site['login_base']
444 record['site'] = ".".join([auth_hrn, login_base])
445 if 'person_ids' in record:
446 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
447 if person_id in persons]
448 usernames = [email.split('@')[0] for email in emails]
449 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
450 record['persons'] = person_hrns
451 if 'slice_ids' in record:
452 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
453 if slice_id in slices]
454 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
455 record['slices'] = slice_hrns
456 if 'node_ids' in record:
457 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
459 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
460 record['nodes'] = node_hrns
461 if 'site_ids' in record:
462 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
464 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
465 record['sites'] = site_hrns
467 if 'expires' in record:
468 date = utcparse(record['expires'])
469 datestring = datetime_to_string(date)
470 record['expires'] = datestring
474 def fill_record_sfa_info(self, records):
476 def startswith(prefix, values):
477 return [value for value in values if value.startswith(prefix)]
482 for record in records:
483 person_ids.extend(record.get("person_ids", []))
484 site_ids.extend(record.get("site_ids", []))
485 if 'site_id' in record:
486 site_ids.append(record['site_id'])
488 # get all pis from the sites we've encountered
489 # and store them in a dictionary keyed on site_id
492 pi_filter = {'peer_id': None, '|roles': ['pi'], '|site_ids': site_ids}
493 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
495 # we will need the pi's hrns also
496 person_ids.append(pi['person_id'])
498 # we also need to keep track of the sites these pis
500 for site_id in pi['site_ids']:
501 if site_id in site_pis:
502 site_pis[site_id].append(pi)
504 site_pis[site_id] = [pi]
506 # get sfa records for all records associated with these records.
507 # we'll replace pl ids (person_ids) with hrns from the sfa records
510 # get the registry records
511 person_list, persons = [], {}
512 person_list = self.api.dbsession().query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
513 # create a hrns keyed on the sfa record's pointer.
514 # Its possible for multiple records to have the same pointer so
515 # the dict's value will be a list of hrns.
516 persons = defaultdict(list)
517 for person in person_list:
518 persons[person.pointer].append(person)
521 pl_person_list, pl_persons = [], {}
522 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
523 pl_persons = list_to_dict(pl_person_list, 'person_id')
526 for record in records:
527 # skip records with no pl info (top level authorities)
528 #if record['pointer'] == -1:
531 type = record['type']
532 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
533 if (type == "slice"):
534 # all slice users are researchers
535 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
537 record['researcher'] = []
538 for person_id in record.get('person_ids', []):
539 hrns = [person.hrn for person in persons[person_id]]
540 record['researcher'].extend(hrns)
542 # pis at the slice's site
543 if 'site_id' in record and record['site_id'] in site_pis:
544 pl_pis = site_pis[record['site_id']]
545 pi_ids = [pi['person_id'] for pi in pl_pis]
546 for person_id in pi_ids:
547 hrns = [person.hrn for person in persons[person_id]]
548 record['PI'].extend(hrns)
549 record['geni_creator'] = record['PI']
551 elif (type.startswith("authority")):
553 logger.info("fill_record_sfa_info - authority xherex")
554 if record['pointer'] != -1:
556 record['operator'] = []
558 for pointer in record.get('person_ids', []):
559 if pointer not in persons or pointer not in pl_persons:
560 # this means there is not sfa or pl record for this user
562 hrns = [person.hrn for person in persons[pointer]]
563 roles = pl_persons[pointer]['roles']
565 record['PI'].extend(hrns)
567 record['operator'].extend(hrns)
569 record['owner'].extend(hrns)
570 # xxx TODO: OrganizationName
571 elif (type == "node"):
572 sfa_info['dns'] = record.get("hostname", "")
573 # xxx TODO: URI, LatLong, IP, DNS
575 elif (type == "user"):
576 logger.info('setting user.email')
577 sfa_info['email'] = record.get("email", "")
578 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
579 sfa_info['geni_certificate'] = record['gid']
580 # xxx TODO: PostalAddress, Phone
581 record.update(sfa_info)
585 # plcapi works by changes, compute what needs to be added/deleted
586 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
587 # hard-wire the code for slice/user for now, could be smarter if needed
588 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
589 subject=self.shell.GetSlices (subject_id)[0]
590 current_target_ids = subject['person_ids']
591 add_target_ids = list ( set (target_ids).difference(current_target_ids))
592 del_target_ids = list ( set (current_target_ids).difference(target_ids))
593 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
594 for target_id in add_target_ids:
595 self.shell.AddPersonToSlice (target_id,subject_id)
596 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
597 for target_id in del_target_ids:
598 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
599 self.shell.DeletePersonFromSlice (target_id, subject_id)
600 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
601 # due to the plcapi limitations this means essentially adding pi role to all people in the list
602 # it's tricky to remove any pi role here, although it might be desirable
603 persons = self.shell.GetPersons ({'peer_id': None, 'person_id': target_ids})
604 for person in persons:
605 if 'pi' not in person['roles']:
606 self.shell.AddRoleToPerson('pi',person['person_id'])
608 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
611 ########################################
612 ########## aggregate oriented
613 ########################################
615 def testbed_name (self): return "myplc"
617 def aggregate_version (self):
620 # first 2 args are None in case of resource discovery
621 def list_resources (self, version=None, options={}):
622 aggregate = PlAggregate(self)
623 rspec = aggregate.list_resources(version=version, options=options)
626 def describe(self, urns, version, options={}):
627 aggregate = PlAggregate(self)
628 return aggregate.describe(urns, version=version, options=options)
630 def status (self, urns, options={}):
631 aggregate = PlAggregate(self)
632 desc = aggregate.describe(urns, version='GENI 3')
633 status = {'geni_urn': desc['geni_urn'],
634 'geni_slivers': desc['geni_slivers']}
637 def allocate (self, urn, rspec_string, expiration, options={}):
639 aggregate = PlAggregate(self)
640 slices = PlSlices(self)
641 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
643 users = options.get('geni_users', [])
645 slice_record = users[0].get('slice_record', {})
648 rspec = RSpec(rspec_string)
649 requested_attributes = rspec.version.get_slice_attributes()
651 # ensure site record exists
652 site = slices.verify_site(xrn.hrn, slice_record, sfa_peer, options=options)
653 # ensure slice record exists
654 slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer, expiration=expiration, options=options)
655 # ensure person records exists
656 persons = slices.verify_persons(xrn.hrn, slice, users, sfa_peer, options=options)
657 # ensure slice attributes exists
658 slices.verify_slice_attributes(slice, requested_attributes, options=options)
660 # add/remove slice from nodes
661 request_nodes = rspec.version.get_nodes_with_slivers()
662 nodes = slices.verify_slice_nodes(urn, slice, request_nodes)
664 # add/remove links links
665 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
668 rspec_requested_leases = rspec.version.get_leases()
669 leases = slices.verify_slice_leases(slice, rspec_requested_leases)
671 return aggregate.describe([xrn.get_urn()], version=rspec.version)
673 def provision(self, urns, options={}):
675 slices = PlSlices(self)
676 aggregate = PlAggregate(self)
677 slivers = aggregate.get_slivers(urns)
679 sfa_peer = slices.get_sfa_peer(slice['hrn'])
680 users = options.get('geni_users', [])
681 persons = slices.verify_persons(slice['hrn'], slice, users, sfa_peer, options=options)
682 # update sliver allocation states and set them to geni_provisioned
683 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
684 dbsession=self.api.dbsession()
685 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',dbsession)
686 version_manager = VersionManager()
687 rspec_version = version_manager.get_version(options['geni_rspec_version'])
688 return self.describe(urns, rspec_version, options=options)
690 def delete(self, urns, options={}):
691 # collect sliver ids so we can update sliver allocation states after
692 # we remove the slivers.
693 aggregate = PlAggregate(self)
694 slivers = aggregate.get_slivers(urns)
696 slice_id = slivers[0]['slice_id']
697 slice_name = slivers[0]['name']
700 for sliver in slivers:
701 node_ids.append(sliver['node_id'])
702 sliver_ids.append(sliver['sliver_id'])
705 leases = self.shell.GetLeases({'name': slice_name})
706 leases_ids = [lease['lease_id'] for lease in leases ]
708 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
710 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
711 if len(leases_ids) > 0:
712 self.shell.DeleteLeases(leases_ids)
714 # delete sliver allocation states
715 dbsession=self.api.dbsession()
716 SliverAllocation.delete_allocations(sliver_ids,dbsession)
720 # prepare return struct
722 for sliver in slivers:
724 {'geni_sliver_urn': sliver['sliver_id'],
725 'geni_allocation_status': 'geni_unallocated',
726 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
729 def renew (self, urns, expiration_time, options={}):
730 aggregate = PlAggregate(self)
731 slivers = aggregate.get_slivers(urns)
733 raise SearchFailed(urns)
735 requested_time = utcparse(expiration_time)
736 record = {'expires': int(datetime_to_epoch(requested_time))}
737 self.shell.UpdateSlice(slice['slice_id'], record)
738 description = self.describe(urns, 'GENI 3', options)
739 return description['geni_slivers']
742 def perform_operational_action (self, urns, action, options={}):
743 # MyPLC doesn't support operational actions. Lets pretend like it
744 # supports start, but reject everything else.
745 action = action.lower()
746 if action not in ['geni_start']:
747 raise UnsupportedOperation(action)
749 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
750 description = self.describe(urns, 'GENI 3', options)
751 for sliver in description['geni_slivers']:
752 if sliver['geni_operational_status'] == 'geni_pending_allocation':
753 raise UnsupportedOperation(action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
755 # Perform Operational Action Here
758 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
761 # set the 'enabled' tag to 0
762 def shutdown (self, xrn, options={}):
763 hrn, _ = urn_to_hrn(xrn)
764 top_auth_hrn = top_auth(hrn)
765 site_hrn = '.'.join(hrn.split('.')[:-1])
766 slice_part = hrn.split('.')[-1]
767 if top_auth_hrn == self.driver.hrn:
768 login_base = slice_hrn.split('.')[-2][:12]
770 login_base = hash_loginbase(site_hrn)
772 slicename = '_'.join([login_base, slice_part])
774 slices = self.shell.GetSlices({'peer_id': None, 'name': slicename}, ['slice_id'])
776 raise RecordNotFound(slice_hrn)
777 slice_id = slices[0]['slice_id']
778 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
780 self.shell.AddSliceTag(slice_id, 'enabled', '0')
781 elif slice_tags[0]['value'] != "0":
782 tag_id = slice_tags[0]['slice_tag_id']
783 self.shell.UpdateSliceTag(tag_id, '0')