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
43 class PlDriver (Driver):
45 # the cache instance is a class member so it survives across incoming
49 def __init__(self, api):
50 Driver.__init__(self, api)
52 self.shell = PlShell(config)
54 if config.SFA_AGGREGATE_CACHING:
55 if PlDriver.cache is None:
56 PlDriver.cache = Cache()
57 self.cache = PlDriver.cache
59 def sliver_to_slice_xrn(self, xrn):
60 sliver_id_parts = Xrn(xrn).get_sliver_id_parts()
61 filter = {'peer_id': None}
63 filter['slice_id'] = int(sliver_id_parts[0])
65 filter['name'] = sliver_id_parts[0]
66 slices = self.shell.GetSlices(filter, ['hrn'])
69 "Unable to locate slice record for sliver: {}".format(xrn))
71 slice_xrn = slice['hrn']
74 def check_sliver_credentials(self, creds, urns):
75 # build list of cred object hrns
78 slice_cred_hrn = Credential(cred=cred).get_gid_object().get_hrn()
79 top_auth_hrn = top_auth(slice_cred_hrn)
80 site_hrn = '.'.join(slice_cred_hrn.split('.')[:-1])
81 slice_part = slice_cred_hrn.split('.')[-1]
82 if top_auth_hrn == self.hrn:
83 login_base = slice_cred_hrn.split('.')[-2][:12]
85 login_base = hash_loginbase(site_hrn)
87 slicename = '_'.join([login_base, slice_part])
88 slice_cred_names.append(slicename)
90 # look up slice name of slivers listed in urns arg
93 sliver_id_parts = Xrn(xrn=urn).get_sliver_id_parts()
95 slice_ids.append(int(sliver_id_parts[0]))
100 raise Forbidden("sliver urn not provided")
102 slices = self.shell.GetSlices(slice_ids)
103 sliver_names = [slice['name'] for slice in slices]
105 # make sure we have a credential for every specified sliver ierd
106 for sliver_name in sliver_names:
107 if sliver_name not in slice_cred_names:
108 msg = "Valid credential not found for target: {}".format(
112 ########################################
114 ########################################
116 def augment_records_with_testbed_info(self, sfa_records):
117 return self.fill_record_info(sfa_records)
120 def register(self, sfa_record, hrn, pub_key):
121 type = sfa_record['type']
122 pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
124 if type == 'authority':
125 sites = self.shell.GetSites(
126 {'peer_id': None, 'login_base': pl_record['login_base']})
128 # xxx when a site gets registered through SFA we need to set
130 if 'max_slices' not in pl_record:
131 pl_record['max_slices'] = 2
132 pointer = self.shell.AddSite(pl_record)
133 self.shell.SetSiteHrn(int(pointer), hrn)
135 pointer = sites[0]['site_id']
137 elif type == 'slice':
138 acceptable_fields = ['url', 'instantiation', 'name', 'description']
139 for key in pl_record.keys():
140 if key not in acceptable_fields:
142 slices = self.shell.GetSlices(
143 {'peer_id': None, 'name': pl_record['name']})
145 if not pl_record.get('url', None) or not pl_record.get('description', None):
146 pl_record['url'] = hrn
147 pl_record['description'] = hrn
149 pointer = self.shell.AddSlice(pl_record)
150 self.shell.SetSliceHrn(int(pointer), hrn)
152 pointer = slices[0]['slice_id']
155 persons = self.shell.GetPersons(
156 {'peer_id': None, 'email': sfa_record['email']})
158 for key in ['first_name', 'last_name']:
159 if key not in sfa_record:
160 sfa_record[key] = '*from*sfa*'
161 # AddPerson does not allow everything to be set
162 can_add = ['first_name', 'last_name', 'title',
163 'email', 'password', 'phone', 'url', 'bio']
164 add_person_dict = {k: sfa_record[k]
165 for k in sfa_record if k in can_add}
166 pointer = self.shell.AddPerson(add_person_dict)
167 self.shell.SetPersonHrn(int(pointer), hrn)
169 pointer = persons[0]['person_id']
171 # enable the person's account
172 self.shell.UpdatePerson(pointer, {'enabled': True})
173 # add this person to the site
174 login_base = get_leaf(sfa_record['authority'])
175 self.shell.AddPersonToSite(pointer, login_base)
177 # What roles should this user have?
179 if 'roles' in sfa_record:
180 # if specified in xml, but only low-level roles
181 roles = [role for role in sfa_record[
182 'roles'] if role in ['user', 'tech']]
183 # at least user if no other cluse could be found
187 self.shell.AddRoleToPerson(role, pointer)
190 self.shell.AddPersonKey(
191 pointer, {'key_type': 'ssh', 'key': pub_key})
195 xrn=sfa_record['authority'], type='authority').pl_login_base()
196 nodes = self.shell.GetNodes(
197 {'peer_id': None, 'hostname': pl_record['hostname']})
199 pointer = self.shell.AddNode(login_base, pl_record)
200 self.shell.SetNodeHrn(int(pointer), hrn)
202 pointer = nodes[0]['node_id']
207 # xxx actually old_sfa_record comes filled with plc stuff as well in the
209 def update(self, old_sfa_record, new_sfa_record, hrn, new_key):
210 pointer = old_sfa_record['pointer']
211 type = old_sfa_record['type']
212 new_key_pointer = None
214 # new_key implemented for users only
215 if new_key and type not in ['user']:
216 raise UnknownSfaType(type)
218 if (type == "authority"):
220 "pldriver.update: calling UpdateSite with {}".format(new_sfa_record))
221 self.shell.UpdateSite(pointer, new_sfa_record)
222 self.shell.SetSiteHrn(pointer, hrn)
224 elif type == "slice":
225 pl_record = self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
226 if 'name' in pl_record:
227 pl_record.pop('name')
228 self.shell.UpdateSlice(pointer, pl_record)
229 self.shell.SetSliceHrn(pointer, hrn)
232 # SMBAKER: UpdatePerson only allows a limited set of fields to be
233 # updated. Ideally we should have a more generic way of doing
234 # this. I copied the field names from UpdatePerson.py...
236 all_fields = new_sfa_record
237 for key in all_fields.keys():
238 if key in ['first_name', 'last_name', 'title', 'email',
239 'password', 'phone', 'url', 'bio', 'accepted_aup',
241 update_fields[key] = all_fields[key]
242 # when updating a user, we always get a 'email' field at this point
243 # this is because 'email' is a native field in the RegUser
245 if 'email' in update_fields and not update_fields['email']:
246 del update_fields['email']
247 self.shell.UpdatePerson(pointer, update_fields)
248 self.shell.SetPersonHrn(pointer, hrn)
251 # must check this key against the previous one if it exists
252 persons = self.shell.GetPersons(
253 {'peer_id': None, 'person_id': pointer}, ['key_ids'])
255 keys = person['key_ids']
256 keys = self.shell.GetKeys(person['key_ids'])
260 if new_key == key['key']:
262 new_key_pointer = key['key_id']
265 new_key_pointer = self.shell.AddPersonKey(
266 pointer, {'key_type': 'ssh', 'key': new_key})
269 self.shell.UpdateNode(pointer, new_sfa_record)
271 return (pointer, new_key_pointer)
274 def remove(self, sfa_record):
275 type = sfa_record['type']
276 pointer = sfa_record['pointer']
278 persons = self.shell.GetPersons(
279 {'peer_id': None, 'person_id': pointer})
280 # only delete this person if he has site ids. if he doesnt, it probably means
281 # he was just removed from a site, not actually deleted
282 if persons and persons[0]['site_ids']:
283 self.shell.DeletePerson(pointer)
284 elif type == 'slice':
285 if self.shell.GetSlices({'peer_id': None, 'slice_id': pointer}):
286 self.shell.DeleteSlice(pointer)
288 if self.shell.GetNodes({'peer_id': None, 'node_id': pointer}):
289 self.shell.DeleteNode(pointer)
290 elif type == 'authority':
291 if self.shell.GetSites({'peer_id': None, 'site_id': pointer}):
292 self.shell.DeleteSite(pointer)
297 # Convert SFA fields to PLC fields for use when registering or updating
298 # registry record in the PLC database
301 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
306 pl_record["name"] = hrn_to_pl_slicename(hrn)
307 if "instantiation" in sfa_record:
308 pl_record['instantiation'] = sfa_record['instantiation']
310 pl_record["instantiation"] = "plc-instantiated"
311 if "url" in sfa_record:
312 pl_record["url"] = sfa_record["url"]
313 if "description" in sfa_record:
314 pl_record["description"] = sfa_record["description"]
315 if "expires" in sfa_record:
316 date = utcparse(sfa_record['expires'])
317 expires = datetime_to_epoch(date)
318 pl_record["expires"] = expires
321 if not "hostname" in pl_record:
322 # fetch from sfa_record
323 if "hostname" not in sfa_record:
324 raise MissingSfaInfo("hostname")
325 pl_record["hostname"] = sfa_record["hostname"]
326 if "model" in sfa_record:
327 pl_record["model"] = sfa_record["model"]
329 pl_record["model"] = "geni"
331 elif type == "authority":
332 pl_record["login_base"] = PlXrn(
333 xrn=hrn, type='authority').pl_login_base()
334 if "name" not in sfa_record or not sfa_record['name']:
335 pl_record["name"] = hrn
336 if "abbreviated_name" not in sfa_record:
337 pl_record["abbreviated_name"] = hrn
338 if "enabled" not in sfa_record:
339 pl_record["enabled"] = True
340 if "is_public" not in sfa_record:
341 pl_record["is_public"] = True
346 def fill_record_info(self, records):
348 Given a (list of) SFA record, fill in the PLC specific
349 and SFA specific fields in the record.
351 if not isinstance(records, list):
354 self.fill_record_pl_info(records)
355 self.fill_record_hrns(records)
356 self.fill_record_sfa_info(records)
359 def fill_record_pl_info(self, records):
361 Fill in the planetlab specific fields of a SFA record. This
362 involves calling the appropriate PLC method to retrieve the
363 database record for the object.
365 @param record: record to fill in field (in/out param)
368 node_ids, site_ids, slice_ids = [], [], []
369 person_ids, key_ids = [], []
370 type_map = {'node': node_ids, 'authority': site_ids,
371 'slice': slice_ids, 'user': person_ids}
373 for record in records:
374 for type in type_map:
375 if type == record['type']:
376 type_map[type].append(record['pointer'])
379 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
381 node_list = self.shell.GetNodes(
382 {'peer_id': None, 'node_id': node_ids})
383 nodes = list_to_dict(node_list, 'node_id')
385 site_list = self.shell.GetSites(
386 {'peer_id': None, 'site_id': site_ids})
387 sites = list_to_dict(site_list, 'site_id')
389 slice_list = self.shell.GetSlices(
390 {'peer_id': None, 'slice_id': slice_ids})
391 slices = list_to_dict(slice_list, 'slice_id')
393 person_list = self.shell.GetPersons(
394 {'peer_id': None, 'person_id': person_ids})
395 persons = list_to_dict(person_list, 'person_id')
396 for person in persons:
397 key_ids.extend(persons[person]['key_ids'])
399 pl_records = {'node': nodes, 'authority': sites,
400 'slice': slices, 'user': persons}
403 key_list = self.shell.GetKeys(key_ids)
404 keys = list_to_dict(key_list, 'key_id')
407 for record in records:
408 # records with pointer==-1 do not have plc info.
409 # for example, the top level authority records which are
410 # authorities, but not PL "sites"
411 if record['pointer'] == -1:
414 for type in pl_records:
415 if record['type'] == type:
416 if record['pointer'] in pl_records[type]:
417 record.update(pl_records[type][record['pointer']])
420 if record['type'] == 'user':
421 if 'key_ids' not in record:
423 "user record has no 'key_ids' - need to import from myplc ?")
425 pubkeys = [keys[key_id]['key']
426 for key_id in record['key_ids'] if key_id in keys]
427 record['keys'] = pubkeys
431 def fill_record_hrns(self, records):
433 convert pl ids to hrns
437 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
438 for record in records:
439 if 'site_id' in record:
440 site_ids.append(record['site_id'])
441 if 'site_ids' in record:
442 site_ids.extend(record['site_ids'])
443 if 'person_ids' in record:
444 person_ids.extend(record['person_ids'])
445 if 'slice_ids' in record:
446 slice_ids.extend(record['slice_ids'])
447 if 'node_ids' in record:
448 node_ids.extend(record['node_ids'])
451 slices, persons, sites, nodes = {}, {}, {}, {}
453 site_list = self.shell.GetSites({'peer_id': None, 'site_id': site_ids}, [
454 'site_id', 'login_base'])
455 sites = list_to_dict(site_list, 'site_id')
457 person_list = self.shell.GetPersons(
458 {'peer_id': None, 'person_id': person_ids}, ['person_id', 'email'])
459 persons = list_to_dict(person_list, 'person_id')
461 slice_list = self.shell.GetSlices(
462 {'peer_id': None, 'slice_id': slice_ids}, ['slice_id', 'name'])
463 slices = list_to_dict(slice_list, 'slice_id')
465 node_list = self.shell.GetNodes(
466 {'peer_id': None, 'node_id': node_ids}, ['node_id', 'hostname'])
467 nodes = list_to_dict(node_list, 'node_id')
469 # convert ids to hrns
470 for record in records:
471 # get all relevant data
472 type = record['type']
473 pointer = record['pointer']
479 if 'site_id' in record:
480 site = sites[record['site_id']]
481 login_base = site['login_base']
482 record['site'] = ".".join([auth_hrn, login_base])
483 if 'person_ids' in record:
484 emails = [persons[person_id]['email'] for person_id in record['person_ids']
485 if person_id in persons]
486 usernames = [email.split('@')[0] for email in emails]
487 person_hrns = [".".join([auth_hrn, login_base, username])
488 for username in usernames]
489 record['persons'] = person_hrns
490 if 'slice_ids' in record:
491 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids']
492 if slice_id in slices]
493 slice_hrns = [slicename_to_hrn(
494 auth_hrn, slicename) for slicename in slicenames]
495 record['slices'] = slice_hrns
496 if 'node_ids' in record:
497 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids']
499 node_hrns = [hostname_to_hrn(
500 auth_hrn, login_base, hostname) for hostname in hostnames]
501 record['nodes'] = node_hrns
502 if 'site_ids' in record:
503 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids']
505 site_hrns = [".".join([auth_hrn, lbase])
506 for lbase in login_bases]
507 record['sites'] = site_hrns
509 if 'expires' in record:
510 date = utcparse(record['expires'])
511 datestring = datetime_to_string(date)
512 record['expires'] = datestring
516 def fill_record_sfa_info(self, records):
518 def startswith(prefix, values):
519 return [value for value in values if value.startswith(prefix)]
524 for record in records:
525 person_ids.extend(record.get("person_ids", []))
526 site_ids.extend(record.get("site_ids", []))
527 if 'site_id' in record:
528 site_ids.append(record['site_id'])
530 # get all pis from the sites we've encountered
531 # and store them in a dictionary keyed on site_id
534 pi_filter = {'peer_id': None, '|roles': [
535 'pi'], '|site_ids': site_ids}
536 pi_list = self.shell.GetPersons(
537 pi_filter, ['person_id', 'site_ids'])
539 # we will need the pi's hrns also
540 person_ids.append(pi['person_id'])
542 # we also need to keep track of the sites these pis
544 for site_id in pi['site_ids']:
545 if site_id in site_pis:
546 site_pis[site_id].append(pi)
548 site_pis[site_id] = [pi]
550 # get sfa records for all records associated with these records.
551 # we'll replace pl ids (person_ids) with hrns from the sfa records
554 # get the registry records
555 person_list, persons = [], {}
556 person_list = self.api.dbsession().query(
557 RegRecord).filter(RegRecord.pointer.in_(person_ids))
558 # create a hrns keyed on the sfa record's pointer.
559 # Its possible for multiple records to have the same pointer so
560 # the dict's value will be a list of hrns.
561 persons = defaultdict(list)
562 for person in person_list:
563 persons[person.pointer].append(person)
566 pl_person_list, pl_persons = [], {}
567 pl_person_list = self.shell.GetPersons(
568 person_ids, ['person_id', 'roles'])
569 pl_persons = list_to_dict(pl_person_list, 'person_id')
572 for record in records:
573 # skip records with no pl info (top level authorities)
574 # if record['pointer'] == -1:
577 type = record['type']
579 "fill_record_sfa_info - incoming record typed {}".format(type))
580 if (type == "slice"):
581 # all slice users are researchers
582 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
584 record['researcher'] = []
585 for person_id in record.get('person_ids', []):
586 hrns = [person.hrn for person in persons[person_id]]
587 record['researcher'].extend(hrns)
589 # pis at the slice's site
590 if 'site_id' in record and record['site_id'] in site_pis:
591 pl_pis = site_pis[record['site_id']]
592 pi_ids = [pi['person_id'] for pi in pl_pis]
593 for person_id in pi_ids:
594 hrns = [person.hrn for person in persons[person_id]]
595 record['PI'].extend(hrns)
596 record['geni_creator'] = record['PI']
598 elif (type.startswith("authority")):
600 logger.info("fill_record_sfa_info - authority xherex")
601 if record['pointer'] != -1:
603 record['operator'] = []
605 for pointer in record.get('person_ids', []):
606 if pointer not in persons or pointer not in pl_persons:
607 # this means there is not sfa or pl record for this
610 hrns = [person.hrn for person in persons[pointer]]
611 roles = pl_persons[pointer]['roles']
613 record['PI'].extend(hrns)
615 record['operator'].extend(hrns)
617 record['owner'].extend(hrns)
618 # xxx TODO: OrganizationName
619 elif (type == "node"):
620 sfa_info['dns'] = record.get("hostname", "")
621 # xxx TODO: URI, LatLong, IP, DNS
623 elif (type == "user"):
624 logger.info('setting user.email')
625 sfa_info['email'] = record.get("email", "")
626 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
627 sfa_info['geni_certificate'] = record['gid']
628 # xxx TODO: PostalAddress, Phone
629 record.update(sfa_info)
632 # plcapi works by changes, compute what needs to be added/deleted
633 def update_relation(self, subject_type, target_type, relation_name, subject_id, target_ids):
634 # hard-wire the code for slice/user for now, could be smarter if needed
635 if subject_type == 'slice' and target_type == 'user' and relation_name == 'researcher':
636 subject = self.shell.GetSlices(subject_id)[0]
637 current_target_ids = subject['person_ids']
638 add_target_ids = list(
639 set(target_ids).difference(current_target_ids))
640 del_target_ids = list(
641 set(current_target_ids).difference(target_ids))
642 logger.debug("subject_id = {} (type={})".format(
643 subject_id, type(subject_id)))
644 for target_id in add_target_ids:
645 self.shell.AddPersonToSlice(target_id, subject_id)
646 logger.debug("add_target_id = {} (type={})".format(
647 target_id, type(target_id)))
648 for target_id in del_target_ids:
649 logger.debug("del_target_id = {} (type={})".format(
650 target_id, type(target_id)))
651 self.shell.DeletePersonFromSlice(target_id, subject_id)
652 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
653 # due to the plcapi limitations this means essentially adding pi role to all people in the list
654 # it's tricky to remove any pi role here, although it might be
656 persons = self.shell.GetPersons(
657 {'peer_id': None, 'person_id': target_ids})
658 for person in persons:
659 if 'pi' not in person['roles']:
660 self.shell.AddRoleToPerson('pi', person['person_id'])
662 logger.info('unexpected relation {} to maintain, {} -> {}'
663 .format(relation_name, subject_type, target_type))
665 ########################################
667 ########################################
669 def testbed_name(self): return "myplc"
671 def aggregate_version(self):
674 # first 2 args are None in case of resource discovery
675 def list_resources(self, version=None, options=None):
678 aggregate = PlAggregate(self)
679 rspec = aggregate.list_resources(version=version, options=options)
682 def describe(self, urns, version, options=None):
685 aggregate = PlAggregate(self)
686 return aggregate.describe(urns, version=version, options=options)
688 def status(self, urns, options=None):
691 aggregate = PlAggregate(self)
692 desc = aggregate.describe(urns, version='GENI 3')
693 status = {'geni_urn': desc['geni_urn'],
694 'geni_slivers': desc['geni_slivers']}
697 def allocate(self, urn, rspec_string, expiration, options=None):
703 (*) append : if set to True, provided attributes are appended
704 to the current list of tags for the slice
705 otherwise, the set of provided attributes are meant to be the
706 the exact set of tags at the end of the call, meaning pre-existing tags
707 are deleted if not repeated in the incoming request
712 aggregate = PlAggregate(self)
713 slices = PlSlices(self)
714 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
716 users = options.get('geni_users', [])
719 slice_record = users[0].get('slice_record', {})
722 rspec = RSpec(rspec_string)
723 requested_attributes = rspec.version.get_slice_attributes()
725 # ensure site record exists
726 site = slices.verify_site(
727 xrn.hrn, slice_record, sfa_peer, options=options)
728 # ensure slice record exists
729 slice = slices.verify_slice(
730 xrn.hrn, slice_record, sfa_peer, expiration=expiration, options=options)
731 # ensure person records exists
732 persons = slices.verify_persons(
733 xrn.hrn, slice, users, sfa_peer, options=options)
734 # ensure slice attributes exists
735 slices.verify_slice_tags(slice, requested_attributes, options=options)
737 # add/remove slice from nodes
738 request_nodes = rspec.version.get_nodes_with_slivers()
739 nodes = slices.verify_slice_nodes(urn, slice, request_nodes)
741 # add/remove links links
742 slices.verify_slice_links(
743 slice, rspec.version.get_link_requests(), nodes)
746 rspec_requested_leases = rspec.version.get_leases()
747 leases = slices.verify_slice_leases(slice, rspec_requested_leases)
749 return aggregate.describe([xrn.get_urn()], version=rspec.version)
751 def provision(self, urns, options=None):
755 slices = PlSlices(self)
756 aggregate = PlAggregate(self)
757 slivers = aggregate.get_slivers(urns)
759 sliver_id_parts = Xrn(urns[0]).get_sliver_id_parts()
760 # allow to be called with an empty rspec, meaning flush
765 filter['slice_id'] = int(sliver_id_parts[0])
767 filter['name'] = sliver_id_parts[0]
768 slices = self.shell.GetSlices(filter, ['hrn'])
771 "Unable to locate slice record for sliver: {}".format(xrn))
773 slice_urn = hrn_to_urn(slice['hrn'], type='slice')
776 slice_id = slivers[0]['slice_id']
777 slice_hrn = self.shell.GetSliceHrn(slice_id)
778 slice = self.shell.GetSlices({'slice_id': slice_id})[0]
779 slice['hrn'] = slice_hrn
780 sfa_peer = slices.get_sfa_peer(slice['hrn'])
781 users = options.get('geni_users', [])
782 persons = slices.verify_persons(
783 slice['hrn'], slice, users, sfa_peer, options=options)
784 # update sliver allocation states and set them to geni_provisioned
785 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
786 dbsession = self.api.dbsession()
787 SliverAllocation.set_allocations(
788 sliver_ids, 'geni_provisioned', dbsession)
790 version_manager = VersionManager()
791 rspec_version = version_manager.get_version(
792 options['geni_rspec_version'])
793 return self.describe(urns, rspec_version, options=options)
795 def delete(self, urns, options=None):
798 # collect sliver ids so we can update sliver allocation states after
799 # we remove the slivers.
800 aggregate = PlAggregate(self)
801 slivers = aggregate.get_slivers(urns)
803 slice_id = slivers[0]['slice_id']
804 slice_name = slivers[0]['name']
807 for sliver in slivers:
808 node_ids.append(sliver['node_id'])
809 sliver_ids.append(sliver['sliver_id'])
812 leases = self.shell.GetLeases(
813 {'name': slice_name, 'node_id': node_ids})
814 leases_ids = [lease['lease_id'] for lease in leases]
816 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
818 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
819 if len(leases_ids) > 0:
820 self.shell.DeleteLeases(leases_ids)
822 # delete sliver allocation states
823 dbsession = self.api.dbsession()
824 SliverAllocation.delete_allocations(sliver_ids, dbsession)
828 # prepare return struct
830 for sliver in slivers:
832 {'geni_sliver_urn': sliver['sliver_id'],
833 'geni_allocation_status': 'geni_unallocated',
834 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
837 def renew(self, urns, expiration_time, options=None):
840 aggregate = PlAggregate(self)
841 slivers = aggregate.get_slivers(urns)
843 raise SearchFailed(urns)
845 requested_time = utcparse(expiration_time)
846 record = {'expires': int(datetime_to_epoch(requested_time))}
847 self.shell.UpdateSlice(slice['slice_id'], record)
848 description = self.describe(urns, 'GENI 3', options)
849 return description['geni_slivers']
851 def perform_operational_action(self, urns, action, options=None):
854 # MyPLC doesn't support operational actions. Lets pretend like it
855 # supports start, but reject everything else.
856 action = action.lower()
857 if action not in ['geni_start']:
858 raise UnsupportedOperation(action)
860 # fault if sliver is not full allocated (operational status is
861 # geni_pending_allocation)
862 description = self.describe(urns, 'GENI 3', options)
863 for sliver in description['geni_slivers']:
864 if sliver['geni_operational_status'] == 'geni_pending_allocation':
865 raise UnsupportedOperation\
866 (action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
868 # Perform Operational Action Here
871 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
874 # set the 'enabled' tag to 0
875 def shutdown(self, xrn, options=None):
878 hrn, _ = urn_to_hrn(xrn)
879 top_auth_hrn = top_auth(hrn)
880 site_hrn = '.'.join(hrn.split('.')[:-1])
881 slice_part = hrn.split('.')[-1]
882 if top_auth_hrn == self.hrn:
883 login_base = slice_hrn.split('.')[-2][:12]
885 login_base = hash_loginbase(site_hrn)
887 slicename = '_'.join([login_base, slice_part])
889 slices = self.shell.GetSlices(
890 {'peer_id': None, 'name': slicename}, ['slice_id'])
892 raise RecordNotFound(slice_hrn)
893 slice_id = slices[0]['slice_id']
894 slice_tags = self.shell.GetSliceTags(
895 {'slice_id': slice_id, 'tagname': 'enabled'})
897 self.shell.AddSliceTag(slice_id, 'enabled', '0')
898 elif slice_tags[0]['value'] != "0":
899 tag_id = slice_tags[0]['slice_tag_id']
900 self.shell.UpdateSliceTag(tag_id, '0')