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_slivers(self, xrn, node=None):
17 #hrn, hrn_type = urn_to_hrn(xrn)
19 #slice_name = hrn_to_pl_slicename(hrn)
20 ## XX Should we just call PLCAPI.GetSliceTicket(slice_name) instead
21 ## of doing all of this?
22 ##return self.api.driver.GetSliceTicket(self.auth, slice_name)
26 #sfa_slice = self.driver.GetSlices(slice_filter = slice_name, \
27 # slice_filter_type = 'slice_hrn')
30 ## Get user information
32 #alchemy_person = dbsession.query(RegRecord).filter_by(record_id = \
33 #sfa_slice['record_id_user']).first()
36 #sliver_attributes = []
38 #if sfa_slice['oar_job_id'] is not -1:
39 #nodes_all = self.driver.GetNodes({'hostname': \
40 #sfa_slice['node_ids']},
41 #['node_id', 'hostname','site','boot_state'])
42 #nodeall_byhostname = dict([(n['hostname'], n) for n in nodes_all])
43 #nodes = sfa_slice['node_ids']
46 ##for sliver_attribute in filter(lambda a: a['node_id'] == \
47 #node['node_id'], slice_tags):
48 #sliver_attribute['tagname'] = 'slab-tag'
49 #sliver_attribute['value'] = 'slab-value'
50 #sliver_attributes.append(sliver_attribute['tagname'])
51 #attributes.append({'tagname': sliver_attribute['tagname'],
52 #'value': sliver_attribute['value']})
54 ## set nodegroup slice attributes
55 #for slice_tag in filter(lambda a: a['nodegroup_id'] \
56 #in node['nodegroup_ids'], slice_tags):
57 ## Do not set any nodegroup slice attributes for
58 ## which there is at least one sliver attribute
60 #if slice_tag not in slice_tags:
61 #attributes.append({'tagname': slice_tag['tagname'],
62 #'value': slice_tag['value']})
64 #for slice_tag in filter(lambda a: a['node_id'] is None, \
66 ## Do not set any global slice attributes for
67 ## which there is at least one sliver attribute
69 #if slice_tag['tagname'] not in sliver_attributes:
70 #attributes.append({'tagname': slice_tag['tagname'],
71 #'value': slice_tag['value']})
73 ## XXX Sanity check; though technically this should
74 ## be a system invariant
75 ## checked with an assertion
76 #if sfa_slice['expires'] > MAXINT: sfa_slice['expires']= MAXINT
80 #'name': sfa_slice['name'],
81 #'slice_id': sfa_slice['slice_id'],
82 #'instantiation': sfa_slice['instantiation'],
83 #'expires': sfa_slice['expires'],
85 #'attributes': attributes
95 def get_peer(self, xrn):
96 hrn, hrn_type = urn_to_hrn(xrn)
97 #Does this slice belong to a local site or a peer senslab site?
100 # get this slice's authority (site)
101 slice_authority = get_authority(hrn)
102 site_authority = slice_authority
103 # get this site's authority (sfa root authority or sub authority)
104 #site_authority = get_authority(slice_authority).lower()
105 logger.debug("SLABSLICES \ get_peer slice_authority %s \
106 site_authority %s hrn %s" %(slice_authority, \
107 site_authority, hrn))
108 #This slice belongs to the current site
109 if site_authority == self.driver.root_auth :
111 # check if we are already peered with this site_authority, if so
112 #peers = self.driver.GetPeers({})
113 peers = self.driver.GetPeers(peer_filter = slice_authority)
114 for peer_record in peers:
116 if site_authority == peer_record.hrn:
118 logger.debug(" SLABSLICES \tget_peer peer %s " %(peer))
121 def get_sfa_peer(self, xrn):
122 hrn, hrn_type = urn_to_hrn(xrn)
124 # return the authority for this hrn or None if we are the authority
126 slice_authority = get_authority(hrn)
127 site_authority = get_authority(slice_authority)
129 if site_authority != self.driver.hrn:
130 sfa_peer = site_authority
135 def verify_slice_leases(self, sfa_slice, requested_jobs_dict, kept_leases, \
139 #First get the list of current leases from OAR
140 leases = self.driver.GetLeases({'name':sfa_slice['slice_hrn']})
141 logger.debug("SLABSLICES verify_slice_leases requested_jobs_dict %s leases %s "%(requested_jobs_dict, leases ))
142 #leases = self.driver.GetLeases({'name':sfa_slice['name']},\
145 current_leases = [lease['lease_id'] for lease in leases]
146 logger.debug("SLABSLICES verify_slice_leases current_leases %s kept_leases %s requested_jobs_dict %s"\
147 %(current_leases,kept_leases,requested_jobs_dict))
148 #Deleted leases are the ones with lease id not declared in the Rspec
149 deleted_leases = list(set(current_leases).difference(kept_leases))
153 #peer = RegAuyhority object is unsubscriptable
154 #TODO :UnBindObjectFromPeer Quick and dirty
155 #auth='senslab2 SA 27/07/12
157 #Commented out UnBindObjectFromPeer SA 09/10/12
158 #self.driver.UnBindObjectFromPeer('senslab2', 'slice', \
159 #sfa_slice['record_id_slice'], peer.hrn)
160 logger.debug("SLABSLICES verify_slice_leases slice %s deleted_leases %s"\
161 %(sfa_slice, deleted_leases))
162 self.driver.DeleteLeases(deleted_leases, \
164 #self.driver.DeleteLeases(deleted_leases, \
167 #TODO verify_slice_leases: catch other exception?
169 logger.log_exc('Failed to remove slice leases')
172 for start_time in requested_jobs_dict:
173 job = requested_jobs_dict[start_time]
174 self.driver.AddLeases(job['hostname'], \
175 sfa_slice, int(job['start_time']), \
176 int(job['duration']))
180 def verify_slice_nodes(self, sfa_slice, requested_slivers, peer):
184 if 'node_ids' in sfa_slice:
185 nodes = self.driver.GetNodes(sfa_slice['list_node_ids'], ['hostname'])
186 current_slivers = [node['hostname'] for node in nodes]
188 # remove nodes not in rspec
189 deleted_nodes = list(set(current_slivers).\
190 difference(requested_slivers))
191 # add nodes from rspec
192 #added_nodes = list(set(requested_slivers).\
193 #difference(current_slivers))
195 #Update the table with the nodes that populate the slice
196 logger.debug("SLABSLICES \tverify_slice_nodes slice %s\
197 \r\n \r\n deleted_nodes %s"\
198 %(sfa_slice,deleted_nodes))
201 #Delete the entire experience
202 self.driver.DeleteSliceFromNodes(sfa_slice)
203 #self.driver.DeleteSliceFromNodes(sfa_slice['slice_hrn'], \
209 def free_egre_key(self):
211 for tag in self.driver.GetSliceTags({'tagname': 'egre_key'}):
212 used.add(int(tag['value']))
214 for i in range(1, 256):
219 raise KeyError("No more EGRE keys available")
228 def handle_peer(self, site, sfa_slice, persons, peer):
233 self.driver.BindObjectToPeer('site', site['site_id'], \
234 peer['shortname'], sfa_slice['site_id'])
235 except Exception, error:
236 self.driver.DeleteSite(site['site_id'])
242 self.driver.BindObjectToPeer('slice', slice['slice_id'], \
243 peer['shortname'], sfa_slice['slice_id'])
244 except Exception, error:
245 self.driver.DeleteSlice(sfa_slice['slice_id'])
249 for person in persons:
251 self.driver.BindObjectToPeer('person', \
252 person['person_id'], peer['shortname'], \
253 person['peer_person_id'])
255 for (key, remote_key_id) in zip(person['keys'], \
258 self.driver.BindObjectToPeer( 'key', \
259 key['key_id'], peer['shortname'], \
262 self.driver.DeleteKey(key['key_id'])
263 logger.log_exc("failed to bind key: %s \
264 to peer: %s " % (key['key_id'], \
266 except Exception, error:
267 self.driver.DeletePerson(person['person_id'])
272 #def verify_site(self, slice_xrn, slice_record={}, peer=None, \
273 #sfa_peer=None, options={}):
274 #(slice_hrn, type) = urn_to_hrn(slice_xrn)
275 #site_hrn = get_authority(slice_hrn)
276 ## login base can't be longer than 20 characters
277 ##slicename = hrn_to_pl_slicename(slice_hrn)
278 #authority_name = slice_hrn.split('.')[0]
279 #login_base = authority_name[:20]
280 #logger.debug(" SLABSLICES.PY \tverify_site authority_name %s \
281 #login_base %s slice_hrn %s" \
282 #%(authority_name,login_base,slice_hrn)
284 #sites = self.driver.GetSites(login_base)
286 ## create new site record
287 #site = {'name': 'geni.%s' % authority_name,
288 #'abbreviated_name': authority_name,
289 #'login_base': login_base,
291 #'max_slivers': 1000,
293 #'peer_site_id': None}
295 #site['peer_site_id'] = slice_record.get('site_id', None)
296 #site['site_id'] = self.driver.AddSite(site)
297 ## exempt federated sites from monitor policies
298 #self.driver.AddSiteTag(site['site_id'], 'exempt_site_until', \
301 ### is this still necessary?
302 ### add record to the local registry
303 ##if sfa_peer and slice_record:
304 ##peer_dict = {'type': 'authority', 'hrn': site_hrn, \
305 ##'peer_authority': sfa_peer, 'pointer': \
307 ##self.registry.register_peer_object(self.credential, peer_dict)
311 ## unbind from peer so we can modify if necessary.
312 ## Will bind back later
313 #self.driver.UnBindObjectFromPeer('site', site['site_id'], \
318 def verify_slice(self, slice_hrn, slice_record, peer, sfa_peer):
320 #login_base = slice_hrn.split(".")[0]
321 slicename = slice_hrn
322 slices_list = self.driver.GetSlices(slice_filter = slicename, \
323 slice_filter_type = 'slice_hrn')
325 for sl in slices_list:
327 logger.debug("SLABSLICE \tverify_slice slicename %s sl %s \
328 slice_record %s"%(slicename, sl, \
331 sfa_slice.update(slice_record)
332 #del slice['last_updated']
333 #del slice['date_created']
335 #slice['peer_slice_id'] = slice_record.get('slice_id', None)
336 ## unbind from peer so we can modify if necessary.
337 ## Will bind back later
338 #self.driver.UnBindObjectFromPeer('slice', \
339 #slice['slice_id'], \
341 #Update existing record (e.g. expires field)
342 #it with the latest info.
343 ##if slice_record and slice['expires'] != slice_record['expires']:
344 ##self.driver.UpdateSlice( slice['slice_id'], {'expires' : \
345 #slice_record['expires']})
347 logger.debug(" SLABSLICES \tverify_slice Oups \
348 slice_record %s peer %s sfa_peer %s "\
349 %(slice_record, peer,sfa_peer))
350 sfa_slice = {'slice_hrn': slicename,
351 #'url': slice_record.get('url', slice_hrn),
352 #'description': slice_record.get('description', slice_hrn)
354 'record_id_user' : slice_record['person_ids'][0],
355 'record_id_slice': slice_record['record_id'],
356 'peer_authority':str(peer.hrn)
360 self.driver.AddSlice(sfa_slice)
361 #slice['slice_id'] = self.driver.AddSlice(slice)
362 logger.debug("SLABSLICES \tverify_slice ADDSLICE OK")
363 #slice['node_ids']=[]
364 #slice['person_ids'] = []
366 #slice['peer_slice_id'] = slice_record.get('slice_id', None)
367 # mark this slice as an sfa peer record
369 #peer_dict = {'type': 'slice', 'hrn': slice_hrn,
370 #'peer_authority': sfa_peer, 'pointer': \
372 #self.registry.register_peer_object(self.credential, peer_dict)
379 def verify_persons(self, slice_hrn, slice_record, users, peer, sfa_peer, \
382 users is a record list. Records can either be local records
383 or users records from known and trusted federated sites.
384 If the user is from another site that senslab doesn't trust yet,
385 then Resolve will raise an error before getting to create_sliver.
387 #TODO SA 21/08/12 verify_persons Needs review
392 #users_dict : dict whose keys can either be the user's hrn or its id.
393 #Values contains only id and hrn
396 #First create dicts by hrn and id for each user in the user record list:
399 if 'urn' in user and (not 'hrn' in user ) :
400 user['hrn'], user['type'] = urn_to_hrn(user['urn'])
402 if 'person_id' in user and 'hrn' in user:
403 users_by_id[user['person_id']] = user
404 users_dict[user['person_id']] = {'person_id':\
405 user['person_id'], 'hrn':user['hrn']}
407 users_by_hrn[user['hrn']] = user
408 users_dict[user['hrn']] = {'person_id':user['person_id'], \
412 logger.debug( "SLABSLICE.PY \t verify_person \
413 users_dict %s \r\n user_by_hrn %s \r\n \
415 %(users_dict,users_by_hrn, users_by_id))
417 existing_user_ids = []
418 existing_user_hrns = []
420 # Check if user is in Senslab LDAP using its hrn.
421 # Assuming Senslab is centralised : one LDAP for all sites,
422 # user_id unknown from LDAP
423 # LDAP does not provide users id, therefore we rely on hrns containing
424 # the login of the user.
425 # If the hrn is not a senslab hrn, the user may not be in LDAP.
427 #Construct the list of filters (list of dicts) for GetPersons
429 for hrn in users_by_hrn:
430 filter_user.append (users_by_hrn[hrn])
431 logger.debug(" SLABSLICE.PY \tverify_person filter_user %s " \
433 #Check user's in LDAP with GetPersons
434 #Needed because what if the user has been deleted in LDAP but
436 existing_users = self.driver.GetPersons(filter_user)
438 #User's in senslab LDAP
440 for user in existing_users :
441 existing_user_hrns.append(users_dict[user['hrn']]['hrn'])
443 append(users_dict[user['hrn']]['person_id'])
445 # User from another known trusted federated site. Check
446 # if a senslab account matching the email has already been created.
449 if isinstance(users, list):
451 req += users[0]['email']
453 req += users['email']
455 ldap_reslt = self.driver.ldap.LdapSearch(req)
457 logger.debug(" SLABSLICE.PY \tverify_person users \
458 USER already in Senslab \t ldap_reslt %s \
460 existing_users.append(ldap_reslt[1])
463 #User not existing in LDAP
464 #TODO SA 21/08/12 raise smthg to add user or add it auto ?
465 logger.debug(" SLABSLICE.PY \tverify_person users \
466 not in ldap ...NEW ACCOUNT NEEDED %s \r\n \t \
467 ldap_reslt %s " %(users, ldap_reslt))
469 requested_user_ids = users_by_id.keys()
470 requested_user_hrns = users_by_hrn.keys()
471 logger.debug("SLABSLICE.PY \tverify_person requested_user_ids %s \
472 user_by_hrn %s " %(requested_user_ids, users_by_hrn))
475 #Check that the user of the slice in the slice record
476 #matches the existing users
478 if slice_record['record_id_user'] in requested_user_ids and \
479 slice_record['PI'][0] in requested_user_hrns:
480 logger.debug(" SLABSLICE \tverify_person \
481 requested_user_ids %s = \
482 slice_record['record_id_user'] %s" \
483 %(requested_user_ids,slice_record['record_id_user']))
489 # users to be added, removed or updated
490 #One user in one senslab slice : there should be no need
491 #to remove/ add any user from/to a slice.
492 #However a user from SFA which is not registered in Senslab yet
493 #should be added to the LDAP.
495 added_user_hrns = set(requested_user_hrns).\
496 difference(set(existing_user_hrns))
498 #self.verify_keys(existing_slice_users, updated_users_list, \
503 for added_user_hrn in added_user_hrns:
504 added_user = users_dict[added_user_hrn]
505 #hrn, type = urn_to_hrn(added_user['urn'])
507 #'first_name': added_user.get('first_name', hrn),
508 #'last_name': added_user.get('last_name', hrn),
509 'first_name': added_user['first_name'],
510 'last_name': added_user['last_name'],
511 'person_id': added_user['person_id'],
512 'peer_person_id': None,
514 'key_ids': added_user.get('key_ids', []),
517 person['person_id'] = self.driver.AddPerson(person)
519 person['peer_person_id'] = added_user['person_id']
520 added_persons.append(person)
523 self.driver.UpdatePerson(person['person_id'], {'enabled': True})
526 #self.driver.AddPersonToSite(added_user_id, login_base)
528 #for key_string in added_user.get('keys', []):
529 #key = {'key':key_string, 'key_type':'ssh'}
530 #key['key_id'] = self.driver.AddPersonKey(person['person_id'], \
532 #person['keys'].append(key)
534 # add the registry record
536 #peer_dict = {'type': 'user', 'hrn': hrn, 'peer_authority': \
538 #'pointer': person['person_id']}
539 #self.registry.register_peer_object(self.credential, peer_dict)
540 #for added_slice_user_hrn in \
541 #added_slice_user_hrns.union(added_user_hrns):
542 #self.driver.AddPersonToSlice(added_slice_user_hrn, \
543 #slice_record['name'])
544 #for added_slice_user_id in \
545 #added_slice_user_ids.union(added_user_ids):
546 # add person to the slice
547 #self.driver.AddPersonToSlice(added_slice_user_id, \
548 #slice_record['name'])
549 # if this is a peer record then it
550 # should already be bound to a peer.
551 # no need to return worry about it getting bound later
556 def verify_keys(self, persons, users, peer, options={}):
559 for person in persons:
560 key_ids.extend(person['key_ids'])
561 keylist = self.driver.GetKeys(key_ids, ['key_id', 'key'])
564 keydict[key['key']] = key['key_id']
565 existing_keys = keydict.keys()
567 for person in persons:
568 persondict[person['email']] = person
574 user_keys = user.get('keys', [])
575 updated_persons.append(user)
576 for key_string in user_keys:
577 requested_keys.append(key_string)
578 if key_string not in existing_keys:
579 key = {'key': key_string, 'key_type': 'ssh'}
582 person = persondict[user['email']]
583 self.driver.UnBindObjectFromPeer('person', \
584 person['person_id'], peer['shortname'])
586 self.driver.AddPersonKey(user['email'], key)
588 key_index = user_keys.index(key['key'])
589 remote_key_id = user['key_ids'][key_index]
590 self.driver.BindObjectToPeer('key', \
591 key['key_id'], peer['shortname'], \
596 self.driver.BindObjectToPeer('person', \
597 person['person_id'], peer['shortname'], \
600 # remove old keys (only if we are not appending)
601 append = options.get('append', True)
603 removed_keys = set(existing_keys).difference(requested_keys)
604 for existing_key_id in keydict:
605 if keydict[existing_key_id] in removed_keys:
608 self.driver.UnBindObjectFromPeer('key', \
609 existing_key_id, peer['shortname'])
610 self.driver.DeleteKey(existing_key_id)
613 #def verify_slice_attributes(self, slice, requested_slice_attributes, \
614 #append=False, admin=False):
615 ## get list of attributes users ar able to manage
616 #filter = {'category': '*slice*'}
618 #filter['|roles'] = ['user']
619 #slice_attributes = self.driver.GetTagTypes(filter)
620 #valid_slice_attribute_names = [attribute['tagname'] \
621 #for attribute in slice_attributes]
623 ## get sliver attributes
624 #added_slice_attributes = []
625 #removed_slice_attributes = []
626 #ignored_slice_attribute_names = []
627 #existing_slice_attributes = self.driver.GetSliceTags({'slice_id': \
630 ## get attributes that should be removed
631 #for slice_tag in existing_slice_attributes:
632 #if slice_tag['tagname'] in ignored_slice_attribute_names:
633 ## If a slice already has a admin only role
634 ## it was probably given to them by an
635 ## admin, so we should ignore it.
636 #ignored_slice_attribute_names.append(slice_tag['tagname'])
638 ## If an existing slice attribute was not
639 ## found in the request it should
641 #attribute_found=False
642 #for requested_attribute in requested_slice_attributes:
643 #if requested_attribute['name'] == slice_tag['tagname'] \
644 #and requested_attribute['value'] == slice_tag['value']:
645 #attribute_found=True
648 #if not attribute_found and not append:
649 #removed_slice_attributes.append(slice_tag)
651 ## get attributes that should be added:
652 #for requested_attribute in requested_slice_attributes:
653 ## if the requested attribute wasn't found we should add it
654 #if requested_attribute['name'] in valid_slice_attribute_names:
655 #attribute_found = False
656 #for existing_attribute in existing_slice_attributes:
657 #if requested_attribute['name'] == \
658 #existing_attribute['tagname'] and \
659 #requested_attribute['value'] == \
660 #existing_attribute['value']:
661 #attribute_found=True
663 #if not attribute_found:
664 #added_slice_attributes.append(requested_attribute)
667 ## remove stale attributes
668 #for attribute in removed_slice_attributes:
670 #self.driver.DeleteSliceTag(attribute['slice_tag_id'])
671 #except Exception, error:
672 #self.logger.warn('Failed to remove sliver attribute. name: \
673 #%s, value: %s, node_id: %s\nCause:%s'\
674 #% (name, value, node_id, str(error)))
676 ## add requested_attributes
677 #for attribute in added_slice_attributes:
679 #self.driver.AddSliceTag(slice['name'], attribute['name'], \
680 #attribute['value'], attribute.get('node_id', None))
681 #except Exception, error:
682 #self.logger.warn('Failed to add sliver attribute. name: %s, \
683 #value: %s, node_id: %s\nCause:%s'\
684 #% (name, value, node_id, str(error)))