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.alchemy import dbsession
14 from sfa.storage.model import RegRecord, SliverAllocation
15 from sfa.trust.credential import Credential
17 # used to be used in get_ticket
18 #from sfa.trust.sfaticket import SfaTicket
19 from sfa.rspecs.version_manager import VersionManager
20 from sfa.rspecs.rspec import RSpec
22 # the driver interface, mostly provides default behaviours
23 from sfa.managers.driver import Driver
24 from sfa.planetlab.plshell import PlShell
25 import sfa.planetlab.peers as peers
26 from sfa.planetlab.plaggregate import PlAggregate
27 from sfa.planetlab.plslices import PlSlices
28 from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, xrn_to_hostname, xrn_to_ext_slicename, top_auth
31 def list_to_dict(recs, key):
33 convert a list of dictionaries into a dictionary keyed on the
34 specified dictionary key
36 return dict ( [ (rec[key],rec) for rec in recs ] )
39 # PlShell is just an xmlrpc serverproxy where methods
40 # can be sent as-is; it takes care of authentication
41 # from the global config
43 class PlDriver (Driver):
45 # the cache instance is a class member so it survives across incoming requests
48 def __init__ (self, config):
49 Driver.__init__ (self, config)
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)
119 pointer = sites[0]['site_id']
121 elif type == 'slice':
122 acceptable_fields=['url', 'instantiation', 'name', 'description']
123 for key in pl_record.keys():
124 if key not in acceptable_fields:
126 slices = self.shell.GetSlices([pl_record['name']])
128 pointer = self.shell.AddSlice(pl_record)
130 pointer = slices[0]['slice_id']
133 persons = self.shell.GetPersons({'email':sfa_record['email']})
135 for key in ['first_name','last_name']:
136 if key not in sfa_record: sfa_record[key]='*from*sfa*'
137 # AddPerson does not allow everything to be set
138 can_add = ['first_name', 'last_name', 'title','email', 'password', 'phone', 'url', 'bio']
139 add_person_dict=dict ( [ (k,sfa_record[k]) for k in sfa_record if k in can_add ] )
140 pointer = self.shell.AddPerson(add_person_dict)
142 pointer = persons[0]['person_id']
144 if 'enabled' in sfa_record and sfa_record['enabled']:
145 self.shell.UpdatePerson(pointer, {'enabled': sfa_record['enabled']})
146 # add this person to the site only if she is being added for the first
147 # time by sfa and doesont already exist in plc
148 if not persons or not persons[0]['site_ids']:
149 login_base = get_leaf(sfa_record['authority'])
150 self.shell.AddPersonToSite(pointer, login_base)
152 # What roles should this user have?
154 if 'roles' in sfa_record:
155 # if specified in xml, but only low-level roles
156 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
157 # at least user if no other cluse could be found
161 self.shell.AddRoleToPerson(role, pointer)
164 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
167 login_base = PlXrn(xrn=sfa_record['authority'],type='authority').pl_login_base()
168 nodes = self.shell.GetNodes([pl_record['hostname']])
170 pointer = self.shell.AddNode(login_base, pl_record)
172 pointer = nodes[0]['node_id']
177 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
178 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
179 pointer = old_sfa_record['pointer']
180 type = old_sfa_record['type']
181 new_key_pointer = None
183 # new_key implemented for users only
184 if new_key and type not in [ 'user' ]:
185 raise UnknownSfaType(type)
187 if (type == "authority"):
188 self.shell.UpdateSite(pointer, new_sfa_record)
190 elif type == "slice":
191 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
192 if 'name' in pl_record:
193 pl_record.pop('name')
194 self.shell.UpdateSlice(pointer, pl_record)
197 # SMBAKER: UpdatePerson only allows a limited set of fields to be
198 # updated. Ideally we should have a more generic way of doing
199 # this. I copied the field names from UpdatePerson.py...
201 all_fields = new_sfa_record
202 for key in all_fields.keys():
203 if key in ['first_name', 'last_name', 'title', 'email',
204 'password', 'phone', 'url', 'bio', 'accepted_aup',
206 update_fields[key] = all_fields[key]
207 # when updating a user, we always get a 'email' field at this point
208 # this is because 'email' is a native field in the RegUser object...
209 if 'email' in update_fields and not update_fields['email']:
210 del update_fields['email']
211 self.shell.UpdatePerson(pointer, update_fields)
214 # must check this key against the previous one if it exists
215 persons = self.shell.GetPersons([pointer], ['key_ids'])
217 keys = person['key_ids']
218 keys = self.shell.GetKeys(person['key_ids'])
222 if new_key == key['key']:
224 new_key_pointer = key['key_id']
227 new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
230 self.shell.UpdateNode(pointer, new_sfa_record)
232 return (pointer, new_key_pointer)
236 def remove (self, sfa_record):
237 type=sfa_record['type']
238 pointer=sfa_record['pointer']
240 persons = self.shell.GetPersons(pointer)
241 # only delete this person if he has site ids. if he doesnt, it probably means
242 # he was just removed from a site, not actually deleted
243 if persons and persons[0]['site_ids']:
244 self.shell.DeletePerson(pointer)
245 elif type == 'slice':
246 if self.shell.GetSlices(pointer):
247 self.shell.DeleteSlice(pointer)
249 if self.shell.GetNodes(pointer):
250 self.shell.DeleteNode(pointer)
251 elif type == 'authority':
252 if self.shell.GetSites(pointer):
253 self.shell.DeleteSite(pointer)
262 # Convert SFA fields to PLC fields for use when registering or updating
263 # registry record in the PLC database
266 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
271 pl_record["name"] = hrn_to_pl_slicename(hrn)
272 if "instantiation" in sfa_record:
273 pl_record['instantiation']=sfa_record['instantiation']
275 pl_record["instantiation"] = "plc-instantiated"
276 if "url" in sfa_record:
277 pl_record["url"] = sfa_record["url"]
278 if "description" in sfa_record:
279 pl_record["description"] = sfa_record["description"]
280 if "expires" in sfa_record:
281 date = utcparse(sfa_record['expires'])
282 expires = datetime_to_epoch(date)
283 pl_record["expires"] = expires
286 if not "hostname" in pl_record:
287 # fetch from sfa_record
288 if "hostname" not in sfa_record:
289 raise MissingSfaInfo("hostname")
290 pl_record["hostname"] = sfa_record["hostname"]
291 if "model" in sfa_record:
292 pl_record["model"] = sfa_record["model"]
294 pl_record["model"] = "geni"
296 elif type == "authority":
297 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
298 if "name" not in sfa_record:
299 pl_record["name"] = hrn
300 if "abbreviated_name" not in sfa_record:
301 pl_record["abbreviated_name"] = hrn
302 if "enabled" not in sfa_record:
303 pl_record["enabled"] = True
304 if "is_public" not in sfa_record:
305 pl_record["is_public"] = True
310 def fill_record_info(self, records):
312 Given a (list of) SFA record, fill in the PLC specific
313 and SFA specific fields in the record.
315 if not isinstance(records, list):
318 self.fill_record_pl_info(records)
319 self.fill_record_hrns(records)
320 self.fill_record_sfa_info(records)
323 def fill_record_pl_info(self, records):
325 Fill in the planetlab specific fields of a SFA record. This
326 involves calling the appropriate PLC method to retrieve the
327 database record for the object.
329 @param record: record to fill in field (in/out param)
332 node_ids, site_ids, slice_ids = [], [], []
333 person_ids, key_ids = [], []
334 type_map = {'node': node_ids, 'authority': site_ids,
335 'slice': slice_ids, 'user': person_ids}
337 for record in records:
338 for type in type_map:
339 if type == record['type']:
340 type_map[type].append(record['pointer'])
343 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
345 node_list = self.shell.GetNodes(node_ids)
346 nodes = list_to_dict(node_list, 'node_id')
348 site_list = self.shell.GetSites(site_ids)
349 sites = list_to_dict(site_list, 'site_id')
351 slice_list = self.shell.GetSlices(slice_ids)
352 slices = list_to_dict(slice_list, 'slice_id')
354 person_list = self.shell.GetPersons(person_ids)
355 persons = list_to_dict(person_list, 'person_id')
356 for person in persons:
357 key_ids.extend(persons[person]['key_ids'])
359 pl_records = {'node': nodes, 'authority': sites,
360 'slice': slices, 'user': persons}
363 key_list = self.shell.GetKeys(key_ids)
364 keys = list_to_dict(key_list, 'key_id')
367 for record in records:
368 # records with pointer==-1 do not have plc info.
369 # for example, the top level authority records which are
370 # authorities, but not PL "sites"
371 if record['pointer'] == -1:
374 for type in pl_records:
375 if record['type'] == type:
376 if record['pointer'] in pl_records[type]:
377 record.update(pl_records[type][record['pointer']])
380 if record['type'] == 'user':
381 if 'key_ids' not in record:
382 logger.info("user record has no 'key_ids' - need to import from myplc ?")
384 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
385 record['keys'] = pubkeys
389 def fill_record_hrns(self, records):
391 convert pl ids to hrns
395 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
396 for record in records:
397 if 'site_id' in record:
398 site_ids.append(record['site_id'])
399 if 'site_ids' in record:
400 site_ids.extend(record['site_ids'])
401 if 'person_ids' in record:
402 person_ids.extend(record['person_ids'])
403 if 'slice_ids' in record:
404 slice_ids.extend(record['slice_ids'])
405 if 'node_ids' in record:
406 node_ids.extend(record['node_ids'])
409 slices, persons, sites, nodes = {}, {}, {}, {}
411 site_list = self.shell.GetSites(site_ids, ['site_id', 'login_base'])
412 sites = list_to_dict(site_list, 'site_id')
414 person_list = self.shell.GetPersons(person_ids, ['person_id', 'email'])
415 persons = list_to_dict(person_list, 'person_id')
417 slice_list = self.shell.GetSlices(slice_ids, ['slice_id', 'name'])
418 slices = list_to_dict(slice_list, 'slice_id')
420 node_list = self.shell.GetNodes(node_ids, ['node_id', 'hostname'])
421 nodes = list_to_dict(node_list, 'node_id')
423 # convert ids to hrns
424 for record in records:
425 # get all relevant data
426 type = record['type']
427 pointer = record['pointer']
433 if 'site_id' in record:
434 site = sites[record['site_id']]
435 login_base = site['login_base']
436 record['site'] = ".".join([auth_hrn, login_base])
437 if 'person_ids' in record:
438 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
439 if person_id in persons]
440 usernames = [email.split('@')[0] for email in emails]
441 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
442 record['persons'] = person_hrns
443 if 'slice_ids' in record:
444 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
445 if slice_id in slices]
446 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
447 record['slices'] = slice_hrns
448 if 'node_ids' in record:
449 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
451 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
452 record['nodes'] = node_hrns
453 if 'site_ids' in record:
454 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
456 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
457 record['sites'] = site_hrns
459 if 'expires' in record:
460 date = utcparse(record['expires'])
461 datestring = datetime_to_string(date)
462 record['expires'] = datestring
466 def fill_record_sfa_info(self, records):
468 def startswith(prefix, values):
469 return [value for value in values if value.startswith(prefix)]
474 for record in records:
475 person_ids.extend(record.get("person_ids", []))
476 site_ids.extend(record.get("site_ids", []))
477 if 'site_id' in record:
478 site_ids.append(record['site_id'])
480 # get all pis from the sites we've encountered
481 # and store them in a dictionary keyed on site_id
484 pi_filter = {'|roles': ['pi'], '|site_ids': site_ids}
485 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
487 # we will need the pi's hrns also
488 person_ids.append(pi['person_id'])
490 # we also need to keep track of the sites these pis
492 for site_id in pi['site_ids']:
493 if site_id in site_pis:
494 site_pis[site_id].append(pi)
496 site_pis[site_id] = [pi]
498 # get sfa records for all records associated with these records.
499 # we'll replace pl ids (person_ids) with hrns from the sfa records
502 # get the registry records
503 person_list, persons = [], {}
504 person_list = dbsession.query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
505 # create a hrns keyed on the sfa record's pointer.
506 # Its possible for multiple records to have the same pointer so
507 # the dict's value will be a list of hrns.
508 persons = defaultdict(list)
509 for person in person_list:
510 persons[person.pointer].append(person)
513 pl_person_list, pl_persons = [], {}
514 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
515 pl_persons = list_to_dict(pl_person_list, 'person_id')
518 for record in records:
519 # skip records with no pl info (top level authorities)
520 #if record['pointer'] == -1:
523 type = record['type']
524 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
525 if (type == "slice"):
526 # all slice users are researchers
527 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
529 record['researcher'] = []
530 for person_id in record.get('person_ids', []):
531 hrns = [person.hrn for person in persons[person_id]]
532 record['researcher'].extend(hrns)
534 # pis at the slice's site
535 if 'site_id' in record and record['site_id'] in site_pis:
536 pl_pis = site_pis[record['site_id']]
537 pi_ids = [pi['person_id'] for pi in pl_pis]
538 for person_id in pi_ids:
539 hrns = [person.hrn for person in persons[person_id]]
540 record['PI'].extend(hrns)
541 record['geni_creator'] = record['PI']
543 elif (type.startswith("authority")):
545 logger.info("fill_record_sfa_info - authority xherex")
546 if record['pointer'] != -1:
548 record['operator'] = []
550 for pointer in record.get('person_ids', []):
551 if pointer not in persons or pointer not in pl_persons:
552 # this means there is not sfa or pl record for this user
554 hrns = [person.hrn for person in persons[pointer]]
555 roles = pl_persons[pointer]['roles']
557 record['PI'].extend(hrns)
559 record['operator'].extend(hrns)
561 record['owner'].extend(hrns)
562 # xxx TODO: OrganizationName
563 elif (type == "node"):
564 sfa_info['dns'] = record.get("hostname", "")
565 # xxx TODO: URI, LatLong, IP, DNS
567 elif (type == "user"):
568 logger.info('setting user.email')
569 sfa_info['email'] = record.get("email", "")
570 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
571 sfa_info['geni_certificate'] = record['gid']
572 # xxx TODO: PostalAddress, Phone
573 record.update(sfa_info)
577 # plcapi works by changes, compute what needs to be added/deleted
578 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
579 # hard-wire the code for slice/user for now, could be smarter if needed
580 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
581 subject=self.shell.GetSlices (subject_id)[0]
582 current_target_ids = subject['person_ids']
583 add_target_ids = list ( set (target_ids).difference(current_target_ids))
584 del_target_ids = list ( set (current_target_ids).difference(target_ids))
585 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
586 for target_id in add_target_ids:
587 self.shell.AddPersonToSlice (target_id,subject_id)
588 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
589 for target_id in del_target_ids:
590 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
591 self.shell.DeletePersonFromSlice (target_id, subject_id)
592 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
593 # due to the plcapi limitations this means essentially adding pi role to all people in the list
594 # it's tricky to remove any pi role here, although it might be desirable
595 persons = self.shell.GetPersons (target_ids)
596 for person in persons:
597 if 'pi' not in person['roles']:
598 self.shell.AddRoleToPerson('pi',person['person_id'])
600 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
603 ########################################
604 ########## aggregate oriented
605 ########################################
607 def testbed_name (self): return "myplc"
609 def aggregate_version (self):
612 # first 2 args are None in case of resource discovery
613 def list_resources (self, version=None, options={}):
614 aggregate = PlAggregate(self)
615 rspec = aggregate.list_resources(version=version, options=options)
618 def describe(self, urns, version, options={}):
619 aggregate = PlAggregate(self)
620 return aggregate.describe(urns, version=version, options=options)
622 def status (self, urns, options={}):
623 aggregate = PlAggregate(self)
624 desc = aggregate.describe(urns, version='GENI 3')
625 status = {'geni_urn': desc['geni_urn'],
626 'geni_slivers': desc['geni_slivers']}
629 def allocate (self, urn, rspec_string, expiration, options={}):
631 aggregate = PlAggregate(self)
632 slices = PlSlices(self)
633 peer = slices.get_peer(xrn.get_hrn())
634 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
636 users = options.get('geni_users', [])
638 slice_record = users[0].get('slice_record', {})
641 rspec = RSpec(rspec_string)
642 requested_attributes = rspec.version.get_slice_attributes()
644 # ensure site record exists
645 site = slices.verify_site(xrn.hrn, slice_record, peer, sfa_peer, options=options)
646 # ensure slice record exists
647 slice = slices.verify_slice(xrn.hrn, slice_record, peer, sfa_peer, expiration=expiration, options=options)
648 # ensure person records exists
649 persons = slices.verify_persons(xrn.hrn, slice, users, peer, sfa_peer, options=options)
650 # ensure slice attributes exists
651 slices.verify_slice_attributes(slice, requested_attributes, options=options)
653 # add/remove slice from nodes
654 request_nodes = rspec.version.get_nodes_with_slivers()
655 nodes = slices.verify_slice_nodes(urn, slice, request_nodes, peer)
657 # add/remove links links
658 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
661 rspec_requested_leases = rspec.version.get_leases()
662 leases = slices.verify_slice_leases(slice, rspec_requested_leases, peer)
664 # handle MyPLC peer association.
665 # only used by plc and ple.
666 slices.handle_peer(site, slice, None, peer)
668 return aggregate.describe([xrn.get_urn()], version=rspec.version)
670 def provision(self, urns, options={}):
672 slices = PlSlices(self)
673 aggregate = PlAggregate(self)
674 slivers = aggregate.get_slivers(urns)
676 peer = slices.get_peer(slice['hrn'])
677 sfa_peer = slices.get_sfa_peer(slice['hrn'])
678 users = options.get('geni_users', [])
679 persons = slices.verify_persons(slice['hrn'], slice, users, peer, sfa_peer, options=options)
680 slices.handle_peer(None, None, persons, peer)
681 # update sliver allocation states and set them to geni_provisioned
682 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
683 SliverAllocation.set_allocations(sliver_ids, 'geni_provisioned')
684 version_manager = VersionManager()
685 rspec_version = version_manager.get_version(options['geni_rspec_version'])
686 return self.describe(urns, rspec_version, options=options)
688 def delete(self, urns, options={}):
689 # collect sliver ids so we can update sliver allocation states after
690 # we remove the slivers.
691 aggregate = PlAggregate(self)
692 slivers = aggregate.get_slivers(urns)
694 slice_id = slivers[0]['slice_id']
695 slice_name = slivers[0]['name']
698 for sliver in slivers:
699 node_ids.append(sliver['node_id'])
700 sliver_ids.append(sliver['sliver_id'])
703 leases = self.shell.GetLeases({'name': slice_name})
704 leases_ids = [lease['lease_id'] for lease in leases ]
706 # determine if this is a peer slice
707 # xxx I wonder if this would not need to use PlSlices.get_peer instead
708 # in which case plc.peers could be deprecated as this here
709 # is the only/last call to this last method in plc.peers
710 #slice_hrn = PlXrn(auth=self.hrn, slice_name).get_hrn()
711 slice_hrn = self.shell.GetSliceHrn(int(slice_id))
712 peer = peers.get_peer(self, slice_hrn)
715 self.shell.UnBindObjectFromPeer('slice', slice_id, peer)
717 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
718 if len(leases_ids) > 0:
719 self.shell.DeleteLeases(leases_ids)
721 # delete sliver allocation states
722 SliverAllocation.delete_allocations(sliver_ids)
725 self.shell.BindObjectToPeer('slice', slice_id, peer, slice['peer_slice_id'])
727 # prepare return struct
729 for sliver in slivers:
731 {'geni_sliver_urn': sliver['sliver_id'],
732 'geni_allocation_status': 'geni_unallocated',
733 'geni_expires': datetime_to_string(utcparse(sliver['expires']))})
736 def renew (self, urns, expiration_time, options={}):
737 aggregate = PlAggregate(self)
738 slivers = aggregate.get_slivers(urns)
740 raise SearchFailed(urns)
742 requested_time = utcparse(expiration_time)
743 record = {'expires': int(datetime_to_epoch(requested_time))}
744 self.shell.UpdateSlice(slice['slice_id'], record)
745 description = self.describe(urns, 'GENI 3', options)
746 return description['geni_slivers']
749 def perform_operational_action (self, urns, action, options={}):
750 # MyPLC doesn't support operational actions. Lets pretend like it
751 # supports start, but reject everything else.
752 action = action.lower()
753 if action not in ['geni_start']:
754 raise UnsupportedOperation(action)
756 # fault if sliver is not full allocated (operational status is geni_pending_allocation)
757 description = self.describe(urns, 'GENI 3', options)
758 for sliver in description['geni_slivers']:
759 if sliver['geni_operational_status'] == 'geni_pending_allocation':
760 raise UnsupportedOperation(action, "Sliver must be fully allocated (operational status is not geni_pending_allocation)")
762 # Perform Operational Action Here
765 geni_slivers = self.describe(urns, 'GENI 3', options)['geni_slivers']
768 # set the 'enabled' tag to 0
769 def shutdown (self, xrn, options={}):
770 hrn = urn_to_hrn(xrn)
771 top_auth_hrn = top_auth(hrn)
772 if top_auth_hrn == self.hrn:
773 slicename = hrn_to_pl_slicename(hrn)
775 slicename = xrn_to_ext_slicename(hrn)
776 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
778 raise RecordNotFound(slice_hrn)
779 slice_id = slices[0]['slice_id']
780 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
782 self.shell.AddSliceTag(slice_id, 'enabled', '0')
783 elif slice_tags[0]['value'] != "0":
784 tag_id = slice_tags[0]['slice_tag_id']
785 self.shell.UpdateSliceTag(tag_id, '0')