9d35ba210da3296c45afd7efe788a032263b99e8
[sfa.git] / sfa / senslab / slabslices.py
1 from sfa.util.xrn import get_authority, urn_to_hrn
2 from sfa.util.sfalogging import logger
3
4
5 MAXINT =  2L**31-1
6
7 class SlabSlices:
8
9     rspec_to_slice_tag = {'max_rate':'net_max_rate'}
10     
11     
12     def __init__(self, driver):
13         self.driver = driver
14         
15     ##Used in SFACE?    
16     #def get_slivers(self, xrn, node=None):
17         #hrn, hrn_type = urn_to_hrn(xrn)
18          
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) 
23         
24
25        
26         #sfa_slice = self.driver.GetSlices(slice_filter = slice_name, \
27         #                                   slice_filter_type = 'slice_hrn')
28  
29
30         ## Get user information
31         ##TODO
32         #alchemy_person = dbsession.query(RegRecord).filter_by(record_id = \
33                                         #sfa_slice['record_id_user']).first()
34
35         #slivers = []
36         #sliver_attributes = []
37             
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']
44             
45             #for node in nodes:
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']})
53
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
59                 ## already set.
60                 #if slice_tag not in slice_tags:
61                     #attributes.append({'tagname': slice_tag['tagname'],
62                         #'value': slice_tag['value']})
63
64             #for slice_tag in filter(lambda a: a['node_id'] is None, \
65                                                             #slice_tags):
66                 ## Do not set any global slice attributes for
67                 ## which there is at least one sliver attribute
68                 ## already set.
69                 #if slice_tag['tagname'] not in sliver_attributes:
70                     #attributes.append({'tagname': slice_tag['tagname'],
71                                    #'value': slice_tag['value']})
72
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
77             
78             #slivers.append({
79                 #'hrn': hrn,
80                 #'name': sfa_slice['name'],
81                 #'slice_id': sfa_slice['slice_id'],
82                 #'instantiation': sfa_slice['instantiation'],
83                 #'expires': sfa_slice['expires'],
84                 #'keys': keys,
85                 #'attributes': attributes
86             #})
87
88         #return slivers
89         
90         
91         
92
93
94         #return slivers
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?
98         peer = None
99         
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 :
110             return None
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:
115           
116             if site_authority == peer_record.hrn:
117                 peer = peer_record
118         logger.debug(" SLABSLICES \tget_peer peer  %s " %(peer))
119         return peer
120
121     def get_sfa_peer(self, xrn):
122         hrn, hrn_type = urn_to_hrn(xrn)
123
124         # return the authority for this hrn or None if we are the authority
125         sfa_peer = None
126         slice_authority = get_authority(hrn)
127         site_authority = get_authority(slice_authority)
128
129         if site_authority != self.driver.hrn:
130             sfa_peer = site_authority
131
132         return sfa_peer
133         
134         
135     def verify_slice_leases(self, sfa_slice, requested_jobs_dict, peer):
136
137        
138         #First get the list of current leases from OAR          
139         leases = self.driver.GetLeases({'name':sfa_slice['slice_hrn']})
140         logger.debug("SLABSLICES verify_slice_leases requested_jobs_dict %s \
141                         leases %s "%(requested_jobs_dict, leases ))
142         
143         
144         if leases : 
145             current_nodes_reserved_by_start_time = {}
146             requested_nodes_by_start_time = {}
147             leases_by_start_time = {}
148             #Create reduced dictionary with key start_time and value 
149             # the list of nodes
150             #-for the leases already registered by OAR first
151             # then for the new leases requested by the user
152             
153             #Leases already scheduled/running in OAR
154             for lease in leases :
155                 current_nodes_reserved_by_start_time[lease['t_from']] = \
156                         lease['reserved_nodes']
157                 leases_by_start_time[lease['t_from']] = lease
158                 
159             #Requested jobs     
160             for start_time in requested_jobs_dict:
161                 requested_nodes_by_start_time[int(start_time)]  = \
162                         requested_jobs_dict[start_time]['hostname']
163                      
164             #Check if there is any difference between the leases already
165             #registered in OAR and the requested jobs.   
166             #Difference could be:
167             #-Lease deleted in the requested jobs
168             #-Added/removed nodes
169             #-Newly added lease 
170
171             
172             #Find all deleted leases
173             start_time_list = \
174                 list(set(leases_by_start_time.keys()).\
175                 difference(requested_nodes_by_start_time.keys()))
176             deleted_leases = [leases_by_start_time[start_time]['lease_id'] \
177                                 for start_time in start_time_list]
178
179   
180             reschedule_jobs_dict = {}
181             #Find added or removed nodes in exisiting leases
182             for start_time in requested_nodes_by_start_time:
183                 if start_time in current_nodes_reserved_by_start_time:
184                     
185                     if requested_nodes_by_start_time[start_time] == \
186                         current_nodes_reserved_by_start_time[start_time]:
187                         continue
188                     
189                     else:
190                         update_node_set = \
191                                 set(requested_nodes_by_start_time[start_time])
192                         added_nodes = \
193                             update_node_set.difference(\
194                             current_nodes_reserved_by_start_time[start_time])
195                         shared_nodes = \
196                             update_node_set.intersection(\
197                             current_nodes_reserved_by_start_time[start_time])
198                         old_nodes_set = \
199                             set(\
200                             current_nodes_reserved_by_start_time[start_time])
201                         removed_nodes = \
202                             old_nodes_set.difference(\
203                             requested_nodes_by_start_time[start_time])
204                         logger.debug("SLABSLICES verify_slice_leases \
205                             shared_nodes %s  added_nodes %s removed_nodes %s"\
206                             %(shared_nodes, added_nodes,removed_nodes ))
207                         #If the lease is modified, delete it before 
208                         #creating it again.
209                         #Add the deleted lease job id in the list
210                         #WARNING :rescheduling does not work if there is already  
211                         # 2 running/scheduled jobs because deleting a job 
212                         #takes time SA 18/10/2012
213                         if added_nodes or removed_nodes:
214                             deleted_leases.append(\
215                                 leases_by_start_time[start_time]['lease_id'])
216                             #Reschedule the job 
217                             if added_nodes or shared_nodes:
218                                 reschedule_jobs_dict[str(start_time)] = \
219                                             requested_jobs_dict[str(start_time)]
220
221                 else: 
222                         #New lease 
223                         job = requested_jobs_dict[str(start_time)]
224                         self.driver.AddLeases(job['hostname'], \
225                                 sfa_slice, int(job['start_time']), \
226                                 int(job['duration']))
227
228             #Deleted leases are the ones with lease id not declared in the Rspec
229             if deleted_leases:
230                 self.driver.DeleteLeases(deleted_leases, sfa_slice['slice_hrn'])
231                 logger.debug("SLABSLICES \
232                         verify_slice_leases slice %s deleted_leases %s"\
233                         %(sfa_slice, deleted_leases))
234                         
235                         
236             if reschedule_jobs_dict : 
237                 for start_time in reschedule :
238                     job = reschedule_jobs_dict[start_time]
239                     self.driver.AddLeases(job['hostname'], \
240                         sfa_slice, int(job['start_time']), \
241                         int(job['duration']))
242         return leases
243
244     def verify_slice_nodes(self, sfa_slice, requested_slivers, peer):
245         current_slivers = []
246         deleted_nodes = []
247
248         if 'node_ids' in sfa_slice:
249             nodes = self.driver.GetNodes(sfa_slice['list_node_ids'], \
250                 ['hostname'])
251             current_slivers = [node['hostname'] for node in nodes]
252     
253             # remove nodes not in rspec
254             deleted_nodes = list(set(current_slivers).\
255                                                 difference(requested_slivers))
256             # add nodes from rspec
257             #added_nodes = list(set(requested_slivers).\
258                                         #difference(current_slivers))
259
260             #Update the table with the nodes that populate the slice
261             logger.debug("SLABSLICES \tverify_slice_nodes slice %s\
262                                          \r\n \r\n deleted_nodes %s"\
263                                         %(sfa_slice, deleted_nodes))
264
265             if deleted_nodes:
266                 #Delete the entire experience
267                 self.driver.DeleteSliceFromNodes(sfa_slice)
268                 #self.driver.DeleteSliceFromNodes(sfa_slice['slice_hrn'], \
269                                                                 #deleted_nodes)
270             return nodes
271
272             
273
274     def free_egre_key(self):
275         used = set()
276         for tag in self.driver.GetSliceTags({'tagname': 'egre_key'}):
277             used.add(int(tag['value']))
278
279         for i in range(1, 256):
280             if i not in used:
281                 key = i
282                 break
283         else:
284             raise KeyError("No more EGRE keys available")
285
286         return str(key)
287
288   
289        
290                         
291         
292
293     def handle_peer(self, site, sfa_slice, persons, peer):
294         if peer:
295             # bind site
296             try:
297                 if site:
298                     self.driver.BindObjectToPeer('site', site['site_id'], \
299                                         peer['shortname'], sfa_slice['site_id'])
300             except Exception, error:
301                 self.driver.DeleteSite(site['site_id'])
302                 raise error
303             
304             # bind slice
305             try:
306                 if sfa_slice:
307                     self.driver.BindObjectToPeer('slice', slice['slice_id'], \
308                                     peer['shortname'], sfa_slice['slice_id'])
309             except Exception, error:
310                 self.driver.DeleteSlice(sfa_slice['slice_id'])
311                 raise error 
312
313             # bind persons
314             for person in persons:
315                 try:
316                     self.driver.BindObjectToPeer('person', \
317                                     person['person_id'], peer['shortname'], \
318                                     person['peer_person_id'])
319
320                     for (key, remote_key_id) in zip(person['keys'], \
321                                                         person['key_ids']):
322                         try:
323                             self.driver.BindObjectToPeer( 'key', \
324                                             key['key_id'], peer['shortname'], \
325                                             remote_key_id)
326                         except:
327                             self.driver.DeleteKey(key['key_id'])
328                             logger.log_exc("failed to bind key: %s \
329                                             to peer: %s " % (key['key_id'], \
330                                             peer['shortname']))
331                 except Exception, error:
332                     self.driver.DeletePerson(person['person_id'])
333                     raise error       
334
335         return sfa_slice
336
337     #def verify_site(self, slice_xrn, slice_record={}, peer=None, \
338                                         #sfa_peer=None, options={}):
339         #(slice_hrn, type) = urn_to_hrn(slice_xrn)
340         #site_hrn = get_authority(slice_hrn)
341         ## login base can't be longer than 20 characters
342         ##slicename = hrn_to_pl_slicename(slice_hrn)
343         #authority_name = slice_hrn.split('.')[0]
344         #login_base = authority_name[:20]
345         #logger.debug(" SLABSLICES.PY \tverify_site authority_name %s  \
346                                         #login_base %s slice_hrn %s" \
347                                         #%(authority_name,login_base,slice_hrn)
348         
349         #sites = self.driver.GetSites(login_base)
350         #if not sites:
351             ## create new site record
352             #site = {'name': 'geni.%s' % authority_name,
353                     #'abbreviated_name': authority_name,
354                     #'login_base': login_base,
355                     #'max_slices': 100,
356                     #'max_slivers': 1000,
357                     #'enabled': True,
358                     #'peer_site_id': None}
359             #if peer:
360                 #site['peer_site_id'] = slice_record.get('site_id', None)
361             #site['site_id'] = self.driver.AddSite(site)
362             ## exempt federated sites from monitor policies
363             #self.driver.AddSiteTag(site['site_id'], 'exempt_site_until', \
364                                                                 #"20200101")
365             
366             ### is this still necessary?
367             ### add record to the local registry 
368             ##if sfa_peer and slice_record:
369                 ##peer_dict = {'type': 'authority', 'hrn': site_hrn, \
370                              ##'peer_authority': sfa_peer, 'pointer': \
371                                                         #site['site_id']}
372                 ##self.registry.register_peer_object(self.credential, peer_dict)
373         #else:
374             #site =  sites[0]
375             #if peer:
376                 ## unbind from peer so we can modify if necessary.
377                 ## Will bind back later
378                 #self.driver.UnBindObjectFromPeer('site', site['site_id'], \
379                                                             #peer['shortname']) 
380         
381         #return site        
382
383     def verify_slice(self, slice_hrn, slice_record, peer, sfa_peer):
384
385         #login_base = slice_hrn.split(".")[0]
386         slicename = slice_hrn
387         slices_list = self.driver.GetSlices(slice_filter = slicename, \
388                                             slice_filter_type = 'slice_hrn') 
389         if slices_list:
390             for sl in slices_list:
391             
392                 logger.debug("SLABSLICE \tverify_slice slicename %s sl %s \
393                                     slice_record %s"%(slicename, sl, \
394                                                             slice_record))
395                 sfa_slice = sl
396                 sfa_slice.update(slice_record)
397                 #del slice['last_updated']
398                 #del slice['date_created']
399                 #if peer:
400                     #slice['peer_slice_id'] = slice_record.get('slice_id', None)
401                     ## unbind from peer so we can modify if necessary. 
402                     ## Will bind back later
403                     #self.driver.UnBindObjectFromPeer('slice', \
404                                                         #slice['slice_id'], \
405                                                             #peer['shortname'])
406                 #Update existing record (e.g. expires field) 
407                     #it with the latest info.
408                 ##if slice_record and slice['expires'] != slice_record['expires']:
409                     ##self.driver.UpdateSlice( slice['slice_id'], {'expires' : \
410                                                         #slice_record['expires']})
411         else:
412             logger.debug(" SLABSLICES \tverify_slice Oups \
413                         slice_record %s peer %s sfa_peer %s "\
414                         %(slice_record, peer,sfa_peer))
415             sfa_slice = {'slice_hrn': slicename,
416                      #'url': slice_record.get('url', slice_hrn), 
417                      #'description': slice_record.get('description', slice_hrn)
418                      'node_list' : [],
419                      'record_id_user' : slice_record['person_ids'][0],
420                      'record_id_slice': slice_record['record_id'],
421                      'peer_authority':str(peer.hrn)
422                     
423                      }
424             # add the slice  
425             self.driver.AddSlice(sfa_slice)                         
426             #slice['slice_id'] = self.driver.AddSlice(slice)
427             logger.debug("SLABSLICES \tverify_slice ADDSLICE OK") 
428             #slice['node_ids']=[]
429             #slice['person_ids'] = []
430             #if peer:
431                 #slice['peer_slice_id'] = slice_record.get('slice_id', None) 
432             # mark this slice as an sfa peer record
433             #if sfa_peer:
434                 #peer_dict = {'type': 'slice', 'hrn': slice_hrn, 
435                              #'peer_authority': sfa_peer, 'pointer': \
436                                                     #slice['slice_id']}
437                 #self.registry.register_peer_object(self.credential, peer_dict)
438             
439
440        
441         return sfa_slice
442
443
444     def verify_persons(self, slice_hrn, slice_record, users,  peer, sfa_peer, \
445                                                                 options={}):
446         """ 
447         users is a record list. Records can either be local records 
448         or users records from known and trusted federated sites. 
449         If the user is from another site that senslab doesn't trust yet,
450         then Resolve will raise an error before getting to create_sliver. 
451         """
452         #TODO SA 21/08/12 verify_persons Needs review 
453         
454         
455         users_by_id = {}  
456         users_by_hrn = {} 
457         #users_dict : dict whose keys can either be the user's hrn or its id.
458         #Values contains only id and hrn 
459         users_dict = {}
460         
461         #First create dicts by hrn and id for each user in the user record list:      
462         for user in users:
463             
464             if 'urn' in user and (not 'hrn' in user ) :
465                 user['hrn'], user['type'] = urn_to_hrn(user['urn'])
466                
467             if 'person_id' in user and 'hrn' in user:
468                 users_by_id[user['person_id']] = user
469                 users_dict[user['person_id']] = {'person_id':\
470                                         user['person_id'], 'hrn':user['hrn']}
471
472                 users_by_hrn[user['hrn']] = user
473                 users_dict[user['hrn']] = {'person_id':user['person_id'], \
474                                                         'hrn':user['hrn']}
475                 
476         
477         logger.debug( "SLABSLICE.PY \t verify_person  \
478                         users_dict %s \r\n user_by_hrn %s \r\n \
479                         \tusers_by_id %s " \
480                         %(users_dict,users_by_hrn, users_by_id))
481         
482         existing_user_ids = []
483         existing_user_hrns = []
484         existing_users = []
485         # Check if user is in Senslab LDAP using its hrn.
486         # Assuming Senslab is centralised :  one LDAP for all sites, 
487         # user_id unknown from LDAP
488         # LDAP does not provide users id, therefore we rely on hrns containing
489         # the login of the user.
490         # If the hrn is not a senslab hrn, the user may not be in LDAP.
491         if users_by_hrn:
492             #Construct the list of filters (list of dicts) for GetPersons
493             filter_user = []
494             for hrn in users_by_hrn:
495                 filter_user.append (users_by_hrn[hrn])
496             logger.debug(" SLABSLICE.PY \tverify_person  filter_user %s " \
497                                                     %(filter_user))
498             #Check user's in LDAP with GetPersons
499             #Needed because what if the user has been deleted in LDAP but 
500             #is still in SFA?
501             existing_users = self.driver.GetPersons(filter_user) 
502                            
503             #User's in senslab LDAP               
504             if existing_users:
505                 for user in existing_users :
506                     existing_user_hrns.append(users_dict[user['hrn']]['hrn'])
507                     existing_user_ids.\
508                                     append(users_dict[user['hrn']]['person_id'])
509          
510             # User from another known trusted federated site. Check 
511             # if a senslab account matching the email has already been created.
512             else: 
513                 req = 'mail='
514                 if isinstance(users, list):
515                     
516                     req += users[0]['email']  
517                 else:
518                     req += users['email']
519                     
520                 ldap_reslt = self.driver.ldap.LdapSearch(req)
521                 if ldap_reslt:
522                     logger.debug(" SLABSLICE.PY \tverify_person users \
523                                 USER already in Senslab \t ldap_reslt %s \
524                                 "%( ldap_reslt)) 
525                     existing_users.append(ldap_reslt[1])
526                  
527                 else:
528                     #User not existing in LDAP
529                     #TODO SA 21/08/12 raise smthg to add user or add it auto ?
530                     logger.debug(" SLABSLICE.PY \tverify_person users \
531                                 not in ldap ...NEW ACCOUNT NEEDED %s \r\n \t \
532                                 ldap_reslt %s "  %(users, ldap_reslt))
533    
534         requested_user_ids = users_by_id.keys() 
535         requested_user_hrns = users_by_hrn.keys()
536         logger.debug("SLABSLICE.PY \tverify_person requested_user_ids  %s \
537                         user_by_hrn %s " %(requested_user_ids, users_by_hrn)) 
538       
539    
540         #Check that the user of the slice in the slice record
541         #matches the existing users 
542         try:
543             if slice_record['record_id_user'] in requested_user_ids and \
544                                 slice_record['PI'][0] in requested_user_hrns:
545                 logger.debug(" SLABSLICE  \tverify_person  \
546                         requested_user_ids %s = \
547                         slice_record['record_id_user'] %s" \
548                         %(requested_user_ids,slice_record['record_id_user']))
549            
550         except KeyError:
551             pass
552             
553       
554         # users to be added, removed or updated
555         #One user in one senslab slice : there should be no need
556         #to remove/ add any user from/to a slice.
557         #However a user from SFA which is not registered in Senslab yet
558         #should be added to the LDAP.
559
560         added_user_hrns = set(requested_user_hrns).\
561                                             difference(set(existing_user_hrns))
562
563         #self.verify_keys(existing_slice_users, updated_users_list, \
564                                                             #peer, append)
565
566         added_persons = []
567         # add new users
568         for added_user_hrn in added_user_hrns:
569             added_user = users_dict[added_user_hrn]
570             #hrn, type = urn_to_hrn(added_user['urn'])  
571             person = {
572                 #'first_name': added_user.get('first_name', hrn),
573                 #'last_name': added_user.get('last_name', hrn),
574                 'first_name': added_user['first_name'],
575                 'last_name': added_user['last_name'],
576                 'person_id': added_user['person_id'],
577                 'peer_person_id': None,
578                 'keys': [],
579                 'key_ids': added_user.get('key_ids', []),
580                 
581             } 
582             person['person_id'] = self.driver.AddPerson(person)
583             if peer:
584                 person['peer_person_id'] = added_user['person_id']
585             added_persons.append(person)
586            
587             # enable the account 
588             self.driver.UpdatePerson(person['person_id'], {'enabled': True})
589             
590             # add person to site
591             #self.driver.AddPersonToSite(added_user_id, login_base)
592
593             #for key_string in added_user.get('keys', []):
594                 #key = {'key':key_string, 'key_type':'ssh'}
595                 #key['key_id'] = self.driver.AddPersonKey(person['person_id'], \
596                                                 #                       key)
597                 #person['keys'].append(key)
598
599             # add the registry record
600             #if sfa_peer:
601                 #peer_dict = {'type': 'user', 'hrn': hrn, 'peer_authority': \
602                                                 #sfa_peer, \
603                                                 #'pointer': person['person_id']}
604                 #self.registry.register_peer_object(self.credential, peer_dict)
605         #for added_slice_user_hrn in \
606                                 #added_slice_user_hrns.union(added_user_hrns):
607             #self.driver.AddPersonToSlice(added_slice_user_hrn, \
608                                                     #slice_record['name'])
609         #for added_slice_user_id in \
610                                     #added_slice_user_ids.union(added_user_ids):
611             # add person to the slice 
612             #self.driver.AddPersonToSlice(added_slice_user_id, \
613                                                 #slice_record['name'])
614             # if this is a peer record then it 
615             # should already be bound to a peer.
616             # no need to return worry about it getting bound later 
617
618         return added_persons
619             
620     #Unused
621     def verify_keys(self, persons, users, peer, options={}):
622         # existing keys 
623         key_ids = []
624         for person in persons:
625             key_ids.extend(person['key_ids'])
626         keylist = self.driver.GetKeys(key_ids, ['key_id', 'key'])
627         keydict = {}
628         for key in keylist:
629             keydict[key['key']] = key['key_id']     
630         existing_keys = keydict.keys()
631         persondict = {}
632         for person in persons:
633             persondict[person['email']] = person    
634     
635         # add new keys
636         requested_keys = []
637         updated_persons = []
638         for user in users:
639             user_keys = user.get('keys', [])
640             updated_persons.append(user)
641             for key_string in user_keys:
642                 requested_keys.append(key_string)
643                 if key_string not in existing_keys:
644                     key = {'key': key_string, 'key_type': 'ssh'}
645                     try:
646                         if peer:
647                             person = persondict[user['email']]
648                             self.driver.UnBindObjectFromPeer('person', \
649                                         person['person_id'], peer['shortname'])
650                         key['key_id'] = \
651                                 self.driver.AddPersonKey(user['email'], key)
652                         if peer:
653                             key_index = user_keys.index(key['key'])
654                             remote_key_id = user['key_ids'][key_index]
655                             self.driver.BindObjectToPeer('key', \
656                                             key['key_id'], peer['shortname'], \
657                                             remote_key_id)
658                             
659                     finally:
660                         if peer:
661                             self.driver.BindObjectToPeer('person', \
662                                     person['person_id'], peer['shortname'], \
663                                     user['person_id'])
664         
665         # remove old keys (only if we are not appending)
666         append = options.get('append', True)
667         if append == False: 
668             removed_keys = set(existing_keys).difference(requested_keys)
669             for existing_key_id in keydict:
670                 if keydict[existing_key_id] in removed_keys:
671
672                     if peer:
673                         self.driver.UnBindObjectFromPeer('key', \
674                                         existing_key_id, peer['shortname'])
675                     self.driver.DeleteKey(existing_key_id)
676  
677
678     #def verify_slice_attributes(self, slice, requested_slice_attributes, \
679                                             #append=False, admin=False):
680         ## get list of attributes users ar able to manage
681         #filter = {'category': '*slice*'}
682         #if not admin:
683             #filter['|roles'] = ['user']
684         #slice_attributes = self.driver.GetTagTypes(filter)
685         #valid_slice_attribute_names = [attribute['tagname'] \
686                                             #for attribute in slice_attributes]
687
688         ## get sliver attributes
689         #added_slice_attributes = []
690         #removed_slice_attributes = []
691         #ignored_slice_attribute_names = []
692         #existing_slice_attributes = self.driver.GetSliceTags({'slice_id': \
693                                                             #slice['slice_id']})
694
695         ## get attributes that should be removed
696         #for slice_tag in existing_slice_attributes:
697             #if slice_tag['tagname'] in ignored_slice_attribute_names:
698                 ## If a slice already has a admin only role 
699                 ## it was probably given to them by an
700                 ## admin, so we should ignore it.
701                 #ignored_slice_attribute_names.append(slice_tag['tagname'])
702             #else:
703                 ## If an existing slice attribute was not 
704                 ## found in the request it should
705                 ## be removed
706                 #attribute_found=False
707                 #for requested_attribute in requested_slice_attributes:
708                     #if requested_attribute['name'] == slice_tag['tagname'] \
709                         #and requested_attribute['value'] == slice_tag['value']:
710                         #attribute_found=True
711                         #break
712
713             #if not attribute_found and not append:
714                 #removed_slice_attributes.append(slice_tag)
715         
716         ## get attributes that should be added:
717         #for requested_attribute in requested_slice_attributes:
718             ## if the requested attribute wasn't found  we should add it
719             #if requested_attribute['name'] in valid_slice_attribute_names:
720                 #attribute_found = False
721                 #for existing_attribute in existing_slice_attributes:
722                     #if requested_attribute['name'] == \
723                         #existing_attribute['tagname'] and \
724                        #requested_attribute['value'] == \
725                        #existing_attribute['value']:
726                         #attribute_found=True
727                         #break
728                 #if not attribute_found:
729                     #added_slice_attributes.append(requested_attribute)
730
731
732         ## remove stale attributes
733         #for attribute in removed_slice_attributes:
734             #try:
735                 #self.driver.DeleteSliceTag(attribute['slice_tag_id'])
736             #except Exception, error:
737                 #self.logger.warn('Failed to remove sliver attribute. name: \
738                                 #%s, value: %s, node_id: %s\nCause:%s'\
739                                 #% (name, value,  node_id, str(error)))
740
741         ## add requested_attributes
742         #for attribute in added_slice_attributes:
743             #try:
744                 #self.driver.AddSliceTag(slice['name'], attribute['name'], \
745                             #attribute['value'], attribute.get('node_id', None))
746             #except Exception, error:
747                 #self.logger.warn('Failed to add sliver attribute. name: %s, \
748                                 #value: %s, node_id: %s\nCause:%s'\
749                                 #% (name, value,  node_id, str(error)))
750
751