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([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 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({'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 only if she is being added for the first
154 # time by sfa and doesont already exist in plc
155 if not persons or not persons[0]['site_ids']:
156 login_base = get_leaf(sfa_record['authority'])
157 self.shell.AddPersonToSite(pointer, login_base)
159 # What roles should this user have?
161 if 'roles' in sfa_record:
162 # if specified in xml, but only low-level roles
163 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
164 # at least user if no other cluse could be found
168 self.shell.AddRoleToPerson(role, pointer)
171 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
174 login_base = PlXrn(xrn=sfa_record['authority'],type='authority').pl_login_base()
175 nodes = self.shell.GetNodes([pl_record['hostname']])
177 pointer = self.shell.AddNode(login_base, pl_record)
178 self.shell.SetNodeHrn(int(pointer), hrn)
180 pointer = nodes[0]['node_id']
185 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
186 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
187 pointer = old_sfa_record['pointer']
188 type = old_sfa_record['type']
189 new_key_pointer = None
191 # new_key implemented for users only
192 if new_key and type not in [ 'user' ]:
193 raise UnknownSfaType(type)
195 if (type == "authority"):
196 self.shell.UpdateSite(pointer, new_sfa_record)
197 self.shell.SetSiteHrn(pointer, hrn)
199 elif type == "slice":
200 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
201 if 'name' in pl_record:
202 pl_record.pop('name')
203 self.shell.UpdateSlice(pointer, pl_record)
204 self.shell.SetSliceHrn(pointer, hrn)
207 # SMBAKER: UpdatePerson only allows a limited set of fields to be
208 # updated. Ideally we should have a more generic way of doing
209 # this. I copied the field names from UpdatePerson.py...
211 all_fields = new_sfa_record
212 for key in all_fields.keys():
213 if key in ['first_name', 'last_name', 'title', 'email',
214 'password', 'phone', 'url', 'bio', 'accepted_aup',
216 update_fields[key] = all_fields[key]
217 # when updating a user, we always get a 'email' field at this point
218 # this is because 'email' is a native field in the RegUser object...
219 if 'email' in update_fields and not update_fields['email']:
220 del update_fields['email']
221 self.shell.UpdatePerson(pointer, update_fields)
222 self.shell.SetPersonHrn(pointer, hrn)
225 # must check this key against the previous one if it exists
226 persons = self.shell.GetPersons([pointer], ['key_ids'])
228 keys = person['key_ids']
229 keys = self.shell.GetKeys(person['key_ids'])
233 if new_key == key['key']:
235 new_key_pointer = key['key_id']
238 new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
241 self.shell.UpdateNode(pointer, new_sfa_record)
243 return (pointer, new_key_pointer)
247 def remove (self, sfa_record):
248 type=sfa_record['type']
249 pointer=sfa_record['pointer']
251 persons = self.shell.GetPersons(pointer)
252 # only delete this person if he has site ids. if he doesnt, it probably means
253 # he was just removed from a site, not actually deleted
254 if persons and persons[0]['site_ids']:
255 self.shell.DeletePerson(pointer)
256 elif type == 'slice':
257 if self.shell.GetSlices(pointer):
258 self.shell.DeleteSlice(pointer)
260 if self.shell.GetNodes(pointer):
261 self.shell.DeleteNode(pointer)
262 elif type == 'authority':
263 if self.shell.GetSites(pointer):
264 self.shell.DeleteSite(pointer)
273 # Convert SFA fields to PLC fields for use when registering or updating
274 # registry record in the PLC database
277 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
282 pl_record["name"] = hrn_to_pl_slicename(hrn)
283 if "instantiation" in sfa_record:
284 pl_record['instantiation']=sfa_record['instantiation']
286 pl_record["instantiation"] = "plc-instantiated"
287 if "url" in sfa_record:
288 pl_record["url"] = sfa_record["url"]
289 if "description" in sfa_record:
290 pl_record["description"] = sfa_record["description"]
291 if "expires" in sfa_record:
292 date = utcparse(sfa_record['expires'])
293 expires = datetime_to_epoch(date)
294 pl_record["expires"] = expires
297 if not "hostname" in pl_record:
298 # fetch from sfa_record
299 if "hostname" not in sfa_record:
300 raise MissingSfaInfo("hostname")
301 pl_record["hostname"] = sfa_record["hostname"]
302 if "model" in sfa_record:
303 pl_record["model"] = sfa_record["model"]
305 pl_record["model"] = "geni"
307 elif type == "authority":
308 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
309 if "name" not in sfa_record:
310 pl_record["name"] = hrn
311 if "abbreviated_name" not in sfa_record:
312 pl_record["abbreviated_name"] = hrn
313 if "enabled" not in sfa_record:
314 pl_record["enabled"] = True
315 if "is_public" not in sfa_record:
316 pl_record["is_public"] = True
321 def fill_record_info(self, records):
323 Given a (list of) SFA record, fill in the PLC specific
324 and SFA specific fields in the record.
326 if not isinstance(records, list):
329 self.fill_record_pl_info(records)
330 self.fill_record_hrns(records)
331 self.fill_record_sfa_info(records)
334 def fill_record_pl_info(self, records):
336 Fill in the planetlab specific fields of a SFA record. This
337 involves calling the appropriate PLC method to retrieve the
338 database record for the object.
340 @param record: record to fill in field (in/out param)
343 node_ids, site_ids, slice_ids = [], [], []
344 person_ids, key_ids = [], []
345 type_map = {'node': node_ids, 'authority': site_ids,
346 'slice': slice_ids, 'user': person_ids}
348 for record in records:
349 for type in type_map:
350 if type == record['type']:
351 type_map[type].append(record['pointer'])
354 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
356 node_list = self.shell.GetNodes(node_ids)
357 nodes = list_to_dict(node_list, 'node_id')
359 site_list = self.shell.GetSites(site_ids)
360 sites = list_to_dict(site_list, 'site_id')
362 slice_list = self.shell.GetSlices(slice_ids)
363 slices = list_to_dict(slice_list, 'slice_id')
365 person_list = self.shell.GetPersons(person_ids)
366 persons = list_to_dict(person_list, 'person_id')
367 for person in persons:
368 key_ids.extend(persons[person]['key_ids'])
370 pl_records = {'node': nodes, 'authority': sites,
371 'slice': slices, 'user': persons}
374 key_list = self.shell.GetKeys(key_ids)
375 keys = list_to_dict(key_list, 'key_id')
378 for record in records:
379 # records with pointer==-1 do not have plc info.
380 # for example, the top level authority records which are
381 # authorities, but not PL "sites"
382 if record['pointer'] == -1:
385 for type in pl_records:
386 if record['type'] == type:
387 if record['pointer'] in pl_records[type]:
388 record.update(pl_records[type][record['pointer']])
391 if record['type'] == 'user':
392 if 'key_ids' not in record:
393 logger.info("user record has no 'key_ids' - need to import from myplc ?")
395 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
396 record['keys'] = pubkeys
400 def fill_record_hrns(self, records):
402 convert pl ids to hrns
406 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
407 for record in records:
408 if 'site_id' in record:
409 site_ids.append(record['site_id'])
410 if 'site_ids' in record:
411 site_ids.extend(record['site_ids'])
412 if 'person_ids' in record:
413 person_ids.extend(record['person_ids'])
414 if 'slice_ids' in record:
415 slice_ids.extend(record['slice_ids'])
416 if 'node_ids' in record:
417 node_ids.extend(record['node_ids'])
420 slices, persons, sites, nodes = {}, {}, {}, {}
422 site_list = self.shell.GetSites(site_ids, ['site_id', 'login_base'])
423 sites = list_to_dict(site_list, 'site_id')
425 person_list = self.shell.GetPersons(person_ids, ['person_id', 'email'])
426 persons = list_to_dict(person_list, 'person_id')
428 slice_list = self.shell.GetSlices(slice_ids, ['slice_id', 'name'])
429 slices = list_to_dict(slice_list, 'slice_id')
431 node_list = self.shell.GetNodes(node_ids, ['node_id', 'hostname'])
432 nodes = list_to_dict(node_list, 'node_id')
434 # convert ids to hrns
435 for record in records:
436 # get all relevant data
437 type = record['type']
438 pointer = record['pointer']
444 if 'site_id' in record:
445 site = sites[record['site_id']]
446 login_base = site['login_base']
447 record['site'] = ".".join([auth_hrn, login_base])
448 if 'person_ids' in record:
449 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
450 if person_id in persons]
451 usernames = [email.split('@')[0] for email in emails]
452 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
453 record['persons'] = person_hrns
454 if 'slice_ids' in record:
455 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
456 if slice_id in slices]
457 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
458 record['slices'] = slice_hrns
459 if 'node_ids' in record:
460 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
462 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
463 record['nodes'] = node_hrns
464 if 'site_ids' in record:
465 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
467 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
468 record['sites'] = site_hrns
470 if 'expires' in record:
471 date = utcparse(record['expires'])
472 datestring = datetime_to_string(date)
473 record['expires'] = datestring
477 def fill_record_sfa_info(self, records):
479 def startswith(prefix, values):
480 return [value for value in values if value.startswith(prefix)]
485 for record in records:
486 person_ids.extend(record.get("person_ids", []))
487 site_ids.extend(record.get("site_ids", []))
488 if 'site_id' in record:
489 site_ids.append(record['site_id'])
491 # get all pis from the sites we've encountered
492 # and store them in a dictionary keyed on site_id
495 pi_filter = {'|roles': ['pi'], '|site_ids': site_ids}
496 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
498 # we will need the pi's hrns also
499 person_ids.append(pi['person_id'])
501 # we also need to keep track of the sites these pis
503 for site_id in pi['site_ids']:
504 if site_id in site_pis:
505 site_pis[site_id].append(pi)
507 site_pis[site_id] = [pi]
509 # get sfa records for all records associated with these records.
510 # we'll replace pl ids (person_ids) with hrns from the sfa records
513 # get the registry records
514 person_list, persons = [], {}
515 person_list = self.api.dbsession().query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
516 # create a hrns keyed on the sfa record's pointer.
517 # Its possible for multiple records to have the same pointer so
518 # the dict's value will be a list of hrns.
519 persons = defaultdict(list)
520 for person in person_list:
521 persons[person.pointer].append(person)
524 pl_person_list, pl_persons = [], {}
525 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
526 pl_persons = list_to_dict(pl_person_list, 'person_id')
529 for record in records:
530 # skip records with no pl info (top level authorities)
531 #if record['pointer'] == -1:
534 type = record['type']
535 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
536 if (type == "slice"):
537 # all slice users are researchers
538 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
540 record['researcher'] = []
541 for person_id in record.get('person_ids', []):
542 hrns = [person.hrn for person in persons[person_id]]
543 record['researcher'].extend(hrns)
545 # pis at the slice's site
546 if 'site_id' in record and record['site_id'] in site_pis:
547 pl_pis = site_pis[record['site_id']]
548 pi_ids = [pi['person_id'] for pi in pl_pis]
549 for person_id in pi_ids:
550 hrns = [person.hrn for person in persons[person_id]]
551 record['PI'].extend(hrns)
552 record['geni_creator'] = record['PI']
554 elif (type.startswith("authority")):
556 logger.info("fill_record_sfa_info - authority xherex")
557 if record['pointer'] != -1:
559 record['operator'] = []
561 for pointer in record.get('person_ids', []):
562 if pointer not in persons or pointer not in pl_persons:
563 # this means there is not sfa or pl record for this user
565 hrns = [person.hrn for person in persons[pointer]]
566 roles = pl_persons[pointer]['roles']
568 record['PI'].extend(hrns)
570 record['operator'].extend(hrns)
572 record['owner'].extend(hrns)
573 # xxx TODO: OrganizationName
574 elif (type == "node"):
575 sfa_info['dns'] = record.get("hostname", "")
576 # xxx TODO: URI, LatLong, IP, DNS
578 elif (type == "user"):
579 logger.info('setting user.email')
580 sfa_info['email'] = record.get("email", "")
581 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
582 sfa_info['geni_certificate'] = record['gid']
583 # xxx TODO: PostalAddress, Phone
584 record.update(sfa_info)
588 # plcapi works by changes, compute what needs to be added/deleted
589 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
590 # hard-wire the code for slice/user for now, could be smarter if needed
591 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
592 subject=self.shell.GetSlices (subject_id)[0]
593 current_target_ids = subject['person_ids']
594 add_target_ids = list ( set (target_ids).difference(current_target_ids))
595 del_target_ids = list ( set (current_target_ids).difference(target_ids))
596 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
597 for target_id in add_target_ids:
598 self.shell.AddPersonToSlice (target_id,subject_id)
599 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
600 for target_id in del_target_ids:
601 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
602 self.shell.DeletePersonFromSlice (target_id, subject_id)
603 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
604 # due to the plcapi limitations this means essentially adding pi role to all people in the list
605 # it's tricky to remove any pi role here, although it might be desirable
606 persons = self.shell.GetPersons (target_ids)
607 for person in persons:
608 if 'pi' not in person['roles']:
609 self.shell.AddRoleToPerson('pi',person['person_id'])
611 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
614 ########################################
615 ########## aggregate oriented
616 ########################################
618 def testbed_name (self): return "myplc"
620 def aggregate_version (self):
623 # first 2 args are None in case of resource discovery
624 def list_resources (self, version=None, options={}):
625 aggregate = PlAggregate(self)
626 rspec = aggregate.list_resources(version=version, options=options)
629 def describe(self, urns, version, options={}):
630 aggregate = PlAggregate(self)
631 return aggregate.describe(urns, version=version, options=options)
633 def status (self, urns, options={}):
634 aggregate = PlAggregate(self)
635 desc = aggregate.describe(urns, version='GENI 3')
636 status = {'geni_urn': desc['geni_urn'],
637 'geni_slivers': desc['geni_slivers']}
640 def allocate (self, urn, rspec_string, expiration, options={}):
642 aggregate = PlAggregate(self)
643 slices = PlSlices(self)
644 peer = slices.get_peer(xrn.get_hrn())
645 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
647 users = options.get('geni_users', [])
649 slice_record = users[0].get('slice_record', {})
652 rspec = RSpec(rspec_string)
653 requested_attributes = rspec.version.get_slice_attributes()
655 # ensure site record exists
656 site = slices.verify_site(xrn.hrn, slice_record, peer, sfa_peer, options=options)
657 # ensure slice record exists
658 slice = slices.verify_slice(xrn.hrn, slice_record, peer, sfa_peer, expiration=expiration, options=options)
659 # ensure person records exists
660 persons = slices.verify_persons(xrn.hrn, slice, users, peer, sfa_peer, options=options)
661 # ensure slice attributes exists
662 slices.verify_slice_attributes(slice, requested_attributes, options=options)
664 # add/remove slice from nodes
665 request_nodes = rspec.version.get_nodes_with_slivers()
666 nodes = slices.verify_slice_nodes(urn, slice, request_nodes, peer)
668 # add/remove links links
669 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
672 rspec_requested_leases = rspec.version.get_leases()
673 leases = slices.verify_slice_leases(slice, rspec_requested_leases, peer)
675 # handle MyPLC peer association.
676 # only used by plc and ple.
677 slices.handle_peer(site, slice, None, peer)
679 return aggregate.describe([xrn.get_urn()], version=rspec.version)
681 def provision(self, urns, options={}):
683 slices = PlSlices(self)
684 aggregate = PlAggregate(self)
685 slivers = aggregate.get_slivers(urns)
687 peer = slices.get_peer(slice['hrn'])
688 sfa_peer = slices.get_sfa_peer(slice['hrn'])
689 users = options.get('geni_users', [])
690 persons = slices.verify_persons(slice['hrn'], slice, users, peer, sfa_peer, options=options)
691 slices.handle_peer(None, None, persons, peer)
692 # update sliver allocation states and set them to geni_provisioned
693 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
694 dbsession=self.api.dbsession()
695 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',dbsession)
696 version_manager = VersionManager()
697 rspec_version = version_manager.get_version(options['geni_rspec_version'])
698 return self.describe(urns, rspec_version, options=options)
700 def delete(self, urns, options={}):
701 # collect sliver ids so we can update sliver allocation states after
702 # we remove the slivers.
703 aggregate = PlAggregate(self)
704 slivers = aggregate.get_slivers(urns)
706 slice_id = slivers[0]['slice_id']
707 slice_name = slivers[0]['name']
710 for sliver in slivers:
711 node_ids.append(sliver['node_id'])
712 sliver_ids.append(sliver['sliver_id'])
715 leases = self.shell.GetLeases({'name': slice_name})
716 leases_ids = [lease['lease_id'] for lease in leases ]
718 # determine if this is a peer slice
719 # xxx I wonder if this would not need to use PlSlices.get_peer instead
720 # in which case plc.peers could be deprecated as this here
721 # is the only/last call to this last method in plc.peers
722 #slice_hrn = PlXrn(auth=self.hrn, slice_name).get_hrn()
723 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
724 peer = peers.get_peer(self, slice_hrn)
727 self.shell.UnBindObjectFromPeer('slice', slice_id, peer)
729 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
730 if len(leases_ids) > 0:
731 self.shell.DeleteLeases(leases_ids)
733 # delete sliver allocation states
734 dbsession=self.api.dbsession()
735 SliverAllocation.delete_allocations(sliver_ids,dbsession)
738 self.shell.BindObjectToPeer('slice', slice_id, peer, slice['peer_slice_id'])
740 # prepare return struct
742 for sliver in slivers:
744 {'geni_sliver_urn': sliver['sliver_id'],
745 'geni_allocation_status': 'geni_unallocated',
746 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
749 def renew (self, urns, expiration_time, options={}):
750 aggregate = PlAggregate(self)
751 slivers = aggregate.get_slivers(urns)
753 raise SearchFailed(urns)
755 requested_time = utcparse(expiration_time)
756 record = {'expires': int(datetime_to_epoch(requested_time))}
757 self.shell.UpdateSlice(slice['slice_id'], record)
758 description = self.describe(urns, 'GENI 3', options)
759 return description['geni_slivers']
762 def perform_operational_action (self, urns, action, options={}):
763 # MyPLC doesn't support operational actions. Lets pretend like it
764 # supports start, but reject everything else.
765 action = action.lower()
766 if action not in ['geni_start']:
767 raise UnsupportedOperation(action)
769 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
770 description = self.describe(urns, 'GENI 3', options)
771 for sliver in description['geni_slivers']:
772 if sliver['geni_operational_status'] == 'geni_pending_allocation':
773 raise UnsupportedOperation(action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
775 # Perform Operational Action Here
778 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
781 # set the 'enabled' tag to 0
782 def shutdown (self, xrn, options={}):
783 hrn, _ = urn_to_hrn(xrn)
784 top_auth_hrn = top_auth(hrn)
785 site_hrn = '.'.join(hrn.split('.')[:-1])
786 slice_part = hrn.split('.')[-1]
787 if top_auth_hrn == self.driver.hrn:
788 login_base = slice_hrn.split('.')[-2][:12]
790 login_base = hash_loginbase(site_hrn)
792 slicename = '_'.join([login_base, slice_part])
794 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
796 raise RecordNotFound(slice_hrn)
797 slice_id = slices[0]['slice_id']
798 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
800 self.shell.AddSliceTag(slice_id, 'enabled', '0')
801 elif slice_tags[0]['value'] != "0":
802 tag_id = slice_tags[0]['slice_tag_id']
803 self.shell.UpdateSliceTag(tag_id, '0')