3 from sfa.util.faults import MissingSfaInfo, UnknownSfaType, \
4 RecordNotFound, SfaNotImplemented, SliverDoesNotExist, SearchFailed
5 from sfa.util.sfalogging import logger
6 from sfa.util.defaultdict import defaultdict
7 from sfa.util.sfatime import utcparse, datetime_to_string, datetime_to_epoch
8 from sfa.util.xrn import Xrn, hrn_to_urn, get_leaf
9 from sfa.util.cache import Cache
11 # one would think the driver should not need to mess with the SFA db, but..
12 from sfa.storage.alchemy import dbsession
13 from sfa.storage.model import RegRecord, SliverAllocation
15 # used to be used in get_ticket
16 #from sfa.trust.sfaticket import SfaTicket
17 from sfa.rspecs.version_manager import VersionManager
18 from sfa.rspecs.rspec import RSpec
20 # the driver interface, mostly provides default behaviours
21 from sfa.managers.driver import Driver
22 from sfa.planetlab.plshell import PlShell
23 import sfa.planetlab.peers as peers
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
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, config):
47 Driver.__init__ (self, config)
48 self.shell = PlShell (config)
50 if config.SFA_AGGREGATE_CACHING:
51 if PlDriver.cache is None:
52 PlDriver.cache = Cache()
53 self.cache = PlDriver.cache
55 ########################################
56 ########## registry oriented
57 ########################################
59 def augment_records_with_testbed_info (self, sfa_records):
60 return self.fill_record_info (sfa_records)
63 def register (self, sfa_record, hrn, pub_key):
64 type = sfa_record['type']
65 pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
67 if type == 'authority':
68 sites = self.shell.GetSites([pl_record['login_base']])
70 # xxx when a site gets registered through SFA we need to set its max_slices
71 if 'max_slices' not in pl_record:
72 pl_record['max_slices']=2
73 pointer = self.shell.AddSite(pl_record)
75 pointer = sites[0]['site_id']
78 acceptable_fields=['url', 'instantiation', 'name', 'description']
79 for key in pl_record.keys():
80 if key not in acceptable_fields:
82 slices = self.shell.GetSlices([pl_record['name']])
84 pointer = self.shell.AddSlice(pl_record)
86 pointer = slices[0]['slice_id']
89 persons = self.shell.GetPersons({'email':sfa_record['email']})
91 for key in ['first_name','last_name']:
92 if key not in sfa_record: sfa_record[key]='*from*sfa*'
93 pointer = self.shell.AddPerson(dict(sfa_record))
95 pointer = persons[0]['person_id']
97 if 'enabled' in sfa_record and sfa_record['enabled']:
98 self.shell.UpdatePerson(pointer, {'enabled': sfa_record['enabled']})
99 # add this person to the site only if she is being added for the first
100 # time by sfa and doesont already exist in plc
101 if not persons or not persons[0]['site_ids']:
102 login_base = get_leaf(sfa_record['authority'])
103 self.shell.AddPersonToSite(pointer, login_base)
105 # What roles should this user have?
107 if 'roles' in sfa_record:
108 # if specified in xml, but only low-level roles
109 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
110 # at least user if no other cluse could be found
114 self.shell.AddRoleToPerson(role, pointer)
117 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
120 login_base = PlXrn(xrn=sfa_record['authority'],type='node').pl_login_base()
121 nodes = self.shell.GetNodes([pl_record['hostname']])
123 pointer = self.shell.AddNode(login_base, pl_record)
125 pointer = nodes[0]['node_id']
130 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
131 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
132 pointer = old_sfa_record['pointer']
133 type = old_sfa_record['type']
135 # new_key implemented for users only
136 if new_key and type not in [ 'user' ]:
137 raise UnknownSfaType(type)
139 if (type == "authority"):
140 self.shell.UpdateSite(pointer, new_sfa_record)
142 elif type == "slice":
143 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
144 if 'name' in pl_record:
145 pl_record.pop('name')
146 self.shell.UpdateSlice(pointer, pl_record)
149 # SMBAKER: UpdatePerson only allows a limited set of fields to be
150 # updated. Ideally we should have a more generic way of doing
151 # this. I copied the field names from UpdatePerson.py...
153 all_fields = new_sfa_record
154 for key in all_fields.keys():
155 if key in ['first_name', 'last_name', 'title', 'email',
156 'password', 'phone', 'url', 'bio', 'accepted_aup',
158 update_fields[key] = all_fields[key]
159 # when updating a user, we always get a 'email' field at this point
160 # this is because 'email' is a native field in the RegUser object...
161 if 'email' in update_fields and not update_fields['email']:
162 del update_fields['email']
163 self.shell.UpdatePerson(pointer, update_fields)
166 # must check this key against the previous one if it exists
167 persons = self.shell.GetPersons([pointer], ['key_ids'])
169 keys = person['key_ids']
170 keys = self.shell.GetKeys(person['key_ids'])
172 # Delete all stale keys
175 if new_key != key['key']:
176 self.shell.DeleteKey(key['key_id'])
180 self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
183 self.shell.UpdateNode(pointer, new_sfa_record)
189 def remove (self, sfa_record):
190 type=sfa_record['type']
191 pointer=sfa_record['pointer']
193 persons = self.shell.GetPersons(pointer)
194 # only delete this person if he has site ids. if he doesnt, it probably means
195 # he was just removed from a site, not actually deleted
196 if persons and persons[0]['site_ids']:
197 self.shell.DeletePerson(pointer)
198 elif type == 'slice':
199 if self.shell.GetSlices(pointer):
200 self.shell.DeleteSlice(pointer)
202 if self.shell.GetNodes(pointer):
203 self.shell.DeleteNode(pointer)
204 elif type == 'authority':
205 if self.shell.GetSites(pointer):
206 self.shell.DeleteSite(pointer)
215 # Convert SFA fields to PLC fields for use when registering or updating
216 # registry record in the PLC database
219 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
224 pl_record["name"] = hrn_to_pl_slicename(hrn)
225 if "instantiation" in sfa_record:
226 pl_record['instantiation']=sfa_record['instantiation']
228 pl_record["instantiation"] = "plc-instantiated"
229 if "url" in sfa_record:
230 pl_record["url"] = sfa_record["url"]
231 if "description" in sfa_record:
232 pl_record["description"] = sfa_record["description"]
233 if "expires" in sfa_record:
234 date = utcparse(sfa_record['expires'])
235 expires = datetime_to_epoch(date)
236 pl_record["expires"] = expires
239 if not "hostname" in pl_record:
240 # fetch from sfa_record
241 if "hostname" not in sfa_record:
242 raise MissingSfaInfo("hostname")
243 pl_record["hostname"] = sfa_record["hostname"]
244 if "model" in sfa_record:
245 pl_record["model"] = sfa_record["model"]
247 pl_record["model"] = "geni"
249 elif type == "authority":
250 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
251 if "name" not in sfa_record:
252 pl_record["name"] = hrn
253 if "abbreviated_name" not in sfa_record:
254 pl_record["abbreviated_name"] = hrn
255 if "enabled" not in sfa_record:
256 pl_record["enabled"] = True
257 if "is_public" not in sfa_record:
258 pl_record["is_public"] = True
263 def fill_record_info(self, records):
265 Given a (list of) SFA record, fill in the PLC specific
266 and SFA specific fields in the record.
268 if not isinstance(records, list):
271 self.fill_record_pl_info(records)
272 self.fill_record_hrns(records)
273 self.fill_record_sfa_info(records)
276 def fill_record_pl_info(self, records):
278 Fill in the planetlab specific fields of a SFA record. This
279 involves calling the appropriate PLC method to retrieve the
280 database record for the object.
282 @param record: record to fill in field (in/out param)
285 node_ids, site_ids, slice_ids = [], [], []
286 person_ids, key_ids = [], []
287 type_map = {'node': node_ids, 'authority': site_ids,
288 'slice': slice_ids, 'user': person_ids}
290 for record in records:
291 for type in type_map:
292 if type == record['type']:
293 type_map[type].append(record['pointer'])
296 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
298 node_list = self.shell.GetNodes(node_ids)
299 nodes = list_to_dict(node_list, 'node_id')
301 site_list = self.shell.GetSites(site_ids)
302 sites = list_to_dict(site_list, 'site_id')
304 slice_list = self.shell.GetSlices(slice_ids)
305 slices = list_to_dict(slice_list, 'slice_id')
307 person_list = self.shell.GetPersons(person_ids)
308 persons = list_to_dict(person_list, 'person_id')
309 for person in persons:
310 key_ids.extend(persons[person]['key_ids'])
312 pl_records = {'node': nodes, 'authority': sites,
313 'slice': slices, 'user': persons}
316 key_list = self.shell.GetKeys(key_ids)
317 keys = list_to_dict(key_list, 'key_id')
320 for record in records:
321 # records with pointer==-1 do not have plc info.
322 # for example, the top level authority records which are
323 # authorities, but not PL "sites"
324 if record['pointer'] == -1:
327 for type in pl_records:
328 if record['type'] == type:
329 if record['pointer'] in pl_records[type]:
330 record.update(pl_records[type][record['pointer']])
333 if record['type'] == 'user':
334 if 'key_ids' not in record:
335 logger.info("user record has no 'key_ids' - need to import from myplc ?")
337 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
338 record['keys'] = pubkeys
342 def fill_record_hrns(self, records):
344 convert pl ids to hrns
348 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
349 for record in records:
350 if 'site_id' in record:
351 site_ids.append(record['site_id'])
352 if 'site_ids' in record:
353 site_ids.extend(record['site_ids'])
354 if 'person_ids' in record:
355 person_ids.extend(record['person_ids'])
356 if 'slice_ids' in record:
357 slice_ids.extend(record['slice_ids'])
358 if 'node_ids' in record:
359 node_ids.extend(record['node_ids'])
362 slices, persons, sites, nodes = {}, {}, {}, {}
364 site_list = self.shell.GetSites(site_ids, ['site_id', 'login_base'])
365 sites = list_to_dict(site_list, 'site_id')
367 person_list = self.shell.GetPersons(person_ids, ['person_id', 'email'])
368 persons = list_to_dict(person_list, 'person_id')
370 slice_list = self.shell.GetSlices(slice_ids, ['slice_id', 'name'])
371 slices = list_to_dict(slice_list, 'slice_id')
373 node_list = self.shell.GetNodes(node_ids, ['node_id', 'hostname'])
374 nodes = list_to_dict(node_list, 'node_id')
376 # convert ids to hrns
377 for record in records:
378 # get all relevant data
379 type = record['type']
380 pointer = record['pointer']
386 if 'site_id' in record:
387 site = sites[record['site_id']]
388 login_base = site['login_base']
389 record['site'] = ".".join([auth_hrn, login_base])
390 if 'person_ids' in record:
391 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
392 if person_id in persons]
393 usernames = [email.split('@')[0] for email in emails]
394 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
395 record['persons'] = person_hrns
396 if 'slice_ids' in record:
397 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
398 if slice_id in slices]
399 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
400 record['slices'] = slice_hrns
401 if 'node_ids' in record:
402 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
404 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
405 record['nodes'] = node_hrns
406 if 'site_ids' in record:
407 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
409 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
410 record['sites'] = site_hrns
412 if 'expires' in record:
413 date = utcparse(record['expires'])
414 datestring = datetime_to_string(date)
415 record['expires'] = datestring
419 def fill_record_sfa_info(self, records):
421 def startswith(prefix, values):
422 return [value for value in values if value.startswith(prefix)]
427 for record in records:
428 person_ids.extend(record.get("person_ids", []))
429 site_ids.extend(record.get("site_ids", []))
430 if 'site_id' in record:
431 site_ids.append(record['site_id'])
433 # get all pis from the sites we've encountered
434 # and store them in a dictionary keyed on site_id
437 pi_filter = {'|roles': ['pi'], '|site_ids': site_ids}
438 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
440 # we will need the pi's hrns also
441 person_ids.append(pi['person_id'])
443 # we also need to keep track of the sites these pis
445 for site_id in pi['site_ids']:
446 if site_id in site_pis:
447 site_pis[site_id].append(pi)
449 site_pis[site_id] = [pi]
451 # get sfa records for all records associated with these records.
452 # we'll replace pl ids (person_ids) with hrns from the sfa records
455 # get the registry records
456 person_list, persons = [], {}
457 person_list = dbsession.query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
458 # create a hrns keyed on the sfa record's pointer.
459 # Its possible for multiple records to have the same pointer so
460 # the dict's value will be a list of hrns.
461 persons = defaultdict(list)
462 for person in person_list:
463 persons[person.pointer].append(person)
466 pl_person_list, pl_persons = [], {}
467 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
468 pl_persons = list_to_dict(pl_person_list, 'person_id')
471 for record in records:
472 # skip records with no pl info (top level authorities)
473 #if record['pointer'] == -1:
476 type = record['type']
477 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
478 if (type == "slice"):
479 # all slice users are researchers
480 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
482 record['researcher'] = []
483 for person_id in record.get('person_ids', []):
484 hrns = [person.hrn for person in persons[person_id]]
485 record['researcher'].extend(hrns)
487 # pis at the slice's site
488 if 'site_id' in record and record['site_id'] in site_pis:
489 pl_pis = site_pis[record['site_id']]
490 pi_ids = [pi['person_id'] for pi in pl_pis]
491 for person_id in pi_ids:
492 hrns = [person.hrn for person in persons[person_id]]
493 record['PI'].extend(hrns)
494 record['geni_creator'] = record['PI']
496 elif (type.startswith("authority")):
498 logger.info("fill_record_sfa_info - authority xherex")
499 if record['pointer'] != -1:
501 record['operator'] = []
503 for pointer in record.get('person_ids', []):
504 if pointer not in persons or pointer not in pl_persons:
505 # this means there is not sfa or pl record for this user
507 hrns = [person.hrn for person in persons[pointer]]
508 roles = pl_persons[pointer]['roles']
510 record['PI'].extend(hrns)
512 record['operator'].extend(hrns)
514 record['owner'].extend(hrns)
515 # xxx TODO: OrganizationName
516 elif (type == "node"):
517 sfa_info['dns'] = record.get("hostname", "")
518 # xxx TODO: URI, LatLong, IP, DNS
520 elif (type == "user"):
521 logger.info('setting user.email')
522 sfa_info['email'] = record.get("email", "")
523 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
524 sfa_info['geni_certificate'] = record['gid']
525 # xxx TODO: PostalAddress, Phone
526 record.update(sfa_info)
530 # plcapi works by changes, compute what needs to be added/deleted
531 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
532 # hard-wire the code for slice/user for now, could be smarter if needed
533 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
534 subject=self.shell.GetSlices (subject_id)[0]
535 current_target_ids = subject['person_ids']
536 add_target_ids = list ( set (target_ids).difference(current_target_ids))
537 del_target_ids = list ( set (current_target_ids).difference(target_ids))
538 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
539 for target_id in add_target_ids:
540 self.shell.AddPersonToSlice (target_id,subject_id)
541 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
542 for target_id in del_target_ids:
543 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
544 self.shell.DeletePersonFromSlice (target_id, subject_id)
545 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
546 # due to the plcapi limitations this means essentially adding pi role to all people in the list
547 # it's tricky to remove any pi role here, although it might be desirable
548 persons = self.shell.GetPersons (target_ids)
549 for person in persons:
550 if 'pi' not in person['roles']:
551 self.shell.AddRoleToPerson('pi',person['person_id'])
553 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
556 ########################################
557 ########## aggregate oriented
558 ########################################
560 def testbed_name (self): return "myplc"
562 def aggregate_version (self):
565 # first 2 args are None in case of resource discovery
566 def list_resources (self, version=None, options={}):
567 aggregate = PlAggregate(self)
568 rspec = aggregate.list_resources(version=version, options=options)
571 def describe(self, urns, version, options={}, allocation_status=None):
572 aggregate = PlAggregate(self)
573 return aggregate.describe(urns, version=version, options=options)
575 def status (self, urns, options={}):
576 aggregate = PlAggregate(self)
577 desc = aggregate.describe(urns)
578 return desc['geni_slivers']
580 def allocate (self, urn, rspec_string, options={}):
582 aggregate = PlAggregate(self)
583 slices = PlSlices(self)
584 peer = slices.get_peer(xrn.get_hrn())
585 sfa_peer = slices.get_sfa_peer(xrn.get_hrn())
587 users = options.get('geni_users', [])
589 slice_record = users[0].get('slice_record', {})
592 rspec = RSpec(rspec_string)
593 requested_attributes = rspec.version.get_slice_attributes()
595 # ensure site record exists
596 site = slices.verify_site(xrn.hrn, slice_record, peer, sfa_peer, options=options)
597 # ensure slice record exists
598 slice = slices.verify_slice(xrn.hrn, slice_record, peer, sfa_peer, options=options)
599 # ensure person records exists
600 persons = slices.verify_persons(xrn.hrn, slice, users, peer, sfa_peer, options=options)
601 # ensure slice attributes exists
602 slices.verify_slice_attributes(slice, requested_attributes, options=options)
604 # add/remove slice from nodes
605 requested_slivers = []
606 for node in rspec.version.get_nodes_with_slivers():
608 if node.get('component_name'):
609 hostname = node.get('component_name').strip()
610 elif node.get('component_id'):
611 hostname = xrn_to_hostname(node.get('component_id').strip())
613 requested_slivers.append(hostname)
614 nodes = slices.verify_slice_nodes(slice, requested_slivers, peer)
616 # update all sliver allocation states setting then to geni_allocated
617 sliver_state_updated = {}
619 sliver_hrn = '%s.%s-%s' % (self.hrn, slice['slice_id'], node['node_id'])
620 sliver_id = Xrn(sliver_hrn, type='sliver').urn
621 sliver_state_updated[sliver_id] = False
623 constraint = SliverAllocation.sliver_id.in_(sliver_state_updated.keys())
624 cur_sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
625 for sliver_allocation in cur_sliver_allocations:
626 sliver_allocation.allocation_state = 'geni_allocated'
627 sliver_state_updated[sliver_allocation.sliver_id] = True
630 # Some states may not have been updated becuase no sliver allocation state record
631 # exists for the sliver. Insert new allocation records for these slivers and set
632 # it to geni_allocated.
633 for (sliver_id, state_updated) in sliver_state_updated.items():
634 if state_updated == False:
635 record = SliverAllocation(sliver_id=sliver_id, allocation_state='geni_allocated')
636 dbsession.add(record)
639 # add/remove links links
640 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
643 requested_leases = []
645 for lease in rspec.version.get_leases():
647 if not lease.get('lease_id'):
648 requested_lease['hostname'] = xrn_to_hostname(lease.get('component_id').strip())
649 requested_lease['start_time'] = lease.get('start_time')
650 requested_lease['duration'] = lease.get('duration')
652 kept_leases.append(int(lease['lease_id']))
653 if requested_lease.get('hostname'):
654 requested_leases.append(requested_lease)
656 leases = slices.verify_slice_leases(slice, requested_leases, kept_leases, peer)
657 # handle MyPLC peer association.
658 # only used by plc and ple.
659 slices.handle_peer(site, slice, persons, peer)
661 return aggregate.describe([xrn.get_urn()], version=rspec.version)
663 def provision(self, urns, options={}):
664 # update sliver allocation states and set them to geni_provisioned
665 aggregate = PlAggregate(self)
666 slivers = aggregate.get_slivers(urns)
667 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
668 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
669 cur_sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
670 for sliver_allocation in cur_sliver_allocations:
671 sliver_allocation.allocation_state = 'geni_provisioned'
674 return self.describe(urns, None, options=options)
676 def delete(self, urns, options={}):
678 aggregate = PlAggregate(self)
679 slivers = aggregate.get_slivers(urns)
680 slice_id = slivers[0]['slice_id']
683 for sliver in slivers:
684 node_ids.append(sliver['node_id'])
685 sliver_ids.append(sliver['sliver_id'])
687 # determine if this is a peer slice
688 # xxx I wonder if this would not need to use PlSlices.get_peer instead
689 # in which case plc.peers could be deprecated as this here
690 # is the only/last call to this last method in plc.peers
691 slice_hrn = PlXrn(auth=self.hrn, slicename=slivers[0]['name']).get_hrn()
692 peer = peers.get_peer(self, slice_hrn)
695 self.shell.UnBindObjectFromPeer('slice', slice_id, peer)
697 self.shell.DeleteSliceFromNodes(slice_id, node_ids)
699 # update slivera allocation states
700 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
701 cur_sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
702 for sliver_allocation in cur_sliver_allocations:
703 sliver_allocation.allocation_state = 'geni_unallocated'
707 self.shell.BindObjectToPeer('slice', slice_id, peer, slice['peer_slice_id'])
711 # prepare return struct
713 for node_id in node_ids:
714 sliver_hrn = '%s.%s-%s' % (self.hrn, slice_id, node_id)
716 {'geni_sliver_urn': Xrn(sliver_hrn, type='sliver').urn,
717 'geni_allocation_status': 'geni_unallocated',
718 'geni_expires': datetime_to_string(utcparse(slivers[0]['expires']))})
721 def renew (self, urns, expiration_time, options={}):
722 # we can only renew slices, not individual slivers. ignore sliver
726 xrn = PlXrn(xrn=urn, type='slice')
727 names.append(xrn.pl_slicename())
728 slices = self.shell.GetSlices(names, ['slice_id'])
730 raise SearchFailed(urns)
732 requested_time = utcparse(expiration_time)
733 record = {'expires': int(datetime_to_epoch(requested_time))}
735 self.shell.UpdateSlice(slice['slice_id'], record)
740 def perform_operational_action (self, urns, action, options={}):
741 # MyPLC doesn't support operational actions. Lets pretend like it
742 # supports start, but reject everything else.
743 action = action.lower()
744 if action == 'geni_start':
747 raise UnsupportedOperation(action)
748 description = self.describe(urns, None, options)
749 return description['geni_slivers']
751 # set the 'enabled' tag to 0
752 def shutdown (self, xrn, options={}):
753 xrn = PlXrn(xrn=xrn, type='slice')
754 slicename = xrn.pl_slicename()
755 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
757 raise RecordNotFound(slice_hrn)
758 slice_id = slices[0]['slice_id']
759 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
761 self.shell.AddSliceTag(slice_id, 'enabled', '0')
762 elif slice_tags[0]['value'] != "0":
763 tag_id = slice_tags[0]['slice_tag_id']
764 self.shell.UpdateSliceTag(tag_id, '0')