4 from sfa.util.faults import MissingSfaInfo, UnknownSfaType, \
5 RecordNotFound, SfaNotImplemented, SliverDoesNotExist
7 from sfa.util.sfalogging import logger
8 from sfa.util.defaultdict import defaultdict
9 from sfa.util.sfatime import utcparse, datetime_to_string, datetime_to_epoch
10 from sfa.util.xrn import Xrn, hrn_to_urn, get_leaf
11 from sfa.util.cache import Cache
13 # one would think the driver should not need to mess with the SFA db, but..
14 from sfa.storage.alchemy import dbsession
15 from sfa.storage.model import RegRecord
17 # used to be used in get_ticket
18 #from sfa.trust.sfaticket import SfaTicket
20 from sfa.rspecs.version_manager import VersionManager
21 from sfa.rspecs.rspec import RSpec
23 # the driver interface, mostly provides default behaviours
24 from sfa.managers.driver import Driver
26 from sfa.planetlab.plshell import PlShell
27 import sfa.planetlab.peers as peers
28 from sfa.planetlab.plaggregate import PlAggregate
29 from sfa.planetlab.plslices import PlSlices
30 from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, xrn_to_hostname, top_auth, hash_loginbase
33 def list_to_dict(recs, key):
35 convert a list of dictionaries into a dictionary keyed on the
36 specified dictionary key
38 return dict ( [ (rec[key],rec) for rec in recs ] )
41 # PlShell is just an xmlrpc serverproxy where methods
42 # can be sent as-is; it takes care of authentication
43 # from the global config
45 class PlDriver (Driver):
47 # the cache instance is a class member so it survives across incoming requests
50 def __init__ (self, config):
51 Driver.__init__ (self, config)
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 ########################################
60 ########## registry oriented
61 ########################################
63 def augment_records_with_testbed_info (self, sfa_records):
64 return self.fill_record_info (sfa_records)
67 def register (self, sfa_record, hrn, pub_key):
68 type = sfa_record['type']
69 pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
71 if type == 'authority':
72 sites = self.shell.GetSites([pl_record['login_base']])
74 # xxx when a site gets registered through SFA we need to set its max_slices
75 if 'max_slices' not in pl_record:
76 pl_record['max_slices']=2
77 pointer = self.shell.AddSite(pl_record)
78 self.shell.SetSiteHrn(int(pointer), hrn)
80 pointer = sites[0]['site_id']
83 acceptable_fields=['url', 'instantiation', 'name', 'description']
84 for key in pl_record.keys():
85 if key not in acceptable_fields:
87 slices = self.shell.GetSlices([pl_record['name']])
89 pointer = self.shell.AddSlice(pl_record)
90 self.shell.SetSliceHrn(int(pointer), hrn)
92 pointer = slices[0]['slice_id']
95 persons = self.shell.GetPersons({'email':sfa_record['email']})
97 for key in ['first_name','last_name']:
98 if key not in sfa_record: sfa_record[key]='*from*sfa*'
99 # AddPerson does not allow everything to be set
100 can_add = ['first_name', 'last_name', 'title','email', 'password', 'phone', 'url', 'bio']
101 add_person_dict=dict ( [ (k,sfa_record[k]) for k in sfa_record if k in can_add ] )
102 pointer = self.shell.AddPerson(add_person_dict)
103 self.shell.SetPersonHrn(int(pointer), hrn)
105 pointer = persons[0]['person_id']
107 if 'enabled' in sfa_record and sfa_record['enabled']:
108 self.shell.UpdatePerson(pointer, {'enabled': sfa_record['enabled']})
109 # add this person to the site only if she is being added for the first
110 # time by sfa and doesont already exist in plc
111 if not persons or not persons[0]['site_ids']:
112 login_base = get_leaf(sfa_record['authority'])
113 self.shell.AddPersonToSite(pointer, login_base)
115 # What roles should this user have?
117 if 'roles' in sfa_record:
118 # if specified in xml, but only low-level roles
119 roles = [ role for role in sfa_record['roles'] if role in ['user','tech'] ]
120 # at least user if no other cluse could be found
124 self.shell.AddRoleToPerson(role, pointer)
127 self.shell.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
130 login_base = PlXrn(xrn=sfa_record['authority'],type='authority').pl_login_base()
131 nodes = self.shell.GetNodes([pl_record['hostname']])
133 pointer = self.shell.AddNode(login_base, pl_record)
134 self.shell.SetNodeHrn(int(pointer), hrn)
136 pointer = nodes[0]['node_id']
141 # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
142 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
143 pointer = old_sfa_record['pointer']
144 type = old_sfa_record['type']
145 new_key_pointer = None
147 # new_key implemented for users only
148 if new_key and type not in [ 'user' ]:
149 raise UnknownSfaType(type)
151 if (type == "authority"):
152 self.shell.UpdateSite(pointer, new_sfa_record)
153 self.shell.SetSiteHrn(pointer, hrn)
155 elif type == "slice":
156 pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
157 if 'name' in pl_record:
158 pl_record.pop('name')
159 self.shell.UpdateSlice(pointer, pl_record)
160 self.shell.SetSliceHrn(pointer, hrn)
163 # SMBAKER: UpdatePerson only allows a limited set of fields to be
164 # updated. Ideally we should have a more generic way of doing
165 # this. I copied the field names from UpdatePerson.py...
167 all_fields = new_sfa_record
168 for key in all_fields.keys():
169 if key in ['first_name', 'last_name', 'title', 'email',
170 'password', 'phone', 'url', 'bio', 'accepted_aup',
172 update_fields[key] = all_fields[key]
173 # when updating a user, we always get a 'email' field at this point
174 # this is because 'email' is a native field in the RegUser object...
175 if 'email' in update_fields and not update_fields['email']:
176 del update_fields['email']
177 self.shell.UpdatePerson(pointer, update_fields)
178 self.shell.SetPersonHrn(pointer, hrn)
181 # must check this key against the previous one if it exists
182 persons = self.shell.GetPersons([pointer], ['key_ids'])
184 keys = person['key_ids']
185 keys = self.shell.GetKeys(person['key_ids'])
189 if new_key == key['key']:
191 new_key_pointer = key['key_id']
194 new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
197 self.shell.UpdateNode(pointer, new_sfa_record)
199 return (pointer, new_key_pointer)
203 def remove (self, sfa_record):
204 type=sfa_record['type']
205 pointer=sfa_record['pointer']
207 persons = self.shell.GetPersons(pointer)
208 # only delete this person if he has site ids. if he doesnt, it probably means
209 # he was just removed from a site, not actually deleted
210 if persons and persons[0]['site_ids']:
211 self.shell.DeletePerson(pointer)
212 elif type == 'slice':
213 if self.shell.GetSlices(pointer):
214 self.shell.DeleteSlice(pointer)
216 if self.shell.GetNodes(pointer):
217 self.shell.DeleteNode(pointer)
218 elif type == 'authority':
219 if self.shell.GetSites(pointer):
220 self.shell.DeleteSite(pointer)
229 # Convert SFA fields to PLC fields for use when registering or updating
230 # registry record in the PLC database
233 def sfa_fields_to_pl_fields(self, type, hrn, sfa_record):
238 pl_record["name"] = hrn_to_pl_slicename(hrn)
239 if "instantiation" in sfa_record:
240 pl_record['instantiation']=sfa_record['instantiation']
242 pl_record["instantiation"] = "plc-instantiated"
243 if "url" in sfa_record:
244 pl_record["url"] = sfa_record["url"]
245 if "description" in sfa_record:
246 pl_record["description"] = sfa_record["description"]
247 if "expires" in sfa_record:
248 date = utcparse(sfa_record['expires'])
249 expires = datetime_to_epoch(date)
250 pl_record["expires"] = expires
253 if not "hostname" in pl_record:
254 # fetch from sfa_record
255 if "hostname" not in sfa_record:
256 raise MissingSfaInfo("hostname")
257 pl_record["hostname"] = sfa_record["hostname"]
258 if "model" in sfa_record:
259 pl_record["model"] = sfa_record["model"]
261 pl_record["model"] = "geni"
263 elif type == "authority":
264 pl_record["login_base"] = PlXrn(xrn=hrn,type='authority').pl_login_base()
265 if "name" not in sfa_record:
266 pl_record["name"] = hrn
267 if "abbreviated_name" not in sfa_record:
268 pl_record["abbreviated_name"] = hrn
269 if "enabled" not in sfa_record:
270 pl_record["enabled"] = True
271 if "is_public" not in sfa_record:
272 pl_record["is_public"] = True
277 def fill_record_info(self, records):
279 Given a (list of) SFA record, fill in the PLC specific
280 and SFA specific fields in the record.
282 if not isinstance(records, list):
285 self.fill_record_pl_info(records)
286 self.fill_record_hrns(records)
287 self.fill_record_sfa_info(records)
290 def fill_record_pl_info(self, records):
292 Fill in the planetlab specific fields of a SFA record. This
293 involves calling the appropriate PLC method to retrieve the
294 database record for the object.
296 @param record: record to fill in field (in/out param)
299 node_ids, site_ids, slice_ids = [], [], []
300 person_ids, key_ids = [], []
301 type_map = {'node': node_ids, 'authority': site_ids,
302 'slice': slice_ids, 'user': person_ids}
304 for record in records:
305 for type in type_map:
306 if type == record['type']:
307 type_map[type].append(record['pointer'])
310 nodes, sites, slices, persons, keys = {}, {}, {}, {}, {}
312 node_list = self.shell.GetNodes(node_ids)
313 nodes = list_to_dict(node_list, 'node_id')
315 site_list = self.shell.GetSites(site_ids)
316 sites = list_to_dict(site_list, 'site_id')
318 slice_list = self.shell.GetSlices(slice_ids)
319 slices = list_to_dict(slice_list, 'slice_id')
321 person_list = self.shell.GetPersons(person_ids)
322 persons = list_to_dict(person_list, 'person_id')
323 for person in persons:
324 key_ids.extend(persons[person]['key_ids'])
326 pl_records = {'node': nodes, 'authority': sites,
327 'slice': slices, 'user': persons}
330 key_list = self.shell.GetKeys(key_ids)
331 keys = list_to_dict(key_list, 'key_id')
334 for record in records:
335 # records with pointer==-1 do not have plc info.
336 # for example, the top level authority records which are
337 # authorities, but not PL "sites"
338 if record['pointer'] == -1:
341 for type in pl_records:
342 if record['type'] == type:
343 if record['pointer'] in pl_records[type]:
344 record.update(pl_records[type][record['pointer']])
347 if record['type'] == 'user':
348 if 'key_ids' not in record:
349 logger.info("user record has no 'key_ids' - need to import from myplc ?")
351 pubkeys = [keys[key_id]['key'] for key_id in record['key_ids'] if key_id in keys]
352 record['keys'] = pubkeys
356 def fill_record_hrns(self, records):
358 convert pl ids to hrns
362 slice_ids, person_ids, site_ids, node_ids = [], [], [], []
363 for record in records:
364 if 'site_id' in record:
365 site_ids.append(record['site_id'])
366 if 'site_ids' in record:
367 site_ids.extend(record['site_ids'])
368 if 'person_ids' in record:
369 person_ids.extend(record['person_ids'])
370 if 'slice_ids' in record:
371 slice_ids.extend(record['slice_ids'])
372 if 'node_ids' in record:
373 node_ids.extend(record['node_ids'])
376 slices, persons, sites, nodes = {}, {}, {}, {}
378 site_list = self.shell.GetSites(site_ids, ['site_id', 'login_base'])
379 sites = list_to_dict(site_list, 'site_id')
381 person_list = self.shell.GetPersons(person_ids, ['person_id', 'email'])
382 persons = list_to_dict(person_list, 'person_id')
384 slice_list = self.shell.GetSlices(slice_ids, ['slice_id', 'name'])
385 slices = list_to_dict(slice_list, 'slice_id')
387 node_list = self.shell.GetNodes(node_ids, ['node_id', 'hostname'])
388 nodes = list_to_dict(node_list, 'node_id')
390 # convert ids to hrns
391 for record in records:
392 # get all relevant data
393 type = record['type']
394 pointer = record['pointer']
400 if 'site_id' in record:
401 site = sites[record['site_id']]
402 login_base = site['login_base']
403 record['site'] = ".".join([auth_hrn, login_base])
404 if 'person_ids' in record:
405 emails = [persons[person_id]['email'] for person_id in record['person_ids'] \
406 if person_id in persons]
407 usernames = [email.split('@')[0] for email in emails]
408 person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
409 record['persons'] = person_hrns
410 if 'slice_ids' in record:
411 slicenames = [slices[slice_id]['name'] for slice_id in record['slice_ids'] \
412 if slice_id in slices]
413 slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
414 record['slices'] = slice_hrns
415 if 'node_ids' in record:
416 hostnames = [nodes[node_id]['hostname'] for node_id in record['node_ids'] \
418 node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
419 record['nodes'] = node_hrns
420 if 'site_ids' in record:
421 login_bases = [sites[site_id]['login_base'] for site_id in record['site_ids'] \
423 site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
424 record['sites'] = site_hrns
426 if 'expires' in record:
427 date = utcparse(record['expires'])
428 datestring = datetime_to_string(date)
429 record['expires'] = datestring
433 def fill_record_sfa_info(self, records):
435 def startswith(prefix, values):
436 return [value for value in values if value.startswith(prefix)]
441 for record in records:
442 person_ids.extend(record.get("person_ids", []))
443 site_ids.extend(record.get("site_ids", []))
444 if 'site_id' in record:
445 site_ids.append(record['site_id'])
447 # get all pis from the sites we've encountered
448 # and store them in a dictionary keyed on site_id
451 pi_filter = {'|roles': ['pi'], '|site_ids': site_ids}
452 pi_list = self.shell.GetPersons(pi_filter, ['person_id', 'site_ids'])
454 # we will need the pi's hrns also
455 person_ids.append(pi['person_id'])
457 # we also need to keep track of the sites these pis
459 for site_id in pi['site_ids']:
460 if site_id in site_pis:
461 site_pis[site_id].append(pi)
463 site_pis[site_id] = [pi]
465 # get sfa records for all records associated with these records.
466 # we'll replace pl ids (person_ids) with hrns from the sfa records
469 # get the registry records
470 person_list, persons = [], {}
471 person_list = dbsession.query (RegRecord).filter(RegRecord.pointer.in_(person_ids))
472 # create a hrns keyed on the sfa record's pointer.
473 # Its possible for multiple records to have the same pointer so
474 # the dict's value will be a list of hrns.
475 persons = defaultdict(list)
476 for person in person_list:
477 persons[person.pointer].append(person)
480 pl_person_list, pl_persons = [], {}
481 pl_person_list = self.shell.GetPersons(person_ids, ['person_id', 'roles'])
482 pl_persons = list_to_dict(pl_person_list, 'person_id')
485 for record in records:
486 # skip records with no pl info (top level authorities)
487 #if record['pointer'] == -1:
490 type = record['type']
491 logger.info("fill_record_sfa_info - incoming record typed %s"%type)
492 if (type == "slice"):
493 # all slice users are researchers
494 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
496 record['researcher'] = []
497 for person_id in record.get('person_ids', []):
498 hrns = [person.hrn for person in persons[person_id]]
499 record['researcher'].extend(hrns)
501 # pis at the slice's site
502 if 'site_id' in record and record['site_id'] in site_pis:
503 pl_pis = site_pis[record['site_id']]
504 pi_ids = [pi['person_id'] for pi in pl_pis]
505 for person_id in pi_ids:
506 hrns = [person.hrn for person in persons[person_id]]
507 record['PI'].extend(hrns)
508 record['geni_creator'] = record['PI']
510 elif (type.startswith("authority")):
512 logger.info("fill_record_sfa_info - authority xherex")
513 if record['pointer'] != -1:
515 record['operator'] = []
517 for pointer in record.get('person_ids', []):
518 if pointer not in persons or pointer not in pl_persons:
519 # this means there is not sfa or pl record for this user
521 hrns = [person.hrn for person in persons[pointer]]
522 roles = pl_persons[pointer]['roles']
524 record['PI'].extend(hrns)
526 record['operator'].extend(hrns)
528 record['owner'].extend(hrns)
529 # xxx TODO: OrganizationName
530 elif (type == "node"):
531 sfa_info['dns'] = record.get("hostname", "")
532 # xxx TODO: URI, LatLong, IP, DNS
534 elif (type == "user"):
535 logger.info('setting user.email')
536 sfa_info['email'] = record.get("email", "")
537 sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
538 sfa_info['geni_certificate'] = record['gid']
539 # xxx TODO: PostalAddress, Phone
540 record.update(sfa_info)
544 # plcapi works by changes, compute what needs to be added/deleted
545 def update_relation (self, subject_type, target_type, relation_name, subject_id, target_ids):
546 # hard-wire the code for slice/user for now, could be smarter if needed
547 if subject_type =='slice' and target_type == 'user' and relation_name == 'researcher':
548 subject=self.shell.GetSlices (subject_id)[0]
549 current_target_ids = subject['person_ids']
550 add_target_ids = list ( set (target_ids).difference(current_target_ids))
551 del_target_ids = list ( set (current_target_ids).difference(target_ids))
552 logger.debug ("subject_id = %s (type=%s)"%(subject_id,type(subject_id)))
553 for target_id in add_target_ids:
554 self.shell.AddPersonToSlice (target_id,subject_id)
555 logger.debug ("add_target_id = %s (type=%s)"%(target_id,type(target_id)))
556 for target_id in del_target_ids:
557 logger.debug ("del_target_id = %s (type=%s)"%(target_id,type(target_id)))
558 self.shell.DeletePersonFromSlice (target_id, subject_id)
559 elif subject_type == 'authority' and target_type == 'user' and relation_name == 'pi':
560 # due to the plcapi limitations this means essentially adding pi role to all people in the list
561 # it's tricky to remove any pi role here, although it might be desirable
562 persons = self.shell.GetPersons (target_ids)
563 for person in persons:
564 if 'pi' not in person['roles']:
565 self.shell.AddRoleToPerson('pi',person['person_id'])
567 logger.info('unexpected relation %s to maintain, %s -> %s'%(relation_name,subject_type,target_type))
570 ########################################
571 ########## aggregate oriented
572 ########################################
574 def testbed_name (self): return "myplc"
576 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
577 def aggregate_version (self):
578 version_manager = VersionManager()
579 ad_rspec_versions = []
580 request_rspec_versions = []
581 for rspec_version in version_manager.versions:
582 if rspec_version.content_type in ['*', 'ad']:
583 ad_rspec_versions.append(rspec_version.to_dict())
584 if rspec_version.content_type in ['*', 'request']:
585 request_rspec_versions.append(rspec_version.to_dict())
587 'testbed':self.testbed_name(),
588 'geni_request_rspec_versions': request_rspec_versions,
589 'geni_ad_rspec_versions': ad_rspec_versions,
592 def list_slices (self, creds, options):
593 # look in cache first
595 slices = self.cache.get('slices')
597 logger.debug("PlDriver.list_slices returns from cache")
601 slices = self.shell.GetSlices({'peer_id': None}, ['name'])
602 slice_hrns = [slicename_to_hrn(self.hrn, slice['name']) for slice in slices]
603 slice_urns = [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slice_hrns]
607 logger.debug ("PlDriver.list_slices stores value in cache")
608 self.cache.add('slices', slice_urns)
612 # first 2 args are None in case of resource discovery
613 def list_resources (self, slice_urn, slice_hrn, creds, options):
614 cached_requested = options.get('cached', True)
616 version_manager = VersionManager()
617 # get the rspec's return format from options
618 rspec_version = version_manager.get_version(options.get('geni_rspec_version'))
619 version_string = "rspec_%s" % (rspec_version)
621 #panos adding the info option to the caching key (can be improved)
622 if options.get('info'):
623 version_string = version_string + "_"+options.get('info', 'default')
625 # Adding the list_leases option to the caching key
626 if options.get('list_leases'):
627 version_string = version_string + "_"+options.get('list_leases', 'default')
629 # Adding geni_available to caching key
630 if options.get('geni_available'):
631 version_string = version_string + "_" + str(options.get('geni_available'))
633 # look in cache first
634 if cached_requested and self.cache and not slice_hrn:
635 rspec = self.cache.get(version_string)
637 logger.debug("PlDriver.ListResources: returning cached advertisement")
640 #panos: passing user-defined options
641 #print "manager options = ",options
642 aggregate = PlAggregate(self)
643 rspec = aggregate.get_rspec(slice_xrn=slice_urn, version=rspec_version,
647 if self.cache and not slice_hrn:
648 logger.debug("PlDriver.ListResources: stores advertisement in cache")
649 self.cache.add(version_string, rspec)
653 def sliver_status (self, slice_urn, slice_hrn):
654 # find out where this slice is currently running
655 slicename = hrn_to_pl_slicename(slice_hrn)
657 slices = self.shell.GetSlices([slicename], ['slice_id', 'node_ids','person_ids','name','expires'])
659 raise SliverDoesNotExist("%s (used %s as slicename internally)" % (slice_hrn, slicename))
662 # report about the local nodes only
663 nodes = self.shell.GetNodes({'node_id':slice['node_ids'],'peer_id':None},
664 ['node_id', 'hostname', 'site_id', 'boot_state', 'last_contact'])
667 raise SliverDoesNotExist("You have not allocated any slivers here")
671 if slice['person_ids']:
672 persons = self.shell.GetPersons(slice['person_ids'], ['key_ids'])
673 key_ids = [key_id for person in persons for key_id in person['key_ids']]
674 person_keys = self.shell.GetKeys(key_ids)
675 keys = [key['key'] for key in person_keys]
677 user.update({'urn': slice_urn,
678 'login': slice['name'],
683 site_ids = [node['site_id'] for node in nodes]
686 top_level_status = 'unknown'
688 top_level_status = 'ready'
689 result['geni_urn'] = slice_urn
690 result['pl_login'] = slice['name']
691 result['pl_expires'] = datetime_to_string(utcparse(slice['expires']))
692 result['geni_expires'] = datetime_to_string(utcparse(slice['expires']))
697 res['pl_hostname'] = node['hostname']
698 res['pl_boot_state'] = node['boot_state']
699 res['pl_last_contact'] = node['last_contact']
700 res['geni_expires'] = datetime_to_string(utcparse(slice['expires']))
701 if node['last_contact'] is not None:
703 res['pl_last_contact'] = datetime_to_string(utcparse(node['last_contact']))
704 sliver_xrn = Xrn(slice_urn, type='sliver', id=node['node_id'])
705 sliver_xrn.set_authority(self.hrn)
707 res['geni_urn'] = sliver_xrn.urn
708 if node['boot_state'] == 'boot':
709 res['geni_status'] = 'ready'
711 res['geni_status'] = 'failed'
712 top_level_status = 'failed'
714 res['geni_error'] = ''
715 res['users'] = [user]
717 resources.append(res)
719 result['geni_status'] = top_level_status
720 result['geni_resources'] = resources
723 def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, users, options):
725 aggregate = PlAggregate(self)
726 slices = PlSlices(self)
727 peer = slices.get_peer(slice_hrn)
728 sfa_peer = slices.get_sfa_peer(slice_hrn)
731 slice_record = users[0].get('slice_record', {})
734 rspec = RSpec(rspec_string)
735 requested_attributes = rspec.version.get_slice_attributes()
737 # ensure site record exists
738 site = slices.verify_site(slice_hrn, slice_record, peer, sfa_peer, options=options)
739 # ensure slice record exists
740 slice = slices.verify_slice(slice_hrn, slice_record, peer, sfa_peer, options=options)
741 # ensure person records exists
742 persons = slices.verify_persons(slice_hrn, slice, users, peer, sfa_peer, options=options)
743 # ensure slice attributes exists
744 slices.verify_slice_attributes(slice, requested_attributes, options=options)
746 # add/remove slice from nodes
747 requested_slivers = {}
748 slivers = rspec.version.get_nodes_with_slivers()
749 nodes = slices.verify_slice_nodes(slice, slivers, peer)
751 # add/remove links links
752 slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes)
756 rspec_requested_leases = rspec.version.get_leases()
757 leases = slices.verify_slice_leases(slice, rspec_requested_leases, peer)
760 #requested_leases = []
762 #for lease in rspec.version.get_leases():
763 # requested_lease = {}
764 # if not lease.get('lease_id'):
765 # requested_lease['hostname'] = xrn_to_hostname(lease.get('component_id').strip())
766 # requested_lease['start_time'] = lease.get('start_time')
767 # requested_lease['duration'] = lease.get('duration')
769 # kept_leases.append(int(lease['lease_id']))
770 # if requested_lease.get('hostname'):
771 # requested_leases.append(requested_lease)
773 #leases = slices.verify_slice_leases(slice, requested_leases, kept_leases, peer)
775 # handle MyPLC peer association.
776 # only used by plc and ple.
777 slices.handle_peer(site, slice, persons, peer)
779 return aggregate.get_rspec(slice_xrn=slice_urn,
780 version=rspec.version)
782 def delete_sliver (self, slice_urn, slice_hrn, creds, options):
784 top_auth_hrn = top_auth(slice_hrn)
785 site_hrn = '.'.join(slice_hrn.split('.')[:-1])
786 slice_part = slice_hrn.split('.')[-1]
787 if top_auth_hrn == self.driver.hrn:
788 login_base = slice_hrn.split('.')[-2][:12]
790 login_base = hash_loginbase(site_hrn)
792 slicename = '_'.join([login_base, slice_part])
794 slices = self.shell.GetSlices({'name': slicename})
800 leases = self.shell.GetLeases({'name': slicename})
801 leases_ids = [lease['lease_id'] for lease in leases ]
802 # determine if this is a peer slice
803 # xxx I wonder if this would not need to use PlSlices.get_peer instead
804 # in which case plc.peers could be deprecated as this here
805 # is the only/last call to this last method in plc.peers
806 peer = peers.get_peer(self, slice_hrn)
809 self.shell.UnBindObjectFromPeer('slice', slice['slice_id'], peer)
810 self.shell.DeleteSliceFromNodes(slicename, slice['node_ids'])
811 if len(leases_ids) > 0:
812 self.shell.DeleteLeases(leases_ids)
815 self.shell.BindObjectToPeer('slice', slice['slice_id'], peer, slice['peer_slice_id'])
818 def renew_sliver (self, slice_urn, slice_hrn, creds, expiration_time, options):
819 top_auth_hrn = top_auth(slice_hrn)
820 site_hrn = '.'.join(slice_hrn.split('.')[:-1])
821 slice_part = slice_hrn.split('.')[-1]
822 if top_auth_hrn == self.driver.hrn:
823 login_base = slice_hrn.split('.')[-2][:12]
825 login_base = hash_loginbase(site_hrn)
827 slicename = '_'.join([login_base, slice_part])
828 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
830 raise RecordNotFound(slice_hrn)
832 requested_time = utcparse(expiration_time)
833 record = {'expires': int(datetime_to_epoch(requested_time))}
835 self.shell.UpdateSlice(slice['slice_id'], record)
840 # remove the 'enabled' tag
841 def start_slice (self, slice_urn, slice_hrn, creds):
842 top_auth_hrn = top_auth(slice_hrn)
843 site_hrn = '.'.join(slice_hrn.split('.')[:-1])
844 slice_part = slice_hrn.split('.')[-1]
845 if top_auth_hrn == self.driver.hrn:
846 login_base = slice_hrn.split('.')[-2][:12]
848 login_base = hash_loginbase(site_hrn)
850 slicename = '_'.join([login_base, slice_part])
852 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
854 raise RecordNotFound(slice_hrn)
855 slice_id = slices[0]['slice_id']
856 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'}, ['slice_tag_id'])
857 # just remove the tag if it exists
859 self.shell.DeleteSliceTag(slice_tags[0]['slice_tag_id'])
862 # set the 'enabled' tag to 0
863 def stop_slice (self, slice_urn, slice_hrn, creds):
864 top_auth_hrn = top_auth(slice_hrn)
865 site_hrn = '.'.join(slice_hrn.split('.')[:-1])
866 slice_part = slice_hrn.split('.')[-1]
867 if top_auth_hrn == self.driver.hrn:
868 login_base = slice_hrn.split('.')[-2][:12]
870 login_base = hash_loginbase(site_hrn)
872 slicename = '_'.join([login_base, slice_part])
874 slices = self.shell.GetSlices({'name': slicename}, ['slice_id'])
876 raise RecordNotFound(slice_hrn)
877 slice_id = slices[0]['slice_id']
878 slice_tags = self.shell.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
880 self.shell.AddSliceTag(slice_id, 'enabled', '0')
881 elif slice_tags[0]['value'] != "0":
882 tag_id = slice_tags[0]['slice_tag_id']
883 self.shell.UpdateSliceTag(tag_id, '0')
886 def reset_slice (self, slice_urn, slice_hrn, creds):
887 raise SfaNotImplemented ("reset_slice not available at this interface")
889 # xxx this code is quite old and has not run for ages
890 # it is obviously totally broken and needs a rewrite
891 def get_ticket (self, slice_urn, slice_hrn, creds, rspec_string, options):
892 raise SfaNotImplemented,"PlDriver.get_ticket needs a rewrite"
893 # please keep this code for future reference
894 # slices = PlSlices(self)
895 # peer = slices.get_peer(slice_hrn)
896 # sfa_peer = slices.get_sfa_peer(slice_hrn)
898 # # get the slice record
899 # credential = api.getCredential()
900 # interface = api.registries[api.hrn]
901 # registry = api.server_proxy(interface, credential)
902 # records = registry.Resolve(xrn, credential)
904 # # make sure we get a local slice record
906 # for tmp_record in records:
907 # if tmp_record['type'] == 'slice' and \
908 # not tmp_record['peer_authority']:
909 # #Error (E0602, GetTicket): Undefined variable 'SliceRecord'
910 # slice_record = SliceRecord(dict=tmp_record)
912 # raise RecordNotFound(slice_hrn)
914 # # similar to CreateSliver, we must verify that the required records exist
915 # # at this aggregate before we can issue a ticket
917 # rspec = RSpec(rspec_string)
918 # requested_attributes = rspec.version.get_slice_attributes()
920 # # ensure site record exists
921 # site = slices.verify_site(slice_hrn, slice_record, peer, sfa_peer)
922 # # ensure slice record exists
923 # slice = slices.verify_slice(slice_hrn, slice_record, peer, sfa_peer)
924 # # ensure person records exists
925 # # xxx users is undefined in this context
926 # persons = slices.verify_persons(slice_hrn, slice, users, peer, sfa_peer)
927 # # ensure slice attributes exists
928 # slices.verify_slice_attributes(slice, requested_attributes)
931 # slivers = slices.get_slivers(slice_hrn)
934 # raise SliverDoesNotExist(slice_hrn)
939 # 'timestamp': int(time.time()),
940 # 'initscripts': initscripts,
944 # # create the ticket
945 # object_gid = record.get_gid_object()
946 # new_ticket = SfaTicket(subject = object_gid.get_subject())
947 # new_ticket.set_gid_caller(api.auth.client_gid)
948 # new_ticket.set_gid_object(object_gid)
949 # new_ticket.set_issuer(key=api.key, subject=self.hrn)
950 # new_ticket.set_pubkey(object_gid.get_pubkey())
951 # new_ticket.set_attributes(data)
952 # new_ticket.set_rspec(rspec)
953 # #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
954 # new_ticket.encode()
957 # return new_ticket.save_to_string(save_parents=True)