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.alchemy import dbsession
14 from sfa.storage.model import RegRecord, SliverAllocation
15 from sfa.trust.credential import Credential
17 # used to be used in get_ticket
18 #from sfa.trust.sfaticket import SfaTicket
19 from sfa.rspecs.version_manager import VersionManager
20 from sfa.rspecs.rspec import RSpec
22 # the driver interface, mostly provides default behaviours
23 from sfa.managers.driver import Driver
24 from sfa.planetlab.plshell import PlShell
25 import sfa.planetlab.peers as peers
26 from sfa.planetlab.plaggregate import PlAggregate
27 from sfa.planetlab.plslices import PlSlices
28 from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, xrn_to_hostname, top_auth, hash_loginbase
31 def list_to_dict(recs, key):
33 convert a list of dictionaries into a dictionary keyed on the
34 specified dictionary key
36 return dict ( [ (rec[key],rec) for rec in recs ] )
39 # PlShell is just an xmlrpc serverproxy where methods
40 # can be sent as-is; it takes care of authentication
41 # from the global config
43 class PlDriver (Driver):
45 # the cache instance is a class member so it survives across incoming requests
48 def __init__ (self, config):
49 Driver.__init__ (self, config)
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([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([pl_record['name']])
129 pointer = self.shell.AddSlice(pl_record)
130 self.shell.SetSliceHrn(int(pointer), hrn)
132 pointer = slices[0]['slice_id']
135 persons = self.shell.GetPersons({'email':sfa_record['email']})
137 for key in ['first_name','last_name']:
138 if key not in sfa_record: sfa_record[key]='*from*sfa*'
139 # AddPerson does not allow everything to be set
140 can_add = ['first_name', 'last_name', 'title','email', 'password', 'phone', 'url', 'bio']
141 add_person_dict=dict ( [ (k,sfa_record[k]) for k in sfa_record if k in can_add ] )
142 pointer = self.shell.AddPerson(add_person_dict)
143 self.shell.SetPersonHrn(int(pointer), hrn)
145 pointer = persons[0]['person_id']
147 if 'enabled' in sfa_record and sfa_record['enabled']:
148 self.shell.UpdatePerson(pointer, {'enabled': sfa_record['enabled']})
149 # add this person to the site only if she is being added for the first
150 # time by sfa and doesont already exist in plc
151 if not persons or not persons[0]['site_ids']:
152 login_base = get_leaf(sfa_record['authority'])
153 self.shell.AddPersonToSite(pointer, login_base)
155 # What roles should this user have?
157 if 'roles' in sfa_record:
158 # if specified in xml, but only low-level roles
159 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
160 # at least user if no other cluse could be found
164 self.shell.AddRoleToPerson(role, pointer)
167 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
170 login_base = PlXrn(xrn=sfa_record['authority'],type='authority').pl_login_base()
171 nodes = self.shell.GetNodes([pl_record['hostname']])
173 pointer = self.shell.AddNode(login_base, pl_record)
174 self.shell.SetNodeHrn(int(pointer), hrn)
176 pointer = nodes[0]['node_id']
181 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
182 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
183 pointer = old_sfa_record['pointer']
184 type = old_sfa_record['type']
185 new_key_pointer = None
187 # new_key implemented for users only
188 if new_key and type not in [ 'user' ]:
189 raise UnknownSfaType(type)
191 if (type == "authority"):
192 self.shell.UpdateSite(pointer, new_sfa_record)
193 self.shell.SetSiteHrn(pointer, hrn)
195 elif type == "slice":
196 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
197 if 'name' in pl_record:
198 pl_record.pop('name')
199 self.shell.UpdateSlice(pointer, pl_record)
200 self.shell.SetSliceHrn(pointer, hrn)
203 # SMBAKER: UpdatePerson only allows a limited set of fields to be
204 # updated. Ideally we should have a more generic way of doing
205 # this. I copied the field names from UpdatePerson.py...
207 all_fields = new_sfa_record
208 for key in all_fields.keys():
209 if key in ['first_name', 'last_name', 'title', 'email',
210 'password', 'phone', 'url', 'bio', 'accepted_aup',
212 update_fields[key] = all_fields[key]
213 # when updating a user, we always get a 'email' field at this point
214 # this is because 'email' is a native field in the RegUser object...
215 if 'email' in update_fields and not update_fields['email']:
216 del update_fields['email']
217 self.shell.UpdatePerson(pointer, update_fields)
218 self.shell.SetPersonHrn(pointer, hrn)
221 # must check this key against the previous one if it exists
222 persons = self.shell.GetPersons([pointer], ['key_ids'])
224 keys = person['key_ids']
225 keys = self.shell.GetKeys(person['key_ids'])
229 if new_key == key['key']:
231 new_key_pointer = key['key_id']
234 new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
237 self.shell.UpdateNode(pointer, new_sfa_record)
239 return (pointer, new_key_pointer)
243 def remove (self, sfa_record):
244 type=sfa_record['type']
245 pointer=sfa_record['pointer']
247 persons = self.shell.GetPersons(pointer)
248 # only delete this person if he has site ids. if he doesnt, it probably means
249 # he was just removed from a site, not actually deleted
250 if persons and persons[0]['site_ids']:
251 self.shell.DeletePerson(pointer)
252 elif type == 'slice':
253 if self.shell.GetSlices(pointer):
254 self.shell.DeleteSlice(pointer)
256 if self.shell.GetNodes(pointer):
257 self.shell.DeleteNode(pointer)
258 elif type == 'authority':
259 if self.shell.GetSites(pointer):
260 self.shell.DeleteSite(pointer)
269 # Convert SFA fields to PLC fields for use when registering or updating
270 # registry record in the PLC database
273 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
278 pl_record["name"] = hrn_to_pl_slicename(hrn)
279 if "instantiation" in sfa_record:
280 pl_record['instantiation']=sfa_record['instantiation']
282 pl_record["instantiation"] = "plc-instantiated"
283 if "url" in sfa_record:
284 pl_record["url"] = sfa_record["url"]
285 if "description" in sfa_record:
286 pl_record["description"] = sfa_record["description"]
287 if "expires" in sfa_record:
288 date = utcparse(sfa_record['expires'])
289 expires = datetime_to_epoch(date)
290 pl_record["expires"] = expires
293 if not "hostname" in pl_record:
294 # fetch from sfa_record
295 if "hostname" not in sfa_record:
296 raise MissingSfaInfo("hostname")
297 pl_record["hostname"] = sfa_record["hostname"]
298 if "model" in sfa_record:
299 pl_record["model"] = sfa_record["model"]
301 pl_record["model"] = "geni"
303 elif type == "authority":
304 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
305 if "name" not in sfa_record:
306 pl_record["name"] = hrn
307 if "abbreviated_name" not in sfa_record:
308 pl_record["abbreviated_name"] = hrn
309 if "enabled" not in sfa_record:
310 pl_record["enabled"] = True
311 if "is_public" not in sfa_record:
312 pl_record["is_public"] = True
317 def fill_record_info(self, records):
319 Given a (list of) SFA record, fill in the PLC specific
320 and SFA specific fields in the record.
322 if not isinstance(records, list):
325 self.fill_record_pl_info(records)
326 self.fill_record_hrns(records)
327 self.fill_record_sfa_info(records)
330 def fill_record_pl_info(self, records):
332 Fill in the planetlab specific fields of a SFA record. This
333 involves calling the appropriate PLC method to retrieve the
334 database record for the object.
336 @param record: record to fill in field (in/out param)
339 node_ids, site_ids, slice_ids = [], [], []
340 person_ids, key_ids = [], []
341 type_map = {'node': node_ids, 'authority': site_ids,
342 'slice': slice_ids, 'user': person_ids}
344 for record in records:
345 for type in type_map:
346 if type == record['type']:
347 type_map[type].append(record['pointer'])
350 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
352 node_list = self.shell.GetNodes(node_ids)
353 nodes = list_to_dict(node_list, 'node_id')
355 site_list = self.shell.GetSites(site_ids)
356 sites = list_to_dict(site_list, 'site_id')
358 slice_list = self.shell.GetSlices(slice_ids)
359 slices = list_to_dict(slice_list, 'slice_id')
361 person_list = self.shell.GetPersons(person_ids)
362 persons = list_to_dict(person_list, 'person_id')
363 for person in persons:
364 key_ids.extend(persons[person]['key_ids'])
366 pl_records = {'node': nodes, 'authority': sites,
367 'slice': slices, 'user': persons}
370 key_list = self.shell.GetKeys(key_ids)
371 keys = list_to_dict(key_list, 'key_id')
374 for record in records:
375 # records with pointer==-1 do not have plc info.
376 # for example, the top level authority records which are
377 # authorities, but not PL "sites"
378 if record['pointer'] == -1:
381 for type in pl_records:
382 if record['type'] == type:
383 if record['pointer'] in pl_records[type]:
384 record.update(pl_records[type][record['pointer']])
387 if record['type'] == 'user':
388 if 'key_ids' not in record:
389 logger.info("user record has no 'key_ids' - need to import from myplc ?")
391 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
392 record['keys'] = pubkeys
396 def fill_record_hrns(self, records):
398 convert pl ids to hrns
402 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
403 for record in records:
404 if 'site_id' in record:
405 site_ids.append(record['site_id'])
406 if 'site_ids' in record:
407 site_ids.extend(record['site_ids'])
408 if 'person_ids' in record:
409 person_ids.extend(record['person_ids'])
410 if 'slice_ids' in record:
411 slice_ids.extend(record['slice_ids'])
412 if 'node_ids' in record:
413 node_ids.extend(record['node_ids'])
416 slices, persons, sites, nodes = {}, {}, {}, {}
418 site_list = self.shell.GetSites(site_ids, ['site_id', 'login_base'])
419 sites = list_to_dict(site_list, 'site_id')
421 person_list = self.shell.GetPersons(person_ids, ['person_id', 'email'])
422 persons = list_to_dict(person_list, 'person_id')
424 slice_list = self.shell.GetSlices(slice_ids, ['slice_id', 'name'])
425 slices = list_to_dict(slice_list, 'slice_id')
427 node_list = self.shell.GetNodes(node_ids, ['node_id', 'hostname'])
428 nodes = list_to_dict(node_list, 'node_id')
430 # convert ids to hrns
431 for record in records:
432 # get all relevant data
433 type = record['type']
434 pointer = record['pointer']
440 if 'site_id' in record:
441 site = sites[record['site_id']]
442 login_base = site['login_base']
443 record['site'] = ".".join([auth_hrn, login_base])
444 if 'person_ids' in record:
445 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
446 if person_id in persons]
447 usernames = [email.split('@')[0] for email in emails]
448 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
449 record['persons'] = person_hrns
450 if 'slice_ids' in record:
451 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
452 if slice_id in slices]
453 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
454 record['slices'] = slice_hrns
455 if 'node_ids' in record:
456 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
458 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
459 record['nodes'] = node_hrns
460 if 'site_ids' in record:
461 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
463 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
464 record['sites'] = site_hrns
466 if 'expires' in record:
467 date = utcparse(record['expires'])
468 datestring = datetime_to_string(date)
469 record['expires'] = datestring
473 def fill_record_sfa_info(self, records):
475 def startswith(prefix, values):
476 return [value for value in values if value.startswith(prefix)]
481 for record in records:
482 person_ids.extend(record.get("person_ids", []))
483 site_ids.extend(record.get("site_ids", []))
484 if 'site_id' in record:
485 site_ids.append(record['site_id'])
487 # get all pis from the sites we've encountered
488 # and store them in a dictionary keyed on site_id
491 pi_filter = {'|roles': ['pi'], '|site_ids': site_ids}
492 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
494 # we will need the pi's hrns also
495 person_ids.append(pi['person_id'])
497 # we also need to keep track of the sites these pis
499 for site_id in pi['site_ids']:
500 if site_id in site_pis:
501 site_pis[site_id].append(pi)
503 site_pis[site_id] = [pi]
505 # get sfa records for all records associated with these records.
506 # we'll replace pl ids (person_ids) with hrns from the sfa records
509 # get the registry records
510 person_list, persons = [], {}
511 person_list = dbsession.query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
512 # create a hrns keyed on the sfa record's pointer.
513 # Its possible for multiple records to have the same pointer so
514 # the dict's value will be a list of hrns.
515 persons = defaultdict(list)
516 for person in person_list:
517 persons[person.pointer].append(person)
520 pl_person_list, pl_persons = [], {}
521 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
522 pl_persons = list_to_dict(pl_person_list, 'person_id')
525 for record in records:
526 # skip records with no pl info (top level authorities)
527 #if record['pointer'] == -1:
530 type = record['type']
531 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
532 if (type == "slice"):
533 # all slice users are researchers
534 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
536 record['researcher'] = []
537 for person_id in record.get('person_ids', []):
538 hrns = [person.hrn for person in persons[person_id]]
539 record['researcher'].extend(hrns)
541 # pis at the slice's site
542 if 'site_id' in record and record['site_id'] in site_pis:
543 pl_pis = site_pis[record['site_id']]
544 pi_ids = [pi['person_id'] for pi in pl_pis]
545 for person_id in pi_ids:
546 hrns = [person.hrn for person in persons[person_id]]
547 record['PI'].extend(hrns)
548 record['geni_creator'] = record['PI']
550 elif (type.startswith("authority")):
552 logger.info("fill_record_sfa_info - authority xherex")
553 if record['pointer'] != -1:
555 record['operator'] = []
557 for pointer in record.get('person_ids', []):
558 if pointer not in persons or pointer not in pl_persons:
559 # this means there is not sfa or pl record for this user
561 hrns = [person.hrn for person in persons[pointer]]
562 roles = pl_persons[pointer]['roles']
564 record['PI'].extend(hrns)
566 record['operator'].extend(hrns)
568 record['owner'].extend(hrns)
569 # xxx TODO: OrganizationName
570 elif (type == "node"):
571 sfa_info['dns'] = record.get("hostname", "")
572 # xxx TODO: URI, LatLong, IP, DNS
574 elif (type == "user"):
575 logger.info('setting user.email')
576 sfa_info['email'] = record.get("email", "")
577 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
578 sfa_info['geni_certificate'] = record['gid']
579 # xxx TODO: PostalAddress, Phone
580 record.update(sfa_info)
584 # plcapi works by changes, compute what needs to be added/deleted
585 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
586 # hard-wire the code for slice/user for now, could be smarter if needed
587 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
588 subject=self.shell.GetSlices (subject_id)[0]
589 current_target_ids = subject['person_ids']
590 add_target_ids = list ( set (target_ids).difference(current_target_ids))
591 del_target_ids = list ( set (current_target_ids).difference(target_ids))
592 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
593 for target_id in add_target_ids:
594 self.shell.AddPersonToSlice (target_id,subject_id)
595 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
596 for target_id in del_target_ids:
597 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
598 self.shell.DeletePersonFromSlice (target_id, subject_id)
599 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
600 # due to the plcapi limitations this means essentially adding pi role to all people in the list
601 # it's tricky to remove any pi role here, although it might be desirable
602 persons = self.shell.GetPersons (target_ids)
603 for person in persons:
604 if 'pi' not in person['roles']:
605 self.shell.AddRoleToPerson('pi',person['person_id'])
607 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
610 ########################################
611 ########## aggregate oriented
612 ########################################
614 def testbed_name (self): return "myplc"
616 def aggregate_version (self):
619 # first 2 args are None in case of resource discovery
620 def list_resources (self, version=None, options={}):
621 aggregate = PlAggregate(self)
622 rspec = aggregate.list_resources(version=version, options=options)
625 def describe(self, urns, version, options={}):
626 aggregate = PlAggregate(self)
627 return aggregate.describe(urns, version=version, options=options)
629 def status (self, urns, options={}):
630 aggregate = PlAggregate(self)
631 desc = aggregate.describe(urns, version='GENI 3')
632 status = {'geni_urn': desc['geni_urn'],
633 'geni_slivers': desc['geni_slivers']}
636 def allocate (self, urn, rspec_string, expiration, options={}):
638 aggregate = PlAggregate(self)
639 slices = PlSlices(self)
640 peer = slices.get_peer(xrn.get_hrn())
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, peer, sfa_peer, options=options)
653 # ensure slice record exists
654 slice = slices.verify_slice(xrn.hrn, slice_record, peer, sfa_peer, expiration=expiration, options=options)
655 # ensure person records exists
656 persons = slices.verify_persons(xrn.hrn, slice, users, peer, 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, peer)
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, peer)
671 # handle MyPLC peer association.
672 # only used by plc and ple.
673 slices.handle_peer(site, slice, None, peer)
675 return aggregate.describe([xrn.get_urn()], version=rspec.version)
677 def provision(self, urns, options={}):
679 slices = PlSlices(self)
680 aggregate = PlAggregate(self)
681 slivers = aggregate.get_slivers(urns)
683 peer = slices.get_peer(slice['hrn'])
684 sfa_peer = slices.get_sfa_peer(slice['hrn'])
685 users = options.get('geni_users', [])
686 persons = slices.verify_persons(slice['hrn'], slice, users, peer, sfa_peer, options=options)
687 slices.handle_peer(None, None, persons, peer)
688 # update sliver allocation states and set them to geni_provisioned
689 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
690 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned')
691 version_manager = VersionManager()
692 rspec_version = version_manager.get_version(options['geni_rspec_version'])
693 return self.describe(urns, rspec_version, options=options)
695 def delete(self, urns, options={}):
696 # collect sliver ids so we can update sliver allocation states after
697 # we remove the slivers.
698 aggregate = PlAggregate(self)
699 slivers = aggregate.get_slivers(urns)
701 slice_id = slivers[0]['slice_id']
702 slice_name = slivers[0]['name']
705 for sliver in slivers:
706 node_ids.append(sliver['node_id'])
707 sliver_ids.append(sliver['sliver_id'])
710 leases = self.shell.GetLeases({'name': slice_name})
711 leases_ids = [lease['lease_id'] for lease in leases ]
713 # determine if this is a peer slice
714 # xxx I wonder if this would not need to use PlSlices.get_peer instead
715 # in which case plc.peers could be deprecated as this here
716 # is the only/last call to this last method in plc.peers
717 #slice_hrn = PlXrn(auth=self.hrn, slice_name).get_hrn()
718 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
719 peer = peers.get_peer(self, slice_hrn)
722 self.shell.UnBindObjectFromPeer('slice', slice_id, peer)
724 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
725 if len(leases_ids) > 0:
726 self.shell.DeleteLeases(leases_ids)
728 # delete sliver allocation states
729 SliverAllocation.delete_allocations(sliver_ids)
732 self.shell.BindObjectToPeer('slice', slice_id, peer, slice['peer_slice_id'])
734 # prepare return struct
736 for sliver in slivers:
738 {'geni_sliver_urn': sliver['sliver_id'],
739 'geni_allocation_status': 'geni_unallocated',
740 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
743 def renew (self, urns, expiration_time, options={}):
744 aggregate = PlAggregate(self)
745 slivers = aggregate.get_slivers(urns)
747 raise SearchFailed(urns)
749 requested_time = utcparse(expiration_time)
750 record = {'expires': int(datetime_to_epoch(requested_time))}
751 self.shell.UpdateSlice(slice['slice_id'], record)
752 description = self.describe(urns, 'GENI 3', options)
753 return description['geni_slivers']
756 def perform_operational_action (self, urns, action, options={}):
757 # MyPLC doesn't support operational actions. Lets pretend like it
758 # supports start, but reject everything else.
759 action = action.lower()
760 if action not in ['geni_start']:
761 raise UnsupportedOperation(action)
763 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
764 description = self.describe(urns, 'GENI 3', options)
765 for sliver in description['geni_slivers']:
766 if sliver['geni_operational_status'] == 'geni_pending_allocation':
767 raise UnsupportedOperation(action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
769 # Perform Operational Action Here
772 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
775 # set the 'enabled' tag to 0
776 def shutdown (self, xrn, options={}):
777 hrn, _ = urn_to_hrn(xrn)
778 top_auth_hrn = top_auth(hrn)
779 site_hrn = '.'.join(hrn.split('.')[:-1])
780 slice_part = hrn.split('.')[-1]
781 if top_auth_hrn == self.driver.hrn:
782 login_base = slice_hrn.split('.')[-2][:12]
784 login_base = hash_loginbase(site_hrn)
786 slicename = '_'.join([login_base, slice_part])
788 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
790 raise RecordNotFound(slice_hrn)
791 slice_id = slices[0]['slice_id']
792 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
794 self.shell.AddSliceTag(slice_id, 'enabled', '0')
795 elif slice_tags[0]['value'] != "0":
796 tag_id = slice_tags[0]['slice_tag_id']
797 self.shell.UpdateSliceTag(tag_id, '0')