1 from sfa.util.xrn import get_authority, urn_to_hrn
2 from sfa.util.sfalogging import logger
9 rspec_to_slice_tag = {'max_rate':'net_max_rate'}
12 def __init__(self, driver):
16 def get_peer(self, xrn):
17 hrn, hrn_type = urn_to_hrn(xrn)
18 #Does this slice belong to a local site or a peer senslab site?
21 # get this slice's authority (site)
22 slice_authority = get_authority(hrn)
23 site_authority = slice_authority
24 # get this site's authority (sfa root authority or sub authority)
25 #site_authority = get_authority(slice_authority).lower()
26 logger.debug("SLABSLICES \ get_peer slice_authority %s \
27 site_authority %s hrn %s" %(slice_authority, \
29 #This slice belongs to the current site
30 if site_authority == self.driver.root_auth :
32 # check if we are already peered with this site_authority, if so
33 #peers = self.driver.GetPeers({})
34 peers = self.driver.GetPeers(peer_filter = slice_authority)
35 for peer_record in peers:
37 if site_authority == peer_record.hrn:
39 logger.debug(" SLABSLICES \tget_peer peer %s " %(peer))
42 def get_sfa_peer(self, xrn):
43 hrn, hrn_type = urn_to_hrn(xrn)
45 # return the authority for this hrn or None if we are the authority
47 slice_authority = get_authority(hrn)
48 site_authority = get_authority(slice_authority)
50 if site_authority != self.driver.hrn:
51 sfa_peer = site_authority
55 #def verify_slice_leases(self, sfa_slice, requested_jobs_dict, peer):
58 ##First get the list of current leases from OAR
59 #leases = self.driver.GetLeases({'name':sfa_slice['slice_hrn']})
60 #logger.debug("SLABSLICES verify_slice_leases requested_jobs_dict %s \
61 #leases %s "%(requested_jobs_dict, leases ))
63 #current_nodes_reserved_by_start_time = {}
64 #requested_nodes_by_start_time = {}
65 #leases_by_start_time = {}
66 #reschedule_jobs_dict = {}
72 ##Create reduced dictionary with key start_time and value
74 ##-for the leases already registered by OAR first
75 ## then for the new leases requested by the user
77 ##Leases already scheduled/running in OAR
78 #for lease in leases :
79 #current_nodes_reserved_by_start_time[lease['t_from']] = \
80 #lease['reserved_nodes']
81 #leases_by_start_time[lease['t_from']] = lease
85 #for start_time in requested_jobs_dict:
86 #requested_nodes_by_start_time[int(start_time)] = \
87 #requested_jobs_dict[start_time]['hostname']
88 ##Check if there is any difference between the leases already
89 ##registered in OAR and the requested jobs.
90 ##Difference could be:
91 ##-Lease deleted in the requested jobs
92 ##-Added/removed nodes
96 ##Find all deleted leases
98 #list(set(leases_by_start_time.keys()).\
99 #difference(requested_nodes_by_start_time.keys()))
100 #deleted_leases = [leases_by_start_time[start_time]['lease_id'] \
101 #for start_time in start_time_list]
105 ##Find added or removed nodes in exisiting leases
106 #for start_time in requested_nodes_by_start_time:
107 #if start_time in current_nodes_reserved_by_start_time:
109 #if requested_nodes_by_start_time[start_time] == \
110 #current_nodes_reserved_by_start_time[start_time]:
115 #set(requested_nodes_by_start_time[start_time])
117 #update_node_set.difference(\
118 #current_nodes_reserved_by_start_time[start_time])
120 #update_node_set.intersection(\
121 #current_nodes_reserved_by_start_time[start_time])
124 #current_nodes_reserved_by_start_time[start_time])
126 #old_nodes_set.difference(\
127 #requested_nodes_by_start_time[start_time])
128 #logger.debug("SLABSLICES verify_slice_leases \
129 #shared_nodes %s added_nodes %s removed_nodes %s"\
130 #%(shared_nodes, added_nodes,removed_nodes ))
131 ##If the lease is modified, delete it before
133 ##Add the deleted lease job id in the list
134 ##WARNING :rescheduling does not work if there is already
135 ## 2 running/scheduled jobs because deleting a job
136 ##takes time SA 18/10/2012
137 #if added_nodes or removed_nodes:
138 #deleted_leases.append(\
139 #leases_by_start_time[start_time]['lease_id'])
141 #if added_nodes or shared_nodes:
142 #reschedule_jobs_dict[str(start_time)] = \
143 #requested_jobs_dict[str(start_time)]
147 #job = requested_jobs_dict[str(start_time)]
148 #self.driver.AddLeases(job['hostname'], \
149 #sfa_slice, int(job['start_time']), \
150 #int(job['duration']))
152 ##Deleted leases are the ones with lease id not declared in the Rspec
154 #self.driver.DeleteLeases(deleted_leases, sfa_slice['slice_hrn'])
155 #logger.debug("SLABSLICES \
156 #verify_slice_leases slice %s deleted_leases %s"\
157 #%(sfa_slice, deleted_leases))
160 #if reschedule_jobs_dict :
161 #for start_time in reschedule :
162 #job = reschedule_jobs_dict[start_time]
163 #self.driver.AddLeases(job['hostname'], \
164 #sfa_slice, int(job['start_time']), \
165 #int(job['duration']))
170 def verify_slice_leases(self, sfa_slice, requested_jobs_dict, peer):
173 #First get the list of current leases from OAR
174 leases = self.driver.GetLeases({'name':sfa_slice['slice_hrn']})
175 logger.debug("SLABSLICES verify_slice_leases requested_jobs_dict %s \
176 leases %s "%(requested_jobs_dict, leases ))
178 current_nodes_reserved_by_start_time = {}
179 requested_nodes_by_start_time = {}
180 leases_by_start_time = {}
181 reschedule_jobs_dict = {}
184 #Create reduced dictionary with key start_time and value
186 #-for the leases already registered by OAR first
187 # then for the new leases requested by the user
189 #Leases already scheduled/running in OAR
190 for lease in leases :
191 current_nodes_reserved_by_start_time[lease['t_from']] = \
192 lease['reserved_nodes']
193 leases_by_start_time[lease['t_from']] = lease
197 for start_time in requested_jobs_dict:
198 requested_nodes_by_start_time[int(start_time)] = \
199 requested_jobs_dict[start_time]['hostname']
200 #Check if there is any difference between the leases already
201 #registered in OAR and the requested jobs.
202 #Difference could be:
203 #-Lease deleted in the requested jobs
204 #-Added/removed nodes
207 logger.debug("SLABSLICES verify_slice_leases requested_nodes_by_start_time %s \
208 "%(requested_nodes_by_start_time ))
209 #Find all deleted leases
211 list(set(leases_by_start_time.keys()).\
212 difference(requested_nodes_by_start_time.keys()))
213 deleted_leases = [leases_by_start_time[start_time]['lease_id'] \
214 for start_time in start_time_list]
218 #Find added or removed nodes in exisiting leases
219 for start_time in requested_nodes_by_start_time:
220 logger.debug("SLABSLICES verify_slice_leases start_time %s \
222 if start_time in current_nodes_reserved_by_start_time:
224 if requested_nodes_by_start_time[start_time] == \
225 current_nodes_reserved_by_start_time[start_time]:
230 set(requested_nodes_by_start_time[start_time])
232 update_node_set.difference(\
233 current_nodes_reserved_by_start_time[start_time])
235 update_node_set.intersection(\
236 current_nodes_reserved_by_start_time[start_time])
239 current_nodes_reserved_by_start_time[start_time])
241 old_nodes_set.difference(\
242 requested_nodes_by_start_time[start_time])
243 logger.debug("SLABSLICES verify_slice_leases \
244 shared_nodes %s added_nodes %s removed_nodes %s"\
245 %(shared_nodes, added_nodes,removed_nodes ))
246 #If the lease is modified, delete it before
248 #Add the deleted lease job id in the list
249 #WARNING :rescheduling does not work if there is already
250 # 2 running/scheduled jobs because deleting a job
251 #takes time SA 18/10/2012
252 if added_nodes or removed_nodes:
253 deleted_leases.append(\
254 leases_by_start_time[start_time]['lease_id'])
256 if added_nodes or shared_nodes:
257 reschedule_jobs_dict[str(start_time)] = \
258 requested_jobs_dict[str(start_time)]
263 job = requested_jobs_dict[str(start_time)]
264 logger.debug("SLABSLICES \
265 NEWLEASE slice %s job %s"\
267 self.driver.AddLeases(job['hostname'], \
268 sfa_slice, int(job['start_time']), \
269 int(job['duration']))
271 #Deleted leases are the ones with lease id not declared in the Rspec
273 self.driver.DeleteLeases(deleted_leases, sfa_slice['slice_hrn'])
274 logger.debug("SLABSLICES \
275 verify_slice_leases slice %s deleted_leases %s"\
276 %(sfa_slice, deleted_leases))
279 if reschedule_jobs_dict :
280 for start_time in reschedule :
281 job = reschedule_jobs_dict[start_time]
282 self.driver.AddLeases(job['hostname'], \
283 sfa_slice, int(job['start_time']), \
284 int(job['duration']))
287 def verify_slice_nodes(self, sfa_slice, requested_slivers, peer):
291 if 'node_ids' in sfa_slice:
292 nodes = self.driver.GetNodes(sfa_slice['list_node_ids'], \
294 current_slivers = [node['hostname'] for node in nodes]
296 # remove nodes not in rspec
297 deleted_nodes = list(set(current_slivers).\
298 difference(requested_slivers))
299 # add nodes from rspec
300 #added_nodes = list(set(requested_slivers).\
301 #difference(current_slivers))
303 #Update the table with the nodes that populate the slice
304 logger.debug("SLABSLICES \tverify_slice_nodes slice %s\
305 \r\n \r\n deleted_nodes %s"\
306 %(sfa_slice, deleted_nodes))
309 #Delete the entire experience
310 self.driver.DeleteSliceFromNodes(sfa_slice)
311 #self.driver.DeleteSliceFromNodes(sfa_slice['slice_hrn'], \
317 def free_egre_key(self):
319 for tag in self.driver.GetSliceTags({'tagname': 'egre_key'}):
320 used.add(int(tag['value']))
322 for i in range(1, 256):
327 raise KeyError("No more EGRE keys available")
336 def handle_peer(self, site, sfa_slice, persons, peer):
341 self.driver.BindObjectToPeer('site', site['site_id'], \
342 peer['shortname'], sfa_slice['site_id'])
343 except Exception, error:
344 self.driver.DeleteSite(site['site_id'])
350 self.driver.BindObjectToPeer('slice', slice['slice_id'], \
351 peer['shortname'], sfa_slice['slice_id'])
352 except Exception, error:
353 self.driver.DeleteSlice(sfa_slice['slice_id'])
357 for person in persons:
359 self.driver.BindObjectToPeer('person', \
360 person['person_id'], peer['shortname'], \
361 person['peer_person_id'])
363 for (key, remote_key_id) in zip(person['keys'], \
366 self.driver.BindObjectToPeer( 'key', \
367 key['key_id'], peer['shortname'], \
370 self.driver.DeleteKey(key['key_id'])
371 logger.log_exc("failed to bind key: %s \
372 to peer: %s " % (key['key_id'], \
374 except Exception, error:
375 self.driver.DeletePerson(person['person_id'])
380 #def verify_site(self, slice_xrn, slice_record={}, peer=None, \
381 #sfa_peer=None, options={}):
382 #(slice_hrn, type) = urn_to_hrn(slice_xrn)
383 #site_hrn = get_authority(slice_hrn)
384 ## login base can't be longer than 20 characters
385 ##slicename = hrn_to_pl_slicename(slice_hrn)
386 #authority_name = slice_hrn.split('.')[0]
387 #login_base = authority_name[:20]
388 #logger.debug(" SLABSLICES.PY \tverify_site authority_name %s \
389 #login_base %s slice_hrn %s" \
390 #%(authority_name,login_base,slice_hrn)
392 #sites = self.driver.GetSites(login_base)
394 ## create new site record
395 #site = {'name': 'geni.%s' % authority_name,
396 #'abbreviated_name': authority_name,
397 #'login_base': login_base,
399 #'max_slivers': 1000,
401 #'peer_site_id': None}
403 #site['peer_site_id'] = slice_record.get('site_id', None)
404 #site['site_id'] = self.driver.AddSite(site)
405 ## exempt federated sites from monitor policies
406 #self.driver.AddSiteTag(site['site_id'], 'exempt_site_until', \
409 ### is this still necessary?
410 ### add record to the local registry
411 ##if sfa_peer and slice_record:
412 ##peer_dict = {'type': 'authority', 'hrn': site_hrn, \
413 ##'peer_authority': sfa_peer, 'pointer': \
415 ##self.registry.register_peer_object(self.credential, peer_dict)
419 ## unbind from peer so we can modify if necessary.
420 ## Will bind back later
421 #self.driver.UnBindObjectFromPeer('site', site['site_id'], \
426 def verify_slice(self, slice_hrn, slice_record, peer, sfa_peer):
428 #login_base = slice_hrn.split(".")[0]
429 slicename = slice_hrn
430 slices_list = self.driver.GetSlices(slice_filter = slicename, \
431 slice_filter_type = 'slice_hrn')
433 for sl in slices_list:
435 logger.debug("SLABSLICE \tverify_slice slicename %s sl %s \
436 slice_record %s"%(slicename, sl, \
439 sfa_slice.update(slice_record)
440 #del slice['last_updated']
441 #del slice['date_created']
443 #slice['peer_slice_id'] = slice_record.get('slice_id', None)
444 ## unbind from peer so we can modify if necessary.
445 ## Will bind back later
446 #self.driver.UnBindObjectFromPeer('slice', \
447 #slice['slice_id'], \
449 #Update existing record (e.g. expires field)
450 #it with the latest info.
451 ##if slice_record and slice['expires'] != slice_record['expires']:
452 ##self.driver.UpdateSlice( slice['slice_id'], {'expires' : \
453 #slice_record['expires']})
455 logger.debug(" SLABSLICES \tverify_slice Oups \
456 slice_record %s peer %s sfa_peer %s "\
457 %(slice_record, peer,sfa_peer))
458 sfa_slice = {'slice_hrn': slicename,
459 #'url': slice_record.get('url', slice_hrn),
460 #'description': slice_record.get('description', slice_hrn)
462 'record_id_user' : slice_record['person_ids'][0],
463 'record_id_slice': slice_record['record_id'],
464 'peer_authority':str(peer.hrn)
468 self.driver.AddSlice(sfa_slice)
469 #slice['slice_id'] = self.driver.AddSlice(slice)
470 logger.debug("SLABSLICES \tverify_slice ADDSLICE OK")
471 #slice['node_ids']=[]
472 #slice['person_ids'] = []
474 #slice['peer_slice_id'] = slice_record.get('slice_id', None)
475 # mark this slice as an sfa peer record
477 #peer_dict = {'type': 'slice', 'hrn': slice_hrn,
478 #'peer_authority': sfa_peer, 'pointer': \
480 #self.registry.register_peer_object(self.credential, peer_dict)
487 def verify_persons(self, slice_hrn, slice_record, users, peer, sfa_peer, \
490 users is a record list. Records can either be local records
491 or users records from known and trusted federated sites.
492 If the user is from another site that senslab doesn't trust yet,
493 then Resolve will raise an error before getting to create_sliver.
495 #TODO SA 21/08/12 verify_persons Needs review
500 #users_dict : dict whose keys can either be the user's hrn or its id.
501 #Values contains only id and hrn
504 #First create dicts by hrn and id for each user in the user record list:
507 if 'urn' in user and (not 'hrn' in user ) :
508 user['hrn'], user['type'] = urn_to_hrn(user['urn'])
510 if 'person_id' in user and 'hrn' in user:
511 users_by_id[user['person_id']] = user
512 users_dict[user['person_id']] = {'person_id':\
513 user['person_id'], 'hrn':user['hrn']}
515 users_by_hrn[user['hrn']] = user
516 users_dict[user['hrn']] = {'person_id':user['person_id'], \
520 logger.debug( "SLABSLICE.PY \t verify_person \
521 users_dict %s \r\n user_by_hrn %s \r\n \
523 %(users_dict,users_by_hrn, users_by_id))
525 existing_user_ids = []
526 existing_user_hrns = []
528 # Check if user is in Senslab LDAP using its hrn.
529 # Assuming Senslab is centralised : one LDAP for all sites,
530 # user_id unknown from LDAP
531 # LDAP does not provide users id, therefore we rely on hrns containing
532 # the login of the user.
533 # If the hrn is not a senslab hrn, the user may not be in LDAP.
535 #Construct the list of filters (list of dicts) for GetPersons
537 for hrn in users_by_hrn:
538 filter_user.append (users_by_hrn[hrn])
539 logger.debug(" SLABSLICE.PY \tverify_person filter_user %s " \
541 #Check user's in LDAP with GetPersons
542 #Needed because what if the user has been deleted in LDAP but
544 existing_users = self.driver.GetPersons(filter_user)
546 #User's in senslab LDAP
548 for user in existing_users :
549 existing_user_hrns.append(users_dict[user['hrn']]['hrn'])
551 append(users_dict[user['hrn']]['person_id'])
553 # User from another known trusted federated site. Check
554 # if a senslab account matching the email has already been created.
557 if isinstance(users, list):
559 req += users[0]['email']
561 req += users['email']
563 ldap_reslt = self.driver.ldap.LdapSearch(req)
565 logger.debug(" SLABSLICE.PY \tverify_person users \
566 USER already in Senslab \t ldap_reslt %s \
568 existing_users.append(ldap_reslt[1])
571 #User not existing in LDAP
572 #TODO SA 21/08/12 raise smthg to add user or add it auto ?
573 logger.debug(" SLABSLICE.PY \tverify_person users \
574 not in ldap ...NEW ACCOUNT NEEDED %s \r\n \t \
575 ldap_reslt %s " %(users, ldap_reslt))
577 requested_user_ids = users_by_id.keys()
578 requested_user_hrns = users_by_hrn.keys()
579 logger.debug("SLABSLICE.PY \tverify_person requested_user_ids %s \
580 user_by_hrn %s " %(requested_user_ids, users_by_hrn))
583 #Check that the user of the slice in the slice record
584 #matches the existing users
586 if slice_record['record_id_user'] in requested_user_ids and \
587 slice_record['PI'][0] in requested_user_hrns:
588 logger.debug(" SLABSLICE \tverify_person \
589 requested_user_ids %s = \
590 slice_record['record_id_user'] %s" \
591 %(requested_user_ids,slice_record['record_id_user']))
597 # users to be added, removed or updated
598 #One user in one senslab slice : there should be no need
599 #to remove/ add any user from/to a slice.
600 #However a user from SFA which is not registered in Senslab yet
601 #should be added to the LDAP.
603 added_user_hrns = set(requested_user_hrns).\
604 difference(set(existing_user_hrns))
606 #self.verify_keys(existing_slice_users, updated_users_list, \
611 for added_user_hrn in added_user_hrns:
612 added_user = users_dict[added_user_hrn]
613 #hrn, type = urn_to_hrn(added_user['urn'])
615 #'first_name': added_user.get('first_name', hrn),
616 #'last_name': added_user.get('last_name', hrn),
617 'first_name': added_user['first_name'],
618 'last_name': added_user['last_name'],
619 'person_id': added_user['person_id'],
620 'peer_person_id': None,
622 'key_ids': added_user.get('key_ids', []),
625 person['person_id'] = self.driver.AddPerson(person)
627 person['peer_person_id'] = added_user['person_id']
628 added_persons.append(person)
631 self.driver.UpdatePerson(person['person_id'], {'enabled': True})
634 #self.driver.AddPersonToSite(added_user_id, login_base)
636 #for key_string in added_user.get('keys', []):
637 #key = {'key':key_string, 'key_type':'ssh'}
638 #key['key_id'] = self.driver.AddPersonKey(person['person_id'], \
640 #person['keys'].append(key)
642 # add the registry record
644 #peer_dict = {'type': 'user', 'hrn': hrn, 'peer_authority': \
646 #'pointer': person['person_id']}
647 #self.registry.register_peer_object(self.credential, peer_dict)
648 #for added_slice_user_hrn in \
649 #added_slice_user_hrns.union(added_user_hrns):
650 #self.driver.AddPersonToSlice(added_slice_user_hrn, \
651 #slice_record['name'])
652 #for added_slice_user_id in \
653 #added_slice_user_ids.union(added_user_ids):
654 # add person to the slice
655 #self.driver.AddPersonToSlice(added_slice_user_id, \
656 #slice_record['name'])
657 # if this is a peer record then it
658 # should already be bound to a peer.
659 # no need to return worry about it getting bound later
664 def verify_keys(self, persons, users, peer, options={}):
667 for person in persons:
668 key_ids.extend(person['key_ids'])
669 keylist = self.driver.GetKeys(key_ids, ['key_id', 'key'])
672 keydict[key['key']] = key['key_id']
673 existing_keys = keydict.keys()
675 for person in persons:
676 persondict[person['email']] = person
682 user_keys = user.get('keys', [])
683 updated_persons.append(user)
684 for key_string in user_keys:
685 requested_keys.append(key_string)
686 if key_string not in existing_keys:
687 key = {'key': key_string, 'key_type': 'ssh'}
690 person = persondict[user['email']]
691 self.driver.UnBindObjectFromPeer('person', \
692 person['person_id'], peer['shortname'])
694 self.driver.AddPersonKey(user['email'], key)
696 key_index = user_keys.index(key['key'])
697 remote_key_id = user['key_ids'][key_index]
698 self.driver.BindObjectToPeer('key', \
699 key['key_id'], peer['shortname'], \
704 self.driver.BindObjectToPeer('person', \
705 person['person_id'], peer['shortname'], \
708 # remove old keys (only if we are not appending)
709 append = options.get('append', True)
711 removed_keys = set(existing_keys).difference(requested_keys)
712 for existing_key_id in keydict:
713 if keydict[existing_key_id] in removed_keys:
716 self.driver.UnBindObjectFromPeer('key', \
717 existing_key_id, peer['shortname'])
718 self.driver.DeleteKey(existing_key_id)
721 #def verify_slice_attributes(self, slice, requested_slice_attributes, \
722 #append=False, admin=False):
723 ## get list of attributes users ar able to manage
724 #filter = {'category': '*slice*'}
726 #filter['|roles'] = ['user']
727 #slice_attributes = self.driver.GetTagTypes(filter)
728 #valid_slice_attribute_names = [attribute['tagname'] \
729 #for attribute in slice_attributes]
731 ## get sliver attributes
732 #added_slice_attributes = []
733 #removed_slice_attributes = []
734 #ignored_slice_attribute_names = []
735 #existing_slice_attributes = self.driver.GetSliceTags({'slice_id': \
738 ## get attributes that should be removed
739 #for slice_tag in existing_slice_attributes:
740 #if slice_tag['tagname'] in ignored_slice_attribute_names:
741 ## If a slice already has a admin only role
742 ## it was probably given to them by an
743 ## admin, so we should ignore it.
744 #ignored_slice_attribute_names.append(slice_tag['tagname'])
746 ## If an existing slice attribute was not
747 ## found in the request it should
749 #attribute_found=False
750 #for requested_attribute in requested_slice_attributes:
751 #if requested_attribute['name'] == slice_tag['tagname'] \
752 #and requested_attribute['value'] == slice_tag['value']:
753 #attribute_found=True
756 #if not attribute_found and not append:
757 #removed_slice_attributes.append(slice_tag)
759 ## get attributes that should be added:
760 #for requested_attribute in requested_slice_attributes:
761 ## if the requested attribute wasn't found we should add it
762 #if requested_attribute['name'] in valid_slice_attribute_names:
763 #attribute_found = False
764 #for existing_attribute in existing_slice_attributes:
765 #if requested_attribute['name'] == \
766 #existing_attribute['tagname'] and \
767 #requested_attribute['value'] == \
768 #existing_attribute['value']:
769 #attribute_found=True
771 #if not attribute_found:
772 #added_slice_attributes.append(requested_attribute)
775 ## remove stale attributes
776 #for attribute in removed_slice_attributes:
778 #self.driver.DeleteSliceTag(attribute['slice_tag_id'])
779 #except Exception, error:
780 #self.logger.warn('Failed to remove sliver attribute. name: \
781 #%s, value: %s, node_id: %s\nCause:%s'\
782 #% (name, value, node_id, str(error)))
784 ## add requested_attributes
785 #for attribute in added_slice_attributes:
787 #self.driver.AddSliceTag(slice['name'], attribute['name'], \
788 #attribute['value'], attribute.get('node_id', None))
789 #except Exception, error:
790 #self.logger.warn('Failed to add sliver attribute. name: %s, \
791 #value: %s, node_id: %s\nCause:%s'\
792 #% (name, value, node_id, str(error)))