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, 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 { 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: {}".format(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: {}".format(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 = { 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)
276 # Convert SFA fields to PLC fields for use when registering or updating
277 # registry record in the PLC database
280 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
285 pl_record["name"] = hrn_to_pl_slicename(hrn)
286 if "instantiation" in sfa_record:
287 pl_record['instantiation']=sfa_record['instantiation']
289 pl_record["instantiation"] = "plc-instantiated"
290 if "url" in sfa_record:
291 pl_record["url"] = sfa_record["url"]
292 if "description" in sfa_record:
293 pl_record["description"] = sfa_record["description"]
294 if "expires" in sfa_record:
295 date = utcparse(sfa_record['expires'])
296 expires = datetime_to_epoch(date)
297 pl_record["expires"] = expires
300 if not "hostname" in pl_record:
301 # fetch from sfa_record
302 if "hostname" not in sfa_record:
303 raise MissingSfaInfo("hostname")
304 pl_record["hostname"] = sfa_record["hostname"]
305 if "model" in sfa_record:
306 pl_record["model"] = sfa_record["model"]
308 pl_record["model"] = "geni"
310 elif type == "authority":
311 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
312 if "name" not in sfa_record or not sfa_record['name']:
313 pl_record["name"] = hrn
314 if "abbreviated_name" not in sfa_record:
315 pl_record["abbreviated_name"] = hrn
316 if "enabled" not in sfa_record:
317 pl_record["enabled"] = True
318 if "is_public" not in sfa_record:
319 pl_record["is_public"] = True
324 def fill_record_info(self, records):
326 Given a (list of) SFA record, fill in the PLC specific
327 and SFA specific fields in the record.
329 if not isinstance(records, list):
332 self.fill_record_pl_info(records)
333 self.fill_record_hrns(records)
334 self.fill_record_sfa_info(records)
337 def fill_record_pl_info(self, records):
339 Fill in the planetlab specific fields of a SFA record. This
340 involves calling the appropriate PLC method to retrieve the
341 database record for the object.
343 @param record: record to fill in field (in/out param)
346 node_ids, site_ids, slice_ids = [], [], []
347 person_ids, key_ids = [], []
348 type_map = {'node': node_ids, 'authority': site_ids,
349 'slice': slice_ids, 'user': person_ids}
351 for record in records:
352 for type in type_map:
353 if type == record['type']:
354 type_map[type].append(record['pointer'])
357 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
359 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids})
360 nodes = list_to_dict(node_list, 'node_id')
362 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids})
363 sites = list_to_dict(site_list, 'site_id')
365 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids})
366 slices = list_to_dict(slice_list, 'slice_id')
368 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids})
369 persons = list_to_dict(person_list, 'person_id')
370 for person in persons:
371 key_ids.extend(persons[person]['key_ids'])
373 pl_records = {'node': nodes, 'authority': sites,
374 'slice': slices, 'user': persons}
377 key_list = self.shell.GetKeys(key_ids)
378 keys = list_to_dict(key_list, 'key_id')
381 for record in records:
382 # records with pointer==-1 do not have plc info.
383 # for example, the top level authority records which are
384 # authorities, but not PL "sites"
385 if record['pointer'] == -1:
388 for type in pl_records:
389 if record['type'] == type:
390 if record['pointer'] in pl_records[type]:
391 record.update(pl_records[type][record['pointer']])
394 if record['type'] == 'user':
395 if 'key_ids' not in record:
396 logger.info("user record has no 'key_ids' - need to import from myplc ?")
398 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
399 record['keys'] = pubkeys
403 def fill_record_hrns(self, records):
405 convert pl ids to hrns
409 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
410 for record in records:
411 if 'site_id' in record:
412 site_ids.append(record['site_id'])
413 if 'site_ids' in record:
414 site_ids.extend(record['site_ids'])
415 if 'person_ids' in record:
416 person_ids.extend(record['person_ids'])
417 if 'slice_ids' in record:
418 slice_ids.extend(record['slice_ids'])
419 if 'node_ids' in record:
420 node_ids.extend(record['node_ids'])
423 slices, persons, sites, nodes = {}, {}, {}, {}
425 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids}, ['site_id', 'login_base'])
426 sites = list_to_dict(site_list, 'site_id')
428 person_list = self.shell.GetPersons({'peer_id': None, 'person_id': person_ids}, ['person_id', 'email'])
429 persons = list_to_dict(person_list, 'person_id')
431 slice_list = self.shell.GetSlices({'peer_id': None, 'slice_id': slice_ids}, ['slice_id', 'name'])
432 slices = list_to_dict(slice_list, 'slice_id')
434 node_list = self.shell.GetNodes({'peer_id': None, 'node_id': node_ids}, ['node_id', 'hostname'])
435 nodes = list_to_dict(node_list, 'node_id')
437 # convert ids to hrns
438 for record in records:
439 # get all relevant data
440 type = record['type']
441 pointer = record['pointer']
447 if 'site_id' in record:
448 site = sites[record['site_id']]
449 login_base = site['login_base']
450 record['site'] = ".".join([auth_hrn, login_base])
451 if 'person_ids' in record:
452 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
453 if person_id in persons]
454 usernames = [email.split('@')[0] for email in emails]
455 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
456 record['persons'] = person_hrns
457 if 'slice_ids' in record:
458 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
459 if slice_id in slices]
460 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
461 record['slices'] = slice_hrns
462 if 'node_ids' in record:
463 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
465 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
466 record['nodes'] = node_hrns
467 if 'site_ids' in record:
468 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
470 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
471 record['sites'] = site_hrns
473 if 'expires' in record:
474 date = utcparse(record['expires'])
475 datestring = datetime_to_string(date)
476 record['expires'] = datestring
480 def fill_record_sfa_info(self, records):
482 def startswith(prefix, values):
483 return [value for value in values if value.startswith(prefix)]
488 for record in records:
489 person_ids.extend(record.get("person_ids", []))
490 site_ids.extend(record.get("site_ids", []))
491 if 'site_id' in record:
492 site_ids.append(record['site_id'])
494 # get all pis from the sites we've encountered
495 # and store them in a dictionary keyed on site_id
498 pi_filter = {'peer_id': None, '|roles': ['pi'], '|site_ids': site_ids}
499 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
501 # we will need the pi's hrns also
502 person_ids.append(pi['person_id'])
504 # we also need to keep track of the sites these pis
506 for site_id in pi['site_ids']:
507 if site_id in site_pis:
508 site_pis[site_id].append(pi)
510 site_pis[site_id] = [pi]
512 # get sfa records for all records associated with these records.
513 # we'll replace pl ids (person_ids) with hrns from the sfa records
516 # get the registry records
517 person_list, persons = [], {}
518 person_list = self.api.dbsession().query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
519 # create a hrns keyed on the sfa record's pointer.
520 # Its possible for multiple records to have the same pointer so
521 # the dict's value will be a list of hrns.
522 persons = defaultdict(list)
523 for person in person_list:
524 persons[person.pointer].append(person)
527 pl_person_list, pl_persons = [], {}
528 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
529 pl_persons = list_to_dict(pl_person_list, 'person_id')
532 for record in records:
533 # skip records with no pl info (top level authorities)
534 #if record['pointer'] == -1:
537 type = record['type']
538 logger.info("fill_record_sfa_info - incoming record typed {}".format(type))
539 if (type == "slice"):
540 # all slice users are researchers
541 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
543 record['researcher'] = []
544 for person_id in record.get('person_ids', []):
545 hrns = [person.hrn for person in persons[person_id]]
546 record['researcher'].extend(hrns)
548 # pis at the slice's site
549 if 'site_id' in record and record['site_id'] in site_pis:
550 pl_pis = site_pis[record['site_id']]
551 pi_ids = [pi['person_id'] for pi in pl_pis]
552 for person_id in pi_ids:
553 hrns = [person.hrn for person in persons[person_id]]
554 record['PI'].extend(hrns)
555 record['geni_creator'] = record['PI']
557 elif (type.startswith("authority")):
559 logger.info("fill_record_sfa_info - authority xherex")
560 if record['pointer'] != -1:
562 record['operator'] = []
564 for pointer in record.get('person_ids', []):
565 if pointer not in persons or pointer not in pl_persons:
566 # this means there is not sfa or pl record for this user
568 hrns = [person.hrn for person in persons[pointer]]
569 roles = pl_persons[pointer]['roles']
571 record['PI'].extend(hrns)
573 record['operator'].extend(hrns)
575 record['owner'].extend(hrns)
576 # xxx TODO: OrganizationName
577 elif (type == "node"):
578 sfa_info['dns'] = record.get("hostname", "")
579 # xxx TODO: URI, LatLong, IP, DNS
581 elif (type == "user"):
582 logger.info('setting user.email')
583 sfa_info['email'] = record.get("email", "")
584 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
585 sfa_info['geni_certificate'] = record['gid']
586 # xxx TODO: PostalAddress, Phone
587 record.update(sfa_info)
591 # plcapi works by changes, compute what needs to be added/deleted
592 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
593 # hard-wire the code for slice/user for now, could be smarter if needed
594 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
595 subject=self.shell.GetSlices (subject_id)[0]
596 current_target_ids = subject['person_ids']
597 add_target_ids = list ( set (target_ids).difference(current_target_ids))
598 del_target_ids = list ( set (current_target_ids).difference(target_ids))
599 logger.debug ("subject_id = {} (type={})".format(subject_id, type(subject_id)))
600 for target_id in add_target_ids:
601 self.shell.AddPersonToSlice (target_id,subject_id)
602 logger.debug ("add_target_id = {} (type={})".format(target_id, type(target_id)))
603 for target_id in del_target_ids:
604 logger.debug ("del_target_id = {} (type={})".format(target_id, type(target_id)))
605 self.shell.DeletePersonFromSlice (target_id, subject_id)
606 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
607 # due to the plcapi limitations this means essentially adding pi role to all people in the list
608 # it's tricky to remove any pi role here, although it might be desirable
609 persons = self.shell.GetPersons ({'peer_id': None, 'person_id': target_ids})
610 for person in persons:
611 if 'pi' not in person['roles']:
612 self.shell.AddRoleToPerson('pi',person['person_id'])
614 logger.info('unexpected relation {} to maintain, {} -> {}'\
615 .format(relation_name, subject_type, target_type))
618 ########################################
619 ########## aggregate oriented
620 ########################################
622 def testbed_name (self): return "myplc"
624 def aggregate_version (self):
627 # first 2 args are None in case of resource discovery
628 def list_resources (self, version=None, options=None):
629 if options is None: options={}
630 aggregate = PlAggregate(self)
631 rspec = aggregate.list_resources(version=version, options=options)
634 def describe(self, urns, version, options=None):
635 if options is None: options={}
636 aggregate = PlAggregate(self)
637 return aggregate.describe(urns, version=version, options=options)
639 def status (self, urns, options=None):
640 if options is None: options={}
641 aggregate = PlAggregate(self)
642 desc = aggregate.describe(urns, version='GENI 3')
643 status = {'geni_urn': desc['geni_urn'],
644 'geni_slivers': desc['geni_slivers']}
647 def allocate (self, urn, rspec_string, expiration, options=None):
653 (*) append : if set to True, provided attributes are appended
654 to the current list of tags for the slice
655 otherwise, the set of provided attributes are meant to be the
656 the exact set of tags at the end of the call, meaning pre-existing tags
657 are deleted if not repeated in the incoming request
659 if options is None: options={}
661 aggregate = PlAggregate(self)
662 slices = PlSlices(self)
663 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
665 users = options.get('geni_users', [])
668 slice_record = users[0].get('slice_record', {})
671 rspec = RSpec(rspec_string)
672 requested_attributes = rspec.version.get_slice_attributes()
674 # ensure site record exists
675 site = slices.verify_site(xrn.hrn, slice_record, sfa_peer, options=options)
676 # ensure slice record exists
677 slice = slices.verify_slice(xrn.hrn, slice_record, sfa_peer, expiration=expiration, options=options)
678 # ensure person records exists
679 persons = slices.verify_persons(xrn.hrn, slice, users, sfa_peer, options=options)
680 # ensure slice attributes exists
681 slices.verify_slice_attributes(slice, requested_attributes, options=options)
683 # add/remove slice from nodes
684 request_nodes = rspec.version.get_nodes_with_slivers()
685 nodes = slices.verify_slice_nodes(urn, slice, request_nodes)
687 # add/remove links links
688 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
691 rspec_requested_leases = rspec.version.get_leases()
692 leases = slices.verify_slice_leases(slice, rspec_requested_leases)
694 return aggregate.describe([xrn.get_urn()], version=rspec.version)
696 def provision(self, urns, options=None):
697 if options is None: options={}
699 slices = PlSlices(self)
700 aggregate = PlAggregate(self)
701 slivers = aggregate.get_slivers(urns)
703 sliver_id_parts = Xrn(urns[0]).get_sliver_id_parts()
704 # allow to be called with an empty rspec, meaning flush reservations
708 filter['slice_id'] = int(sliver_id_parts[0])
710 filter['name'] = sliver_id_parts[0]
711 slices = self.shell.GetSlices(filter,['hrn'])
713 raise Forbidden("Unable to locate slice record for sliver: {}".format(xrn))
715 slice_urn = hrn_to_urn(slice['hrn'], type='slice')
718 slice_id = slivers[0]['slice_id']
719 slice_hrn = self.shell.GetSliceHrn(slice_id)
720 slice = self.shell.GetSlices({'slice_id': slice_id})[0]
721 slice['hrn'] = slice_hrn
722 sfa_peer = slices.get_sfa_peer(slice['hrn'])
723 users = options.get('geni_users', [])
724 persons = slices.verify_persons(slice['hrn'], slice, users, sfa_peer, options=options)
725 # update sliver allocation states and set them to geni_provisioned
726 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
727 dbsession=self.api.dbsession()
728 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned',dbsession)
730 version_manager = VersionManager()
731 rspec_version = version_manager.get_version(options['geni_rspec_version'])
732 return self.describe(urns, rspec_version, options=options)
734 def delete(self, urns, options=None):
735 if options is None: options={}
736 # collect sliver ids so we can update sliver allocation states after
737 # we remove the slivers.
738 aggregate = PlAggregate(self)
739 slivers = aggregate.get_slivers(urns)
741 slice_id = slivers[0]['slice_id']
742 slice_name = slivers[0]['name']
745 for sliver in slivers:
746 node_ids.append(sliver['node_id'])
747 sliver_ids.append(sliver['sliver_id'])
750 leases = self.shell.GetLeases({'name': slice_name, 'node_id': node_ids})
751 leases_ids = [lease['lease_id'] for lease in leases ]
753 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
755 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
756 if len(leases_ids) > 0:
757 self.shell.DeleteLeases(leases_ids)
759 # delete sliver allocation states
760 dbsession = self.api.dbsession()
761 SliverAllocation.delete_allocations(sliver_ids, dbsession)
765 # prepare return struct
767 for sliver in slivers:
769 {'geni_sliver_urn': sliver['sliver_id'],
770 'geni_allocation_status': 'geni_unallocated',
771 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
774 def renew (self, urns, expiration_time, options=None):
775 if options is None: options={}
776 aggregate = PlAggregate(self)
777 slivers = aggregate.get_slivers(urns)
779 raise SearchFailed(urns)
781 requested_time = utcparse(expiration_time)
782 record = {'expires': int(datetime_to_epoch(requested_time))}
783 self.shell.UpdateSlice(slice['slice_id'], record)
784 description = self.describe(urns, 'GENI 3', options)
785 return description['geni_slivers']
788 def perform_operational_action (self, urns, action, options=None):
789 if options is None: options={}
790 # MyPLC doesn't support operational actions. Lets pretend like it
791 # supports start, but reject everything else.
792 action = action.lower()
793 if action not in ['geni_start']:
794 raise UnsupportedOperation(action)
796 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
797 description = self.describe(urns, 'GENI 3', options)
798 for sliver in description['geni_slivers']:
799 if sliver['geni_operational_status'] == 'geni_pending_allocation':
800 raise UnsupportedOperation\
801 (action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
803 # Perform Operational Action Here
806 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
809 # set the 'enabled' tag to 0
810 def shutdown (self, xrn, options=None):
811 if options is None: options={}
812 hrn, _ = urn_to_hrn(xrn)
813 top_auth_hrn = top_auth(hrn)
814 site_hrn = '.'.join(hrn.split('.')[:-1])
815 slice_part = hrn.split('.')[-1]
816 if top_auth_hrn == self.hrn:
817 login_base = slice_hrn.split('.')[-2][:12]
819 login_base = hash_loginbase(site_hrn)
821 slicename = '_'.join([login_base, slice_part])
823 slices = self.shell.GetSlices({'peer_id': None, 'name': slicename}, ['slice_id'])
825 raise RecordNotFound(slice_hrn)
826 slice_id = slices[0]['slice_id']
827 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
829 self.shell.AddSliceTag(slice_id, 'enabled', '0')
830 elif slice_tags[0]['value'] != "0":
831 tag_id = slice_tags[0]['slice_tag_id']
832 self.shell.UpdateSliceTag(tag_id, '0')