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 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 = self.api.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 dbsession=self.api.dbsession()
691 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',dbsession)
692 version_manager = VersionManager()
693 rspec_version = version_manager.get_version(options['geni_rspec_version'])
694 return self.describe(urns, rspec_version, options=options)
696 def delete(self, urns, options={}):
697 # collect sliver ids so we can update sliver allocation states after
698 # we remove the slivers.
699 aggregate = PlAggregate(self)
700 slivers = aggregate.get_slivers(urns)
702 slice_id = slivers[0]['slice_id']
703 slice_name = slivers[0]['name']
706 for sliver in slivers:
707 node_ids.append(sliver['node_id'])
708 sliver_ids.append(sliver['sliver_id'])
711 leases = self.shell.GetLeases({'name': slice_name})
712 leases_ids = [lease['lease_id'] for lease in leases ]
714 # determine if this is a peer slice
715 # xxx I wonder if this would not need to use PlSlices.get_peer instead
716 # in which case plc.peers could be deprecated as this here
717 # is the only/last call to this last method in plc.peers
718 #slice_hrn = PlXrn(auth=self.hrn, slice_name).get_hrn()
719 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
720 peer = peers.get_peer(self, slice_hrn)
723 self.shell.UnBindObjectFromPeer('slice', slice_id, peer)
725 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
726 if len(leases_ids) > 0:
727 self.shell.DeleteLeases(leases_ids)
729 # delete sliver allocation states
730 dbsession=self.api.dbsession()
731 SliverAllocation.delete_allocations(sliver_ids,dbsession)
734 self.shell.BindObjectToPeer('slice', slice_id, peer, slice['peer_slice_id'])
736 # prepare return struct
738 for sliver in slivers:
740 {'geni_sliver_urn': sliver['sliver_id'],
741 'geni_allocation_status': 'geni_unallocated',
742 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
745 def renew (self, urns, expiration_time, options={}):
746 aggregate = PlAggregate(self)
747 slivers = aggregate.get_slivers(urns)
749 raise SearchFailed(urns)
751 requested_time = utcparse(expiration_time)
752 record = {'expires': int(datetime_to_epoch(requested_time))}
753 self.shell.UpdateSlice(slice['slice_id'], record)
754 description = self.describe(urns, 'GENI 3', options)
755 return description['geni_slivers']
758 def perform_operational_action (self, urns, action, options={}):
759 # MyPLC doesn't support operational actions. Lets pretend like it
760 # supports start, but reject everything else.
761 action = action.lower()
762 if action not in ['geni_start']:
763 raise UnsupportedOperation(action)
765 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
766 description = self.describe(urns, 'GENI 3', options)
767 for sliver in description['geni_slivers']:
768 if sliver['geni_operational_status'] == 'geni_pending_allocation':
769 raise UnsupportedOperation(action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
771 # Perform Operational Action Here
774 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
777 # set the 'enabled' tag to 0
778 def shutdown (self, xrn, options={}):
779 hrn, _ = urn_to_hrn(xrn)
780 top_auth_hrn = top_auth(hrn)
781 site_hrn = '.'.join(hrn.split('.')[:-1])
782 slice_part = hrn.split('.')[-1]
783 if top_auth_hrn == self.driver.hrn:
784 login_base = slice_hrn.split('.')[-2][:12]
786 login_base = hash_loginbase(site_hrn)
788 slicename = '_'.join([login_base, slice_part])
790 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
792 raise RecordNotFound(slice_hrn)
793 slice_id = slices[0]['slice_id']
794 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
796 self.shell.AddSliceTag(slice_id, 'enabled', '0')
797 elif slice_tags[0]['value'] != "0":
798 tag_id = slice_tags[0]['slice_tag_id']
799 self.shell.UpdateSliceTag(tag_id, '0')