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['name']})
141 #leases = self.driver.GetLeases({'name':sfa_slice['name']},\
144 current_leases = [lease['lease_id'] for lease in leases]
145 #Deleted leases are the ones with lease id not declared in the Rspec
146 deleted_leases = list(set(current_leases).difference(kept_leases))
150 #peer = RegAuyhority object is unsubscriptable
151 #TODO :UnBindObjectFromPeer Quick and dirty
152 #auth='senslab2 SA 27/07/12
154 #Commented out UnBindObjectFromPeer SA 09/10/12
155 #self.driver.UnBindObjectFromPeer('senslab2', 'slice', \
156 #sfa_slice['record_id_slice'], peer.hrn)
158 self.driver.DeleteLeases(deleted_leases, \
161 #TODO verify_slice_leases: catch other exception?
163 logger.log_exc('Failed to remove slice leases')
166 for start_time in requested_jobs_dict:
167 job = requested_jobs_dict[start_time]
168 self.driver.AddLeases(job['hostname'], \
169 sfa_slice, int(job['start_time']), \
170 int(job['duration']))
174 def verify_slice_nodes(self, sfa_slice, requested_slivers, peer):
178 if sfa_slice['node_ids']:
179 nodes = self.driver.GetNodes(sfa_slice['node_ids'], ['hostname'])
180 current_slivers = [node['hostname'] for node in nodes]
182 # remove nodes not in rspec
183 deleted_nodes = list(set(current_slivers).\
184 difference(requested_slivers))
185 # add nodes from rspec
186 #added_nodes = list(set(requested_slivers).\
187 #difference(current_slivers))
189 #Update the table with the nodes that populate the slice
190 logger.debug("SLABSLICES \tverify_slice_nodes slice %s\
191 \r\n \r\n deleted_nodes %s"\
192 %(sfa_slice,deleted_nodes))
195 self.driver.DeleteSliceFromNodes(sfa_slice['name'], \
201 def free_egre_key(self):
203 for tag in self.driver.GetSliceTags({'tagname': 'egre_key'}):
204 used.add(int(tag['value']))
206 for i in range(1, 256):
211 raise KeyError("No more EGRE keys available")
220 def handle_peer(self, site, sfa_slice, persons, peer):
225 self.driver.BindObjectToPeer('site', site['site_id'], \
226 peer['shortname'], sfa_slice['site_id'])
227 except Exception, error:
228 self.driver.DeleteSite(site['site_id'])
234 self.driver.BindObjectToPeer('slice', slice['slice_id'], \
235 peer['shortname'], sfa_slice['slice_id'])
236 except Exception, error:
237 self.driver.DeleteSlice(sfa_slice['slice_id'])
241 for person in persons:
243 self.driver.BindObjectToPeer('person', \
244 person['person_id'], peer['shortname'], \
245 person['peer_person_id'])
247 for (key, remote_key_id) in zip(person['keys'], \
250 self.driver.BindObjectToPeer( 'key', \
251 key['key_id'], peer['shortname'], \
254 self.driver.DeleteKey(key['key_id'])
255 logger.log_exc("failed to bind key: %s \
256 to peer: %s " % (key['key_id'], \
258 except Exception, error:
259 self.driver.DeletePerson(person['person_id'])
264 #def verify_site(self, slice_xrn, slice_record={}, peer=None, \
265 #sfa_peer=None, options={}):
266 #(slice_hrn, type) = urn_to_hrn(slice_xrn)
267 #site_hrn = get_authority(slice_hrn)
268 ## login base can't be longer than 20 characters
269 ##slicename = hrn_to_pl_slicename(slice_hrn)
270 #authority_name = slice_hrn.split('.')[0]
271 #login_base = authority_name[:20]
272 #logger.debug(" SLABSLICES.PY \tverify_site authority_name %s \
273 #login_base %s slice_hrn %s" \
274 #%(authority_name,login_base,slice_hrn)
276 #sites = self.driver.GetSites(login_base)
278 ## create new site record
279 #site = {'name': 'geni.%s' % authority_name,
280 #'abbreviated_name': authority_name,
281 #'login_base': login_base,
283 #'max_slivers': 1000,
285 #'peer_site_id': None}
287 #site['peer_site_id'] = slice_record.get('site_id', None)
288 #site['site_id'] = self.driver.AddSite(site)
289 ## exempt federated sites from monitor policies
290 #self.driver.AddSiteTag(site['site_id'], 'exempt_site_until', \
293 ### is this still necessary?
294 ### add record to the local registry
295 ##if sfa_peer and slice_record:
296 ##peer_dict = {'type': 'authority', 'hrn': site_hrn, \
297 ##'peer_authority': sfa_peer, 'pointer': \
299 ##self.registry.register_peer_object(self.credential, peer_dict)
303 ## unbind from peer so we can modify if necessary.
304 ## Will bind back later
305 #self.driver.UnBindObjectFromPeer('site', site['site_id'], \
310 def verify_slice(self, slice_hrn, slice_record, peer, sfa_peer):
312 #login_base = slice_hrn.split(".")[0]
313 slicename = slice_hrn
314 slices_list = self.driver.GetSlices(slice_filter = slicename, \
315 slice_filter_type = 'slice_hrn')
317 for sl in slices_list:
319 logger.debug("SLABSLICE \tverify_slice slicename %s sl %s \
320 slice_record %s"%(slicename, sl, \
323 sfa_slice.update(slice_record)
324 #del slice['last_updated']
325 #del slice['date_created']
327 #slice['peer_slice_id'] = slice_record.get('slice_id', None)
328 ## unbind from peer so we can modify if necessary.
329 ## Will bind back later
330 #self.driver.UnBindObjectFromPeer('slice', \
331 #slice['slice_id'], \
333 #Update existing record (e.g. expires field)
334 #it with the latest info.
335 ##if slice_record and slice['expires'] != slice_record['expires']:
336 ##self.driver.UpdateSlice( slice['slice_id'], {'expires' : \
337 #slice_record['expires']})
339 logger.debug(" SLABSLICES \tverify_slice Oups \
340 slice_record %s peer %s sfa_peer %s "\
341 %(slice_record, peer,sfa_peer))
342 sfa_slice = {'slice_hrn': slicename,
343 #'url': slice_record.get('url', slice_hrn),
344 #'description': slice_record.get('description', slice_hrn)
346 'record_id_user' : slice_record['person_ids'][0],
347 'record_id_slice': slice_record['record_id'],
348 'peer_authority':str(peer.hrn)
352 self.driver.AddSlice(sfa_slice)
353 #slice['slice_id'] = self.driver.AddSlice(slice)
354 logger.debug("SLABSLICES \tverify_slice ADDSLICE OK")
355 #slice['node_ids']=[]
356 #slice['person_ids'] = []
358 #slice['peer_slice_id'] = slice_record.get('slice_id', None)
359 # mark this slice as an sfa peer record
361 #peer_dict = {'type': 'slice', 'hrn': slice_hrn,
362 #'peer_authority': sfa_peer, 'pointer': \
364 #self.registry.register_peer_object(self.credential, peer_dict)
371 def verify_persons(self, slice_hrn, slice_record, users, peer, sfa_peer, \
374 users is a record list. Records can either be local records
375 or users records from known and trusted federated sites.
376 If the user is from another site that senslab doesn't trust yet,
377 then Resolve will raise an error before getting to create_sliver.
379 #TODO SA 21/08/12 verify_persons Needs review
384 #users_dict : dict whose keys can either be the user's hrn or its id.
385 #Values contains only id and hrn
388 #First create dicts by hrn and id for each user in the user record list:
391 if 'urn' in user and (not 'hrn' in user ) :
392 user['hrn'], user['type'] = urn_to_hrn(user['urn'])
394 if 'person_id' in user and 'hrn' in user:
395 users_by_id[user['person_id']] = user
396 users_dict[user['person_id']] = {'person_id':\
397 user['person_id'], 'hrn':user['hrn']}
399 users_by_hrn[user['hrn']] = user
400 users_dict[user['hrn']] = {'person_id':user['person_id'], \
404 logger.debug( "SLABSLICE.PY \t verify_person \
405 users_dict %s \r\n user_by_hrn %s \r\n \
407 %(users_dict,users_by_hrn, users_by_id))
409 existing_user_ids = []
410 existing_user_hrns = []
412 # Check if user is in Senslab LDAP using its hrn.
413 # Assuming Senslab is centralised : one LDAP for all sites,
414 # user_id unknown from LDAP
415 # LDAP does not provide users id, therefore we rely on hrns containing
416 # the login of the user.
417 # If the hrn is not a senslab hrn, the user may not be in LDAP.
419 #Construct the list of filters (list of dicts) for GetPersons
421 for hrn in users_by_hrn:
422 filter_user.append (users_by_hrn[hrn])
423 logger.debug(" SLABSLICE.PY \tverify_person filter_user %s " \
425 #Check user's in LDAP with GetPersons
426 #Needed because what if the user has been deleted in LDAP but
428 existing_users = self.driver.GetPersons(filter_user)
430 #User's in senslab LDAP
432 for user in existing_users :
433 existing_user_hrns.append(users_dict[user['hrn']]['hrn'])
435 append(users_dict[user['hrn']]['person_id'])
437 # User from another known trusted federated site. Check
438 # if a senslab account matching the email has already been created.
441 if isinstance(users, list):
443 req += users[0]['email']
445 req += users['email']
447 ldap_reslt = self.driver.ldap.LdapSearch(req)
449 logger.debug(" SLABSLICE.PY \tverify_person users \
450 USER already in Senslab \t ldap_reslt %s \
452 existing_users.append(ldap_reslt[1])
455 #User not existing in LDAP
456 #TODO SA 21/08/12 raise smthg to add user or add it auto ?
457 logger.debug(" SLABSLICE.PY \tverify_person users \
458 not in ldap ...NEW ACCOUNT NEEDED %s \r\n \t \
459 ldap_reslt %s " %(users, ldap_reslt))
461 requested_user_ids = users_by_id.keys()
462 requested_user_hrns = users_by_hrn.keys()
463 logger.debug("SLABSLICE.PY \tverify_person requested_user_ids %s \
464 user_by_hrn %s " %(requested_user_ids, users_by_hrn))
467 #Check that the user of the slice in the slice record
468 #matches the existing users
470 if slice_record['record_id_user'] in requested_user_ids and \
471 slice_record['PI'][0] in requested_user_hrns:
472 logger.debug(" SLABSLICE \tverify_person \
473 requested_user_ids %s = \
474 slice_record['record_id_user'] %s" \
475 %(requested_user_ids,slice_record['record_id_user']))
481 # users to be added, removed or updated
482 #One user in one senslab slice : there should be no need
483 #to remove/ add any user from/to a slice.
484 #However a user from SFA which is not registered in Senslab yet
485 #should be added to the LDAP.
487 added_user_hrns = set(requested_user_hrns).\
488 difference(set(existing_user_hrns))
490 #self.verify_keys(existing_slice_users, updated_users_list, \
495 for added_user_hrn in added_user_hrns:
496 added_user = users_dict[added_user_hrn]
497 #hrn, type = urn_to_hrn(added_user['urn'])
499 #'first_name': added_user.get('first_name', hrn),
500 #'last_name': added_user.get('last_name', hrn),
501 'first_name': added_user['first_name'],
502 'last_name': added_user['last_name'],
503 'person_id': added_user['person_id'],
504 'peer_person_id': None,
506 'key_ids': added_user.get('key_ids', []),
509 person['person_id'] = self.driver.AddPerson(person)
511 person['peer_person_id'] = added_user['person_id']
512 added_persons.append(person)
515 self.driver.UpdatePerson(person['person_id'], {'enabled': True})
518 #self.driver.AddPersonToSite(added_user_id, login_base)
520 #for key_string in added_user.get('keys', []):
521 #key = {'key':key_string, 'key_type':'ssh'}
522 #key['key_id'] = self.driver.AddPersonKey(person['person_id'], \
524 #person['keys'].append(key)
526 # add the registry record
528 #peer_dict = {'type': 'user', 'hrn': hrn, 'peer_authority': \
530 #'pointer': person['person_id']}
531 #self.registry.register_peer_object(self.credential, peer_dict)
532 #for added_slice_user_hrn in \
533 #added_slice_user_hrns.union(added_user_hrns):
534 #self.driver.AddPersonToSlice(added_slice_user_hrn, \
535 #slice_record['name'])
536 #for added_slice_user_id in \
537 #added_slice_user_ids.union(added_user_ids):
538 # add person to the slice
539 #self.driver.AddPersonToSlice(added_slice_user_id, \
540 #slice_record['name'])
541 # if this is a peer record then it
542 # should already be bound to a peer.
543 # no need to return worry about it getting bound later
548 def verify_keys(self, persons, users, peer, options={}):
551 for person in persons:
552 key_ids.extend(person['key_ids'])
553 keylist = self.driver.GetKeys(key_ids, ['key_id', 'key'])
556 keydict[key['key']] = key['key_id']
557 existing_keys = keydict.keys()
559 for person in persons:
560 persondict[person['email']] = person
566 user_keys = user.get('keys', [])
567 updated_persons.append(user)
568 for key_string in user_keys:
569 requested_keys.append(key_string)
570 if key_string not in existing_keys:
571 key = {'key': key_string, 'key_type': 'ssh'}
574 person = persondict[user['email']]
575 self.driver.UnBindObjectFromPeer('person', \
576 person['person_id'], peer['shortname'])
578 self.driver.AddPersonKey(user['email'], key)
580 key_index = user_keys.index(key['key'])
581 remote_key_id = user['key_ids'][key_index]
582 self.driver.BindObjectToPeer('key', \
583 key['key_id'], peer['shortname'], \
588 self.driver.BindObjectToPeer('person', \
589 person['person_id'], peer['shortname'], \
592 # remove old keys (only if we are not appending)
593 append = options.get('append', True)
595 removed_keys = set(existing_keys).difference(requested_keys)
596 for existing_key_id in keydict:
597 if keydict[existing_key_id] in removed_keys:
600 self.driver.UnBindObjectFromPeer('key', \
601 existing_key_id, peer['shortname'])
602 self.driver.DeleteKey(existing_key_id)
605 #def verify_slice_attributes(self, slice, requested_slice_attributes, \
606 #append=False, admin=False):
607 ## get list of attributes users ar able to manage
608 #filter = {'category': '*slice*'}
610 #filter['|roles'] = ['user']
611 #slice_attributes = self.driver.GetTagTypes(filter)
612 #valid_slice_attribute_names = [attribute['tagname'] \
613 #for attribute in slice_attributes]
615 ## get sliver attributes
616 #added_slice_attributes = []
617 #removed_slice_attributes = []
618 #ignored_slice_attribute_names = []
619 #existing_slice_attributes = self.driver.GetSliceTags({'slice_id': \
622 ## get attributes that should be removed
623 #for slice_tag in existing_slice_attributes:
624 #if slice_tag['tagname'] in ignored_slice_attribute_names:
625 ## If a slice already has a admin only role
626 ## it was probably given to them by an
627 ## admin, so we should ignore it.
628 #ignored_slice_attribute_names.append(slice_tag['tagname'])
630 ## If an existing slice attribute was not
631 ## found in the request it should
633 #attribute_found=False
634 #for requested_attribute in requested_slice_attributes:
635 #if requested_attribute['name'] == slice_tag['tagname'] \
636 #and requested_attribute['value'] == slice_tag['value']:
637 #attribute_found=True
640 #if not attribute_found and not append:
641 #removed_slice_attributes.append(slice_tag)
643 ## get attributes that should be added:
644 #for requested_attribute in requested_slice_attributes:
645 ## if the requested attribute wasn't found we should add it
646 #if requested_attribute['name'] in valid_slice_attribute_names:
647 #attribute_found = False
648 #for existing_attribute in existing_slice_attributes:
649 #if requested_attribute['name'] == \
650 #existing_attribute['tagname'] and \
651 #requested_attribute['value'] == \
652 #existing_attribute['value']:
653 #attribute_found=True
655 #if not attribute_found:
656 #added_slice_attributes.append(requested_attribute)
659 ## remove stale attributes
660 #for attribute in removed_slice_attributes:
662 #self.driver.DeleteSliceTag(attribute['slice_tag_id'])
663 #except Exception, error:
664 #self.logger.warn('Failed to remove sliver attribute. name: \
665 #%s, value: %s, node_id: %s\nCause:%s'\
666 #% (name, value, node_id, str(error)))
668 ## add requested_attributes
669 #for attribute in added_slice_attributes:
671 #self.driver.AddSliceTag(slice['name'], attribute['name'], \
672 #attribute['value'], attribute.get('node_id', None))
673 #except Exception, error:
674 #self.logger.warn('Failed to add sliver attribute. name: %s, \
675 #value: %s, node_id: %s\nCause:%s'\
676 #% (name, value, node_id, str(error)))