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()
58 filter = {'peer_id': None}
60 filter['slice_id'] = int(sliver_id_parts[0])
62 filter['name'] = sliver_id_parts[0]
63 slices = self.shell.GetSlices(filter,['hrn'])
65 raise Forbidden("Unable to locate slice record for sliver: %s" % xrn)
67 slice_xrn = slice['hrn']
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 top_auth_hrn = top_auth(slice_cred_hrn)
76 site_hrn = '.'.join(slice_cred_hrn.split('.')[:-1])
77 slice_part = slice_cred_hrn.split('.')[-1]
78 if top_auth_hrn == self.hrn:
79 login_base = slice_cred_hrn.split('.')[-2][:12]
81 login_base = hash_loginbase(site_hrn)
83 slicename = '_'.join([login_base, slice_part])
84 slice_cred_names.append(slicename)
86 # look up slice name of slivers listed in urns arg
89 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
91 slice_ids.append(int(sliver_id_parts[0]))
96 raise Forbidden("sliver urn not provided")
98 slices = self.shell.GetSlices(slice_ids)
99 sliver_names = [slice['name'] for slice in slices]
101 # make sure we have a credential for every specified sliver ierd
102 for sliver_name in sliver_names:
103 if sliver_name not in slice_cred_names:
104 msg = "Valid credential not found for target: %s" % sliver_name
107 ########################################
108 ########## registry oriented
109 ########################################
111 def augment_records_with_testbed_info (self, sfa_records):
112 return self.fill_record_info (sfa_records)
115 def register (self, sfa_record, hrn, pub_key):
116 type = sfa_record['type']
117 pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
119 if type == 'authority':
120 sites = self.shell.GetSites({'peer_id': None, 'login_base': pl_record['login_base']})
122 # xxx when a site gets registered through SFA we need to set its max_slices
123 if 'max_slices' not in pl_record:
124 pl_record['max_slices']=2
125 pointer = self.shell.AddSite(pl_record)
126 self.shell.SetSiteHrn(int(pointer), hrn)
128 pointer = sites[0]['site_id']
130 elif type == 'slice':
131 acceptable_fields=['url', 'instantiation', 'name', 'description']
132 for key in pl_record.keys():
133 if key not in acceptable_fields:
135 slices = self.shell.GetSlices({'peer_id': None, 'name': pl_record['name']})
137 if not pl_record.get('url', None) or not pl_record.get('description', None):
138 pl_record['url'] = hrn
139 pl_record['description'] = hrn
141 pointer = self.shell.AddSlice(pl_record)
142 self.shell.SetSliceHrn(int(pointer), hrn)
144 pointer = slices[0]['slice_id']
147 persons = self.shell.GetPersons({'peer_id': None, 'email': sfa_record['email']})
149 for key in ['first_name','last_name']:
150 if key not in sfa_record: sfa_record[key]='*from*sfa*'
151 # AddPerson does not allow everything to be set
152 can_add = ['first_name', 'last_name', 'title','email', 'password', 'phone', 'url', 'bio']
153 add_person_dict=dict ( [ (k,sfa_record[k]) for k in sfa_record if k in can_add ] )
154 pointer = self.shell.AddPerson(add_person_dict)
155 self.shell.SetPersonHrn(int(pointer), hrn)
157 pointer = persons[0]['person_id']
159 # enable the person's account
160 self.shell.UpdatePerson(pointer, {'enabled': True})
161 # add this person to the site
162 login_base = get_leaf(sfa_record['authority'])
163 self.shell.AddPersonToSite(pointer, login_base)
165 # What roles should this user have?
167 if 'roles' in sfa_record:
168 # if specified in xml, but only low-level roles
169 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
170 # at least user if no other cluse could be found
174 self.shell.AddRoleToPerson(role, pointer)
177 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
180 login_base = PlXrn(xrn=sfa_record['authority'],type='authority').pl_login_base()
181 nodes = self.shell.GetNodes({'peer_id': None, 'hostname': pl_record['hostname']})
183 pointer = self.shell.AddNode(login_base, pl_record)
184 self.shell.SetNodeHrn(int(pointer), hrn)
186 pointer = nodes[0]['node_id']
191 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
192 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
193 pointer = old_sfa_record['pointer']
194 type = old_sfa_record['type']
195 new_key_pointer = None
197 # new_key implemented for users only
198 if new_key and type not in [ 'user' ]:
199 raise UnknownSfaType(type)
201 if (type == "authority"):
202 self.shell.UpdateSite(pointer, new_sfa_record)
203 self.shell.SetSiteHrn(pointer, hrn)
205 elif type == "slice":
206 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
207 if 'name' in pl_record:
208 pl_record.pop('name')
209 self.shell.UpdateSlice(pointer, pl_record)
210 self.shell.SetSliceHrn(pointer, hrn)
213 # SMBAKER: UpdatePerson only allows a limited set of fields to be
214 # updated. Ideally we should have a more generic way of doing
215 # this. I copied the field names from UpdatePerson.py...
217 all_fields = new_sfa_record
218 for key in all_fields.keys():
219 if key in ['first_name', 'last_name', 'title', 'email',
220 'password', 'phone', 'url', 'bio', 'accepted_aup',
222 update_fields[key] = all_fields[key]
223 # when updating a user, we always get a 'email' field at this point
224 # this is because 'email' is a native field in the RegUser object...
225 if 'email' in update_fields and not update_fields['email']:
226 del update_fields['email']
227 self.shell.UpdatePerson(pointer, update_fields)
228 self.shell.SetPersonHrn(pointer, hrn)
231 # must check this key against the previous one if it exists
232 persons = self.shell.GetPersons({'peer_id': None, 'person_id': pointer}, ['key_ids'])
234 keys = person['key_ids']
235 keys = self.shell.GetKeys(person['key_ids'])
239 if new_key == key['key']:
241 new_key_pointer = key['key_id']
244 new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
247 self.shell.UpdateNode(pointer, new_sfa_record)
249 return (pointer, new_key_pointer)
253 def remove (self, sfa_record):
254 type=sfa_record['type']
255 pointer=sfa_record['pointer']
257 persons = self.shell.GetPersons({'peer_id': None, 'person_id': pointer})
258 # only delete this person if he has site ids. if he doesnt, it probably means
259 # he was just removed from a site, not actually deleted
260 if persons and persons[0]['site_ids']:
261 self.shell.DeletePerson(pointer)
262 elif type == 'slice':
263 if self.shell.GetSlices({'peer_id': None, 'slice_id': pointer}):
264 self.shell.DeleteSlice(pointer)
266 if self.shell.GetNodes({'peer_id': None, 'node_id': pointer}):
267 self.shell.DeleteNode(pointer)
268 elif type == 'authority':
269 if self.shell.GetSites({'peer_id': None, 'site_id': pointer}):
270 self.shell.DeleteSite(pointer)
279 # Convert SFA fields to PLC fields for use when registering or updating
280 # registry record in the PLC database
283 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
288 pl_record["name"] = hrn_to_pl_slicename(hrn)
289 if "instantiation" in sfa_record:
290 pl_record['instantiation']=sfa_record['instantiation']
292 pl_record["instantiation"] = "plc-instantiated"
293 if "url" in sfa_record:
294 pl_record["url"] = sfa_record["url"]
295 if "description" in sfa_record:
296 pl_record["description"] = sfa_record["description"]
297 if "expires" in sfa_record:
298 date = utcparse(sfa_record['expires'])
299 expires = datetime_to_epoch(date)
300 pl_record["expires"] = expires
303 if not "hostname" in pl_record:
304 # fetch from sfa_record
305 if "hostname" not in sfa_record:
306 raise MissingSfaInfo("hostname")
307 pl_record["hostname"] = sfa_record["hostname"]
308 if "model" in sfa_record:
309 pl_record["model"] = sfa_record["model"]
311 pl_record["model"] = "geni"
313 elif type == "authority":
314 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
315 if "name" not in sfa_record:
316 pl_record["name"] = hrn
317 if "abbreviated_name" not in sfa_record:
318 pl_record["abbreviated_name"] = hrn
319 if "enabled" not in sfa_record:
320 pl_record["enabled"] = True
321 if "is_public" not in sfa_record:
322 pl_record["is_public"] = True
327 def fill_record_info(self, records):
329 Given a (list of) SFA record, fill in the PLC specific
330 and SFA specific fields in the record.
332 if not isinstance(records, list):
335 self.fill_record_pl_info(records)
336 self.fill_record_hrns(records)
337 self.fill_record_sfa_info(records)
340 def fill_record_pl_info(self, records):
342 Fill in the planetlab specific fields of a SFA record. This
343 involves calling the appropriate PLC method to retrieve the
344 database record for the object.
346 @param record: record to fill in field (in/out param)
349 node_ids, site_ids, slice_ids = [], [], []
350 person_ids, key_ids = [], []
351 type_map = {'node': node_ids, 'authority': site_ids,
352 'slice': slice_ids, 'user': person_ids}
354 for record in records:
355 for type in type_map:
356 if type == record['type']:
357 type_map[type].append(record['pointer'])
360 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
362 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids})
363 nodes = list_to_dict(node_list, 'node_id')
365 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids})
366 sites = list_to_dict(site_list, 'site_id')
368 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids})
369 slices = list_to_dict(slice_list, 'slice_id')
371 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids})
372 persons = list_to_dict(person_list, 'person_id')
373 for person in persons:
374 key_ids.extend(persons[person]['key_ids'])
376 pl_records = {'node': nodes, 'authority': sites,
377 'slice': slices, 'user': persons}
380 key_list = self.shell.GetKeys(key_ids)
381 keys = list_to_dict(key_list, 'key_id')
384 for record in records:
385 # records with pointer==-1 do not have plc info.
386 # for example, the top level authority records which are
387 # authorities, but not PL "sites"
388 if record['pointer'] == -1:
391 for type in pl_records:
392 if record['type'] == type:
393 if record['pointer'] in pl_records[type]:
394 record.update(pl_records[type][record['pointer']])
397 if record['type'] == 'user':
398 if 'key_ids' not in record:
399 logger.info("user record has no 'key_ids' - need to import from myplc ?")
401 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
402 record['keys'] = pubkeys
406 def fill_record_hrns(self, records):
408 convert pl ids to hrns
412 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
413 for record in records:
414 if 'site_id' in record:
415 site_ids.append(record['site_id'])
416 if 'site_ids' in record:
417 site_ids.extend(record['site_ids'])
418 if 'person_ids' in record:
419 person_ids.extend(record['person_ids'])
420 if 'slice_ids' in record:
421 slice_ids.extend(record['slice_ids'])
422 if 'node_ids' in record:
423 node_ids.extend(record['node_ids'])
426 slices, persons, sites, nodes = {}, {}, {}, {}
428 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids}, ['site_id', 'login_base'])
429 sites = list_to_dict(site_list, 'site_id')
431 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids}, ['person_id', 'email'])
432 persons = list_to_dict(person_list, 'person_id')
434 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids}, ['slice_id', 'name'])
435 slices = list_to_dict(slice_list, 'slice_id')
437 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids}, ['node_id', 'hostname'])
438 nodes = list_to_dict(node_list, 'node_id')
440 # convert ids to hrns
441 for record in records:
442 # get all relevant data
443 type = record['type']
444 pointer = record['pointer']
450 if 'site_id' in record:
451 site = sites[record['site_id']]
452 login_base = site['login_base']
453 record['site'] = ".".join([auth_hrn, login_base])
454 if 'person_ids' in record:
455 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
456 if person_id in persons]
457 usernames = [email.split('@')[0] for email in emails]
458 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
459 record['persons'] = person_hrns
460 if 'slice_ids' in record:
461 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
462 if slice_id in slices]
463 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
464 record['slices'] = slice_hrns
465 if 'node_ids' in record:
466 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
468 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
469 record['nodes'] = node_hrns
470 if 'site_ids' in record:
471 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
473 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
474 record['sites'] = site_hrns
476 if 'expires' in record:
477 date = utcparse(record['expires'])
478 datestring = datetime_to_string(date)
479 record['expires'] = datestring
483 def fill_record_sfa_info(self, records):
485 def startswith(prefix, values):
486 return [value for value in values if value.startswith(prefix)]
491 for record in records:
492 person_ids.extend(record.get("person_ids", []))
493 site_ids.extend(record.get("site_ids", []))
494 if 'site_id' in record:
495 site_ids.append(record['site_id'])
497 # get all pis from the sites we've encountered
498 # and store them in a dictionary keyed on site_id
501 pi_filter = {'peer_id': None, '|roles': ['pi'], '|site_ids': site_ids}
502 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
504 # we will need the pi's hrns also
505 person_ids.append(pi['person_id'])
507 # we also need to keep track of the sites these pis
509 for site_id in pi['site_ids']:
510 if site_id in site_pis:
511 site_pis[site_id].append(pi)
513 site_pis[site_id] = [pi]
515 # get sfa records for all records associated with these records.
516 # we'll replace pl ids (person_ids) with hrns from the sfa records
519 # get the registry records
520 person_list, persons = [], {}
521 person_list = self.api.dbsession().query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
522 # create a hrns keyed on the sfa record's pointer.
523 # Its possible for multiple records to have the same pointer so
524 # the dict's value will be a list of hrns.
525 persons = defaultdict(list)
526 for person in person_list:
527 persons[person.pointer].append(person)
530 pl_person_list, pl_persons = [], {}
531 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
532 pl_persons = list_to_dict(pl_person_list, 'person_id')
535 for record in records:
536 # skip records with no pl info (top level authorities)
537 #if record['pointer'] == -1:
540 type = record['type']
541 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
542 if (type == "slice"):
543 # all slice users are researchers
544 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
546 record['researcher'] = []
547 for person_id in record.get('person_ids', []):
548 hrns = [person.hrn for person in persons[person_id]]
549 record['researcher'].extend(hrns)
551 # pis at the slice's site
552 if 'site_id' in record and record['site_id'] in site_pis:
553 pl_pis = site_pis[record['site_id']]
554 pi_ids = [pi['person_id'] for pi in pl_pis]
555 for person_id in pi_ids:
556 hrns = [person.hrn for person in persons[person_id]]
557 record['PI'].extend(hrns)
558 record['geni_creator'] = record['PI']
560 elif (type.startswith("authority")):
562 logger.info("fill_record_sfa_info - authority xherex")
563 if record['pointer'] != -1:
565 record['operator'] = []
567 for pointer in record.get('person_ids', []):
568 if pointer not in persons or pointer not in pl_persons:
569 # this means there is not sfa or pl record for this user
571 hrns = [person.hrn for person in persons[pointer]]
572 roles = pl_persons[pointer]['roles']
574 record['PI'].extend(hrns)
576 record['operator'].extend(hrns)
578 record['owner'].extend(hrns)
579 # xxx TODO: OrganizationName
580 elif (type == "node"):
581 sfa_info['dns'] = record.get("hostname", "")
582 # xxx TODO: URI, LatLong, IP, DNS
584 elif (type == "user"):
585 logger.info('setting user.email')
586 sfa_info['email'] = record.get("email", "")
587 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
588 sfa_info['geni_certificate'] = record['gid']
589 # xxx TODO: PostalAddress, Phone
590 record.update(sfa_info)
594 # plcapi works by changes, compute what needs to be added/deleted
595 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
596 # hard-wire the code for slice/user for now, could be smarter if needed
597 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
598 subject=self.shell.GetSlices (subject_id)[0]
599 current_target_ids = subject['person_ids']
600 add_target_ids = list ( set (target_ids).difference(current_target_ids))
601 del_target_ids = list ( set (current_target_ids).difference(target_ids))
602 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
603 for target_id in add_target_ids:
604 self.shell.AddPersonToSlice (target_id,subject_id)
605 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
606 for target_id in del_target_ids:
607 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
608 self.shell.DeletePersonFromSlice (target_id, subject_id)
609 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
610 # due to the plcapi limitations this means essentially adding pi role to all people in the list
611 # it's tricky to remove any pi role here, although it might be desirable
612 persons = self.shell.GetPersons ({'peer_id': None, 'person_id': target_ids})
613 for person in persons:
614 if 'pi' not in person['roles']:
615 self.shell.AddRoleToPerson('pi',person['person_id'])
617 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
620 ########################################
621 ########## aggregate oriented
622 ########################################
624 def testbed_name (self): return "myplc"
626 def aggregate_version (self):
629 # first 2 args are None in case of resource discovery
630 def list_resources (self, version=None, options=None):
631 if options is None: options={}
632 aggregate = PlAggregate(self)
633 rspec = aggregate.list_resources(version=version, options=options)
636 def describe(self, urns, version, options=None):
637 if options is None: options={}
638 aggregate = PlAggregate(self)
639 return aggregate.describe(urns, version=version, options=options)
641 def status (self, urns, options=None):
642 if options is None: options={}
643 aggregate = PlAggregate(self)
644 desc = aggregate.describe(urns, version='GENI 3')
645 status = {'geni_urn': desc['geni_urn'],
646 'geni_slivers': desc['geni_slivers']}
649 def allocate (self, urn, rspec_string, expiration, options=None):
650 if options is None: options={}
652 aggregate = PlAggregate(self)
653 slices = PlSlices(self)
654 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
656 users = options.get('geni_users', [])
659 slice_record = users[0].get('slice_record', {})
662 rspec = RSpec(rspec_string)
663 requested_attributes = rspec.version.get_slice_attributes()
665 # ensure site record exists
666 site = slices.verify_site(xrn.hrn, slice_record, sfa_peer, options=options)
667 # ensure slice record exists
668 slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer, expiration=expiration, options=options)
669 # ensure person records exists
670 persons = slices.verify_persons(xrn.hrn, slice, users, sfa_peer, options=options)
671 # ensure slice attributes exists
672 slices.verify_slice_attributes(slice, requested_attributes, options=options)
674 # add/remove slice from nodes
675 request_nodes = rspec.version.get_nodes_with_slivers()
676 nodes = slices.verify_slice_nodes(urn, slice, request_nodes)
678 # add/remove links links
679 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
682 rspec_requested_leases = rspec.version.get_leases()
683 leases = slices.verify_slice_leases(slice, rspec_requested_leases)
685 return aggregate.describe([xrn.get_urn()], version=rspec.version)
687 def provision(self, urns, options=None):
688 if options is None: options={}
690 slices = PlSlices(self)
691 aggregate = PlAggregate(self)
692 slivers = aggregate.get_slivers(urns)
694 sliver_id_parts = Xrn(urns[0]).get_sliver_id_parts()
697 filter['slice_id'] = int(sliver_id_parts[0])
699 filter['name'] = sliver_id_parts[0]
700 slices = self.shell.GetSlices(filter,['hrn'])
702 raise Forbidden("Unable to locate slice record for sliver: %s" % xrn)
704 slice_urn = hrn_to_urn(slice['hrn'], type='slice')
707 slice_id = slivers[0]['slice_id']
708 slice_hrn = self.shell.GetSliceHrn(slice_id)
709 slice = self.shell.GetSlices({'slice_id': slice_id})[0]
710 slice['hrn'] = slice_hrn
711 sfa_peer = slices.get_sfa_peer(slice['hrn'])
712 users = options.get('geni_users', [])
713 persons = slices.verify_persons(slice['hrn'], slice, users, sfa_peer, options=options)
714 # update sliver allocation states and set them to geni_provisioned
715 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
716 dbsession=self.api.dbsession()
717 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',dbsession)
719 version_manager = VersionManager()
720 rspec_version = version_manager.get_version(options['geni_rspec_version'])
721 return self.describe(urns, rspec_version, options=options)
723 def delete(self, urns, options=None):
724 if options is None: options={}
725 # collect sliver ids so we can update sliver allocation states after
726 # we remove the slivers.
727 aggregate = PlAggregate(self)
728 slivers = aggregate.get_slivers(urns)
730 slice_id = slivers[0]['slice_id']
731 slice_name = slivers[0]['name']
734 for sliver in slivers:
735 node_ids.append(sliver['node_id'])
736 sliver_ids.append(sliver['sliver_id'])
739 leases = self.shell.GetLeases({'name': slice_name, 'node_id': node_ids})
740 leases_ids = [lease['lease_id'] for lease in leases ]
742 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
744 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
745 if len(leases_ids) > 0:
746 self.shell.DeleteLeases(leases_ids)
748 # delete sliver allocation states
749 dbsession=self.api.dbsession()
750 SliverAllocation.delete_allocations(sliver_ids,dbsession)
754 # prepare return struct
756 for sliver in slivers:
758 {'geni_sliver_urn': sliver['sliver_id'],
759 'geni_allocation_status': 'geni_unallocated',
760 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
763 def renew (self, urns, expiration_time, options=None):
764 if options is None: options={}
765 aggregate = PlAggregate(self)
766 slivers = aggregate.get_slivers(urns)
768 raise SearchFailed(urns)
770 requested_time = utcparse(expiration_time)
771 record = {'expires': int(datetime_to_epoch(requested_time))}
772 self.shell.UpdateSlice(slice['slice_id'], record)
773 description = self.describe(urns, 'GENI 3', options)
774 return description['geni_slivers']
777 def perform_operational_action (self, urns, action, options=None):
778 if options is None: options={}
779 # MyPLC doesn't support operational actions. Lets pretend like it
780 # supports start, but reject everything else.
781 action = action.lower()
782 if action not in ['geni_start']:
783 raise UnsupportedOperation(action)
785 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
786 description = self.describe(urns, 'GENI 3', options)
787 for sliver in description['geni_slivers']:
788 if sliver['geni_operational_status'] == 'geni_pending_allocation':
789 raise UnsupportedOperation(action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
791 # Perform Operational Action Here
794 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
797 # set the 'enabled' tag to 0
798 def shutdown (self, xrn, options=None):
799 if options is None: options={}
800 hrn, _ = urn_to_hrn(xrn)
801 top_auth_hrn = top_auth(hrn)
802 site_hrn = '.'.join(hrn.split('.')[:-1])
803 slice_part = hrn.split('.')[-1]
804 if top_auth_hrn == self.hrn:
805 login_base = slice_hrn.split('.')[-2][:12]
807 login_base = hash_loginbase(site_hrn)
809 slicename = '_'.join([login_base, slice_part])
811 slices = self.shell.GetSlices({'peer_id': None, 'name': slicename}, ['slice_id'])
813 raise RecordNotFound(slice_hrn)
814 slice_id = slices[0]['slice_id']
815 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
817 self.shell.AddSliceTag(slice_id, 'enabled', '0')
818 elif slice_tags[0]['value'] != "0":
819 tag_id = slice_tags[0]['slice_tag_id']
820 self.shell.UpdateSliceTag(tag_id, '0')