Cleaning.
[sfa.git] / sfa / senslab / slabdriver.py
1 import subprocess
2
3 from datetime import datetime
4
5 from sfa.util.faults import SliverDoesNotExist, UnknownSfaType
6 from sfa.util.sfalogging import logger
7
8 from sfa.storage.alchemy import dbsession
9 from sfa.storage.model import RegRecord, RegUser, RegSlice
10
11 from sfa.trust.credential import Credential
12
13
14 from sfa.managers.driver import Driver
15 from sfa.rspecs.version_manager import VersionManager
16 from sfa.rspecs.rspec import RSpec
17
18 from sfa.util.xrn import hrn_to_urn, get_authority
19
20
21 ## thierry: everything that is API-related (i.e. handling incoming requests) 
22 # is taken care of 
23 # SlabDriver should be really only about talking to the senslab testbed
24
25
26 from sfa.senslab.OARrestapi import  OARrestapi
27 from sfa.senslab.LDAPapi import LDAPapi
28
29 from sfa.senslab.slabpostgres import SlabDB, slab_dbsession, SliceSenslab
30                                                                 
31 from sfa.senslab.slabaggregate import SlabAggregate, slab_xrn_to_hostname, \
32                                                             slab_xrn_object
33 from sfa.senslab.slabslices import SlabSlices
34
35
36
37 # thierry : note
38 # this inheritance scheme is so that the driver object can receive
39 # GetNodes or GetSites sorts of calls directly
40 # and thus minimize the differences in the managers with the pl version
41 class SlabDriver(Driver):
42     """ Senslab Driver class inherited from Driver generic class.
43     
44     Contains methods compliant with the SFA standard and the testbed
45     infrastructure (calls to LDAP and OAR).
46     """
47     def __init__(self, config):
48         Driver.__init__ (self, config)
49         self.config = config
50         self.hrn = config.SFA_INTERFACE_HRN
51         self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
52         self.oar = OARrestapi()
53         self.ldap = LDAPapi()
54         self.time_format = "%Y-%m-%d %H:%M:%S"
55         self.db = SlabDB(config, debug = True)
56         self.cache = None
57         
58     
59     def sliver_status(self, slice_urn, slice_hrn):
60         """Receive a status request for slice named urn/hrn 
61         urn:publicid:IDN+senslab+nturro_slice hrn senslab.nturro_slice
62         shall return a structure as described in
63         http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
64         NT : not sure if we should implement this or not, but used by sface.
65         
66         """
67         
68         #First get the slice with the slice hrn
69         slice_list =  self.GetSlices(slice_filter = slice_hrn, \
70                                     slice_filter_type = 'slice_hrn')
71         
72         if len(slice_list) is 0:
73             raise SliverDoesNotExist("%s  slice_hrn" % (slice_hrn))
74         
75         #Slice has the same slice hrn for each slice in the slice/lease list
76         #So fetch the info on the user once 
77         one_slice = slice_list[0] 
78         recuser = dbsession.query(RegRecord).filter_by(record_id = \
79                                             one_slice['record_id_user']).first()
80         
81         #Make a list of all the nodes hostnames  in use for this slice
82         slice_nodes_list = []
83         for single_slice in slice_list:
84             for node in single_slice['node_ids']:
85                 slice_nodes_list.append(node['hostname'])
86             
87         #Get all the corresponding nodes details    
88         nodes_all = self.GetNodes({'hostname':slice_nodes_list},
89                                 ['node_id', 'hostname','site','boot_state'])
90         nodeall_byhostname = dict([(one_node['hostname'], one_node) \
91                                             for one_node in nodes_all])  
92           
93           
94           
95         for single_slice in slice_list:
96
97               #For compatibility
98             top_level_status = 'empty' 
99             result = {}
100             result.fromkeys(\
101                 ['geni_urn','pl_login','geni_status','geni_resources'], None)
102             result['pl_login'] = recuser.hrn
103             logger.debug("Slabdriver - sliver_status Sliver status \
104                                         urn %s hrn %s single_slice  %s \r\n " \
105                                         %(slice_urn, slice_hrn, single_slice))
106             try:
107                 nodes_in_slice = single_slice['node_ids']
108             except KeyError:
109                 #No job in the slice
110                 result['geni_status'] = top_level_status
111                 result['geni_resources'] = [] 
112                 return result
113            
114             top_level_status = 'ready' 
115
116             #A job is running on Senslab for this slice
117             # report about the local nodes that are in the slice only
118          
119             result['geni_urn'] = slice_urn
120             
121
122             
123             #timestamp = float(sl['startTime']) + float(sl['walltime']) 
124             #result['pl_expires'] = strftime(self.time_format, \
125                                                     #gmtime(float(timestamp)))
126             #result['slab_expires'] = strftime(self.time_format,\
127                                                     #gmtime(float(timestamp)))
128             
129             resources = []
130             for node in single_slice['node_ids']:
131                 res = {}
132                 #res['slab_hostname'] = node['hostname']
133                 #res['slab_boot_state'] = node['boot_state']
134                 
135                 res['pl_hostname'] = node['hostname']
136                 res['pl_boot_state'] = \
137                             nodeall_byhostname[node['hostname']]['boot_state']
138                 #res['pl_last_contact'] = strftime(self.time_format, \
139                                                     #gmtime(float(timestamp)))
140                 sliver_id =  Xrn(slice_urn, type='slice', \
141                         id=nodeall_byhostname[node['hostname']]['node_id'], \
142                         authority=self.hrn).urn
143     
144                 res['geni_urn'] = sliver_id 
145                 if nodeall_byhostname[node['hostname']]['boot_state'] == 'Alive':
146
147                     res['geni_status'] = 'ready'
148                 else:
149                     res['geni_status'] = 'failed'
150                     top_level_status = 'failed' 
151                     
152                 res['geni_error'] = ''
153         
154                 resources.append(res)
155                 
156             result['geni_status'] = top_level_status
157             result['geni_resources'] = resources 
158             logger.debug("SLABDRIVER \tsliver_statusresources %s res %s "\
159                                                     %(resources,res))
160             return result        
161             
162     def get_user(self, hrn):
163         return dbsession.query(RegRecord).filter_by(hrn = hrn).first() 
164          
165          
166     def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, \
167                                                              users, options):
168         aggregate = SlabAggregate(self)
169         
170         slices = SlabSlices(self)
171         peer = slices.get_peer(slice_hrn)
172         sfa_peer = slices.get_sfa_peer(slice_hrn)
173         slice_record = None 
174  
175         if not isinstance(creds, list):
176             creds = [creds]
177     
178         if users:
179             slice_record = users[0].get('slice_record', {}) 
180             logger.debug("SLABDRIVER.PY \t create_sliver \t\
181                                             slice_record %s \r\n \r\n users %s" \
182                                             %(slice_record, users))
183             slice_record['user'] = {'keys':users[0]['keys'], 'email':users[0]['email'], 'hrn':slice_record['reg-researchers'][0]}
184         # parse rspec
185         rspec = RSpec(rspec_string)
186         logger.debug("SLABDRIVER.PY \t create_sliver \trspec.version \
187                                             %s slice_record %s users %s" \
188                                             %(rspec.version,slice_record, users))
189                                             
190
191         # ensure site record exists?
192         # ensure slice record exists
193         #Removed options to verify_slice SA 14/08/12
194         sfa_slice = slices.verify_slice(slice_hrn, slice_record, peer, \
195                                                     sfa_peer)
196                                                     
197         # ensure person records exists
198         #verify_persons returns added persons but since the return value
199         #is not used 
200         slices.verify_persons(slice_hrn, sfa_slice, users, peer, \
201                                                     sfa_peer, options=options)                                           
202         #requested_attributes returned by rspec.version.get_slice_attributes() 
203         #unused, removed SA 13/08/12
204         rspec.version.get_slice_attributes()
205
206         logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice))
207         
208         
209         
210
211         
212         # add/remove slice from nodes 
213        
214         requested_slivers = [node.get('component_id') \
215                             for node in rspec.version.get_nodes_with_slivers()\
216                             if node.get('authority_id') is self.root_auth]
217         l = [ node for node in rspec.version.get_nodes_with_slivers() ]
218         logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
219                                     requested_slivers %s  listnodes %s" \
220                                     %(requested_slivers,l))
221         #verify_slice_nodes returns nodes, but unused here. Removed SA 13/08/12.
222         #slices.verify_slice_nodes(sfa_slice, requested_slivers, peer) 
223         
224         # add/remove leases
225         requested_lease_list = []
226
227         logger.debug("SLABDRIVER.PY \tcreate_sliver AVANTLEASE " )
228         rspec_requested_leases = rspec.version.get_leases()
229         for lease in rspec.version.get_leases():
230             single_requested_lease = {}
231             logger.debug("SLABDRIVER.PY \tcreate_sliver lease %s " %(lease))
232             if not lease.get('lease_id'):
233                 if get_authority(lease['component_id']) == self.root_auth:
234                     single_requested_lease['hostname'] = \
235                                 slab_xrn_to_hostname(\
236                                                 lease.get('component_id').strip())
237                     single_requested_lease['start_time'] = lease.get('start_time')
238                     single_requested_lease['duration'] = lease.get('duration')
239
240             #if single_requested_lease.get('hostname'):
241                     requested_lease_list.append(single_requested_lease)
242                 
243         logger.debug("SLABDRIVER.PY \tcreate_sliver APRESLEASE" )       
244         #dCreate dict of leases by start_time, regrouping nodes reserved
245         #at the same
246         #time, for the same amount of time = one job on OAR
247         requested_job_dict = {}
248         for lease in requested_lease_list:
249             
250             #In case it is an asap experiment start_time is empty
251             if lease['start_time'] == '':
252                 lease['start_time'] = '0' 
253                 
254             if lease['start_time'] not in requested_job_dict:
255                 if isinstance(lease['hostname'], str):
256                     lease['hostname'] =  [lease['hostname']]
257                     
258                 requested_job_dict[lease['start_time']] = lease
259                 
260             else :
261                 job_lease = requested_job_dict[lease['start_time']]
262                 if lease['duration'] == job_lease['duration'] :
263                     job_lease['hostname'].append(lease['hostname'])
264                     
265           
266                 
267                         
268         logger.debug("SLABDRIVER.PY \tcreate_sliver  requested_job_dict %s "\
269                                                      %(requested_job_dict))    
270         #verify_slice_leases returns the leases , but the return value is unused
271         #here. Removed SA 13/08/12           
272         slices.verify_slice_leases(sfa_slice, \
273                                     requested_job_dict, peer)
274         
275         return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
276         
277         
278     def delete_sliver (self, slice_urn, slice_hrn, creds, options):
279         
280         sfa_slice_list  = self.GetSlices(slice_filter = slice_hrn, \
281                                             slice_filter_type = 'slice_hrn')
282         
283         if not sfa_slice_list:
284             return 1
285         
286         #Delete all in the slice
287         for sfa_slice in sfa_slice_list:
288
289         
290             logger.debug("SLABDRIVER.PY delete_sliver slice %s" %(sfa_slice))
291             slices = SlabSlices(self)
292             # determine if this is a peer slice
293         
294             peer = slices.get_peer(slice_hrn) 
295             #TODO delete_sliver SA : UnBindObjectFromPeer should be 
296             #used when there is another 
297             #senslab testbed, which is not the case 14/08/12 . 
298             
299             logger.debug("SLABDRIVER.PY delete_sliver peer %s" %(peer))
300             try:
301                 if peer:
302                     self.UnBindObjectFromPeer('slice', \
303                                             sfa_slice['record_id_slice'], \
304                                             peer, None)
305                 self.DeleteSliceFromNodes(sfa_slice)
306             finally:
307                 if peer:
308                     self.BindObjectToPeer('slice', \
309                                             sfa_slice['record_id_slice'], \
310                                             peer, sfa_slice['peer_slice_id'])
311             return 1
312             
313             
314     def AddSlice(self, slice_record, user_record):
315         #Add slice to the sfa table
316         sfa_record = RegSlice (hrn=slice_record['slice_hrn'], gid=slice_record['gid'], 
317                                                  pointer=slice_record['slice_id'],
318                                                  authority=slice_record['authority'])
319         logger.debug("SLABDRIVER.PY AddSlice  sfa_record %s user_record %s" %(sfa_record, user_record))
320         #There is no way to separate-adding the slice to the tesbed 
321         #nd then importing it from the testebd to SFA because of the senslab's architecture
322         sfa_record.just_created()
323         dbsession.add(sfa_record)
324         dbsession.commit() 
325         sfa_record.reg_researchers =  [user_record]
326         dbsession.commit()       
327         #sl_rec = dbsession.query(RegSlice).filter(RegSlice.hrn.match(slice_hrn)).all()
328                     
329                             
330         slab_slice = SliceSenslab( slice_hrn = slice_record['slice_hrn'], \
331                         record_id_slice = sfa_record.record_id , \
332                         record_id_user = slice_record['record_id_user'], \
333                         peer_authority = slice_record['peer_authority'])
334         logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s slab_slice %s sfa_record %s" \
335                                             %(slice_record,slab_slice, sfa_record))
336         slab_dbsession.add(slab_slice)
337         slab_dbsession.commit()
338         return
339         
340     # first 2 args are None in case of resource discovery
341     def list_resources (self, slice_urn, slice_hrn, creds, options):
342         #cached_requested = options.get('cached', True) 
343     
344         version_manager = VersionManager()
345         # get the rspec's return format from options
346         rspec_version = \
347                 version_manager.get_version(options.get('geni_rspec_version'))
348         version_string = "rspec_%s" % (rspec_version)
349     
350         #panos adding the info option to the caching key (can be improved)
351         if options.get('info'):
352             version_string = version_string + "_" + \
353                                         options.get('info', 'default')
354     
355         # look in cache first
356         #if cached_requested and self.cache and not slice_hrn:
357             #rspec = self.cache.get(version_string)
358             #if rspec:
359                 #logger.debug("SlabDriver.ListResources: \
360                                     #returning cached advertisement")
361                 #return rspec 
362     
363         #panos: passing user-defined options
364         aggregate = SlabAggregate(self)
365         origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
366         options.update({'origin_hrn':origin_hrn})
367         rspec =  aggregate.get_rspec(slice_xrn=slice_urn, \
368                                         version=rspec_version, options=options)
369        
370         # cache the result
371         #if self.cache and not slice_hrn:
372             #logger.debug("Slab.ListResources: stores advertisement in cache")
373             #self.cache.add(version_string, rspec)
374     
375         return rspec
376         
377         
378     def list_slices (self, creds, options):
379         # look in cache first
380         #if self.cache:
381             #slices = self.cache.get('slices')
382             #if slices:
383                 #logger.debug("PlDriver.list_slices returns from cache")
384                 #return slices
385     
386         # get data from db 
387
388         slices = self.GetSlices()        
389         logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices))        
390         slice_hrns = [slab_slice['slice_hrn'] for slab_slice in slices]
391         #slice_hrns = [slicename_to_hrn(self.hrn, slab_slice['slice_hrn']) \
392                                                     #for slab_slice in slices]
393         slice_urns = [hrn_to_urn(slice_hrn, 'slice') \
394                                                 for slice_hrn in slice_hrns]
395
396         # cache the result
397         #if self.cache:
398             #logger.debug ("SlabDriver.list_slices stores value in cache")
399             #self.cache.add('slices', slice_urns) 
400     
401         return slice_urns
402     
403    
404     def register (self, sfa_record, hrn, pub_key):
405         """ 
406         Adding new user, slice, node or site should not be handled
407         by SFA.
408         
409         Adding nodes = OAR
410         Adding users = LDAP Senslab
411         Adding slice = Import from LDAP users
412         Adding site = OAR
413         """
414         return -1
415             
416     #No site or node record update allowed       
417     def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
418         pointer = old_sfa_record['pointer']
419         old_sfa_record_type = old_sfa_record['type']
420
421         # new_key implemented for users only
422         if new_key and old_sfa_record_type not in [ 'user' ]:
423             raise UnknownSfaType(old_sfa_record_type)
424         
425         #if (type == "authority"):
426             #self.shell.UpdateSite(pointer, new_sfa_record)
427     
428         if old_sfa_record_type == "slice":
429             slab_record = self.sfa_fields_to_slab_fields(old_sfa_record_type, \
430                                                 hrn, new_sfa_record)
431             if 'name' in slab_record:
432                 slab_record.pop('name')
433                 #Prototype should be UpdateSlice(self,
434                 #auth, slice_id_or_name, slice_fields)
435                 #Senslab cannot update slice since slice = job
436                 #so we must delete and create another job
437                 self.UpdateSlice(pointer, slab_record)
438     
439         elif old_sfa_record_type == "user":
440             update_fields = {}
441             all_fields = new_sfa_record
442             for key in all_fields.keys():
443                 if key in ['first_name', 'last_name', 'title', 'email',
444                            'password', 'phone', 'url', 'bio', 'accepted_aup',
445                            'enabled']:
446                     update_fields[key] = all_fields[key]
447             self.UpdatePerson(pointer, update_fields)
448     
449             if new_key:
450                 # must check this key against the previous one if it exists
451                 persons = self.GetPersons([pointer], ['key_ids'])
452                 person = persons[0]
453                 keys = person['key_ids']
454                 keys = self.GetKeys(person['key_ids'])
455                 
456                 # Delete all stale keys
457                 key_exists = False
458                 for key in keys:
459                     if new_key != key['key']:
460                         self.DeleteKey(key['key_id'])
461                     else:
462                         key_exists = True
463                 if not key_exists:
464                     self.AddPersonKey(pointer, {'key_type': 'ssh', \
465                                                     'key': new_key})
466
467
468         return True
469         
470
471     def remove (self, sfa_record):
472         sfa_record_type = sfa_record['type']
473         hrn = sfa_record['hrn']
474         if sfa_record_type == 'user':
475
476             #get user from senslab ldap  
477             person = self.GetPersons(sfa_record)
478             #No registering at a given site in Senslab.
479             #Once registered to the LDAP, all senslab sites are
480             #accesible.
481             if person :
482                 #Mark account as disabled in ldap
483                 self.DeletePerson(sfa_record)
484         elif sfa_record_type == 'slice':
485             if self.GetSlices(slice_filter = hrn, \
486                                     slice_filter_type = 'slice_hrn'):
487                 self.DeleteSlice(sfa_record)
488
489         #elif type == 'authority':
490             #if self.GetSites(pointer):
491                 #self.DeleteSite(pointer)
492
493         return True
494             
495             
496             
497     #TODO clean GetPeers. 05/07/12SA        
498     def GetPeers (self, auth = None, peer_filter=None, return_fields_list=None):
499
500         existing_records = {}
501         existing_hrns_by_types = {}
502         logger.debug("SLABDRIVER \tGetPeers auth = %s, peer_filter %s, \
503                     return_field %s " %(auth , peer_filter, return_fields_list))
504         all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
505         for record in all_records:
506             existing_records[(record.hrn, record.type)] = record
507             if record.type not in existing_hrns_by_types:
508                 existing_hrns_by_types[record.type] = [record.hrn]
509                 logger.debug("SLABDRIVER \tGetPeer\t NOT IN \
510                     existing_hrns_by_types %s " %( existing_hrns_by_types))
511             else:
512                 
513                 logger.debug("SLABDRIVER \tGetPeer\t \INNN  type %s hrn %s " \
514                                                 %(record.type,record.hrn))
515                 existing_hrns_by_types[record.type].append(record.hrn)
516
517                         
518         logger.debug("SLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
519                                              %( existing_hrns_by_types))
520         records_list = [] 
521       
522         try: 
523             if peer_filter:
524                 records_list.append(existing_records[(peer_filter,'authority')])
525             else :
526                 for hrn in existing_hrns_by_types['authority']:
527                     records_list.append(existing_records[(hrn,'authority')])
528                     
529             logger.debug("SLABDRIVER \tGetPeer \trecords_list  %s " \
530                                             %(records_list))
531
532         except KeyError:
533             pass
534                 
535         return_records = records_list
536         if not peer_filter and not return_fields_list:
537             return records_list
538
539        
540         logger.debug("SLABDRIVER \tGetPeer return_records %s " \
541                                                     %(return_records))
542         return return_records
543         
544      
545     #TODO  : Handling OR request in make_ldap_filters_from_records 
546     #instead of the for loop 
547     #over the records' list
548     def GetPersons(self, person_filter=None):
549         """
550         person_filter should be a list of dictionnaries when not set to None.
551         Returns a list of users whose accounts are enabled found in ldap.
552        
553         """
554         logger.debug("SLABDRIVER \tGetPersons person_filter %s" \
555                                                     %(person_filter))
556         person_list = []
557         if person_filter and isinstance(person_filter, list):
558         #If we are looking for a list of users (list of dict records)
559         #Usually the list contains only one user record
560             for searched_attributes in person_filter:
561                 
562                 #Get only enabled user accounts in senslab LDAP : 
563                 #add a filter for make_ldap_filters_from_record
564                 person = self.ldap.LdapFindUser(searched_attributes, \
565                                 is_user_enabled=True)
566                 person_list.append(person)
567           
568         else:
569             #Get only enabled user accounts in senslab LDAP : 
570             #add a filter for make_ldap_filters_from_record
571             person_list  = self.ldap.LdapFindUser(is_user_enabled=True)  
572
573         return person_list
574
575     def GetTimezone(self):
576         server_timestamp, server_tz = self.oar.parser.\
577                                             SendRequest("GET_timezone")
578         return server_timestamp, server_tz
579     
580
581     def DeleteJobs(self, job_id, slice_hrn):
582         if not job_id or job_id is -1:
583             return
584         username  = slice_hrn.split(".")[-1].rstrip("_slice")
585         reqdict = {}
586         reqdict['method'] = "delete"
587         reqdict['strval'] = str(job_id)
588        
589
590         answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id', \
591                                                     reqdict,username)
592         logger.debug("SLABDRIVER \tDeleteJobs jobid  %s \r\n answer %s \
593                                 username %s" %(job_id,answer, username))
594         return answer
595
596             
597         
598         ##TODO : Unused GetJobsId ? SA 05/07/12
599     #def GetJobsId(self, job_id, username = None ):
600         #"""
601         #Details about a specific job. 
602         #Includes details about submission time, jot type, state, events, 
603         #owner, assigned ressources, walltime etc...
604             
605         #"""
606         #req = "GET_jobs_id"
607         #node_list_k = 'assigned_network_address'
608         ##Get job info from OAR    
609         #job_info = self.oar.parser.SendRequest(req, job_id, username)
610
611         #logger.debug("SLABDRIVER \t GetJobsId  %s " %(job_info))
612         #try:
613             #if job_info['state'] == 'Terminated':
614                 #logger.debug("SLABDRIVER \t GetJobsId job %s TERMINATED"\
615                                                             #%(job_id))
616                 #return None
617             #if job_info['state'] == 'Error':
618                 #logger.debug("SLABDRIVER \t GetJobsId ERROR message %s "\
619                                                             #%(job_info))
620                 #return None
621                                                             
622         #except KeyError:
623             #logger.error("SLABDRIVER \tGetJobsId KeyError")
624             #return None 
625         
626         #parsed_job_info  = self.get_info_on_reserved_nodes(job_info, \
627                                                             #node_list_k)
628         ##Replaces the previous entry 
629         ##"assigned_network_address" / "reserved_resources"
630         ##with "node_ids"
631         #job_info.update({'node_ids':parsed_job_info[node_list_k]})
632         #del job_info[node_list_k]
633         #logger.debug(" \r\nSLABDRIVER \t GetJobsId job_info %s " %(job_info))
634         #return job_info
635
636         
637     def GetJobsResources(self, job_id, username = None):
638         #job_resources=['reserved_resources', 'assigned_resources',\
639                             #'job_id', 'job_uri', 'assigned_nodes',\
640                              #'api_timestamp']
641         #assigned_res = ['resource_id', 'resource_uri']
642         #assigned_n = ['node', 'node_uri']
643
644         req = "GET_jobs_id_resources"
645        
646                
647         #Get job resources list from OAR    
648         node_id_list = self.oar.parser.SendRequest(req, job_id, username)
649         logger.debug("SLABDRIVER \t GetJobsResources  %s " %(node_id_list))
650         
651         hostname_list = \
652             self.__get_hostnames_from_oar_node_ids(node_id_list)
653         
654
655         #Replaces the previous entry "assigned_network_address" / 
656         #"reserved_resources"
657         #with "node_ids"
658         job_info = {'node_ids': hostname_list}
659
660         return job_info
661
662             
663     def get_info_on_reserved_nodes(self, job_info, node_list_name):
664         #Get the list of the testbed nodes records and make a 
665         #dictionnary keyed on the hostname out of it
666         node_list_dict = self.GetNodes() 
667         #node_hostname_list = []
668         node_hostname_list = [node['hostname'] for node in node_list_dict] 
669         #for node in node_list_dict:
670             #node_hostname_list.append(node['hostname'])
671         node_dict = dict(zip(node_hostname_list, node_list_dict))
672         try :
673             reserved_node_hostname_list = []
674             for index in range(len(job_info[node_list_name])):
675                #job_info[node_list_name][k] = 
676                 reserved_node_hostname_list[index] = \
677                         node_dict[job_info[node_list_name][index]]['hostname']
678                             
679             logger.debug("SLABDRIVER \t get_info_on_reserved_nodes \
680                         reserved_node_hostname_list %s" \
681                         %(reserved_node_hostname_list))
682         except KeyError:
683             logger.error("SLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
684             
685         return reserved_node_hostname_list  
686             
687     def GetNodesCurrentlyInUse(self):
688         """Returns a list of all the nodes already involved in an oar job"""
689         return self.oar.parser.SendRequest("GET_running_jobs") 
690     
691     def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
692         full_nodes_dict_list = self.GetNodes()
693         #Put the full node list into a dictionary keyed by oar node id
694         oar_id_node_dict = {}
695         for node in full_nodes_dict_list:
696             oar_id_node_dict[node['oar_id']] = node
697             
698         #logger.debug("SLABDRIVER \t  __get_hostnames_from_oar_node_ids\
699                         #oar_id_node_dict %s" %(oar_id_node_dict))
700
701         hostname_dict_list = [] 
702         for resource_id in resource_id_list:
703             #Because jobs requested "asap" do not have defined resources
704             if resource_id is not "Undefined":
705                 hostname_dict_list.append(\
706                         oar_id_node_dict[resource_id]['hostname'])
707                 
708             #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
709         return hostname_dict_list 
710         
711     def GetReservedNodes(self,username = None):
712         #Get the nodes in use and the reserved nodes
713         reservation_dict_list = \
714                         self.oar.parser.SendRequest("GET_reserved_nodes", \
715                         username = username)
716         
717         
718         for resa in reservation_dict_list:
719             logger.debug ("GetReservedNodes resa %s"%(resa))
720             #dict list of hostnames and their site
721             resa['reserved_nodes'] = \
722                 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
723                 
724         #del resa['resource_ids']
725         return reservation_dict_list
726      
727     def GetNodes(self, node_filter_dict = None, return_fields_list = None):
728         """
729         node_filter_dict : dictionnary of lists
730         
731         """
732         node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
733         node_dict_list = node_dict_by_id.values()
734         logger.debug (" SLABDRIVER GetNodes  node_filter_dict %s return_fields_list %s "%(node_filter_dict,return_fields_list))
735         #No  filtering needed return the list directly
736         if not (node_filter_dict or return_fields_list):
737             return node_dict_list
738         
739         return_node_list = []
740         if node_filter_dict:
741             for filter_key in node_filter_dict:
742                 try:
743                     #Filter the node_dict_list by each value contained in the 
744                     #list node_filter_dict[filter_key]
745                     for value in node_filter_dict[filter_key]:
746                         for node in node_dict_list:
747                             if node[filter_key] == value:
748                                 if return_fields_list :
749                                     tmp = {}
750                                     for k in return_fields_list:
751                                         tmp[k] = node[k]     
752                                     return_node_list.append(tmp)
753                                 else:
754                                     return_node_list.append(node)
755                 except KeyError:
756                     logger.log_exc("GetNodes KeyError")
757                     return
758
759
760         return return_node_list
761     
762   
763     def GetSites(self, site_filter_name_list = None, return_fields_list = None):
764         site_dict = self.oar.parser.SendRequest("GET_sites")
765         #site_dict : dict where the key is the sit ename
766         return_site_list = []
767         if not ( site_filter_name_list or return_fields_list):
768             return_site_list = site_dict.values()
769             return return_site_list
770         
771         for site_filter_name in site_filter_name_list:
772             if site_filter_name in site_dict:
773                 if return_fields_list:
774                     for field in return_fields_list:
775                         tmp = {}
776                         try:
777                             tmp[field] = site_dict[site_filter_name][field]
778                         except KeyError:
779                             logger.error("GetSites KeyError %s "%(field))
780                             return None
781                     return_site_list.append(tmp)
782                 else:
783                     return_site_list.append( site_dict[site_filter_name])
784             
785
786         return return_site_list
787                 
788                 
789       
790     def GetSlices(self, slice_filter = None, slice_filter_type = None):
791     #def GetSlices(self, slice_filter = None, slice_filter_type = None, \
792                                             #return_fields_list = None):
793         """ Get the slice records from the slab db. 
794         Returns a slice ditc if slice_filter  and slice_filter_type 
795         are specified.
796         Returns a list of slice dictionnaries if there are no filters
797         specified. 
798        
799         """
800         login = None
801         authorized_filter_types_list = ['slice_hrn', 'record_id_user']
802         return_slicerec_dictlist = []
803         
804         #First try to get information on the slice based on the filter provided     
805         if slice_filter_type in authorized_filter_types_list:
806             
807             
808             def __get_slice_records(slice_filter = None, slice_filter_type = None):
809        
810                 login = None
811                 #Get list of slices based on the slice hrn
812                 if slice_filter_type == 'slice_hrn':
813         
814                     login = slice_filter.split(".")[1].split("_")[0] 
815                     
816                     #DO NOT USE RegSlice - reg_researchers to get the hrn of the user
817                     #otherwise will mess up the RegRecord in Resolve, don't know
818                     #why - SA 08/08/2012
819                     
820                     #Only one entry for one user  = one slice in slice_senslab table
821                     slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).first()
822                     
823                     if slicerec is None:
824                         return login, None    
825                 #Get slice based on user id                             
826                 if slice_filter_type == 'record_id_user':
827                     slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).first()
828                     
829                
830                 if slicerec:
831                     fixed_slicerec_dict = slicerec.dump_sqlalchemyobj_to_dict()
832                     #At this point if the there is no login it means 
833                     #record_id_user filter has been used for filtering
834                     if login is None :
835                         login = fixed_slicerec_dict['slice_hrn'].split(".")[1].split("_")[0] 
836                     return login, fixed_slicerec_dict
837                 
838             
839             
840             login, fixed_slicerec_dict = \
841                             __get_slice_records(slice_filter, slice_filter_type)
842             logger.debug(" SLABDRIVER \tGetSlices login %s \
843                             slice record %s slice_filter %s"\
844                             %(login, fixed_slicerec_dict,slice_filter))
845     
846             
847             #Now we have the slice record fixed_slicerec_dict, get the 
848             #jobs associated to this slice
849             leases_list = self.GetReservedNodes(username = login)
850             
851             #If no job is running or no job scheduled 
852             #return only the slice record           
853             if leases_list == [] and fixed_slicerec_dict:
854                 return_slicerec_dictlist.append(fixed_slicerec_dict)
855                 
856             #If several jobs for one slice , put the slice record into 
857             # each lease information dict
858             for lease in leases_list : 
859                 slicerec_dict = {} 
860                 
861                 reserved_list = lease['reserved_nodes']
862                 
863                 slicerec_dict['oar_job_id'] = lease['lease_id']
864                 slicerec_dict.update({'list_node_ids':{'hostname':reserved_list}})   
865                 slicerec_dict.update({'node_ids':lease['reserved_nodes']})
866                 #Update lease dict with the slice record
867                 if fixed_slicerec_dict:
868                     slicerec_dict.update(fixed_slicerec_dict)
869                     slicerec_dict.update({'hrn':\
870                                     str(fixed_slicerec_dict['slice_hrn'])})
871                     
872     
873                 return_slicerec_dictlist.append(slicerec_dict)
874                 logger.debug("SLABDRIVER.PY  \tGetSlices  \
875                         slicerec_dict %s return_slicerec_dictlist %s \
876                         lease['reserved_nodes'] \
877                         %s" %(slicerec_dict, return_slicerec_dictlist,\
878                         lease['reserved_nodes'] ))
879                 
880             logger.debug("SLABDRIVER.PY  \tGetSlices  RETURN \
881                         return_slicerec_dictlist  %s" %(return_slicerec_dictlist))
882                             
883             return return_slicerec_dictlist
884                 
885                 
886         else:
887             #Get all slices from the senslab sfa database ,
888             #put them in dict format
889             query_slice_list = slab_dbsession.query(SliceSenslab).all()
890             return_slicerec_dictlist = []
891             for record in query_slice_list:
892                 return_slicerec_dictlist.append(record.dump_sqlalchemyobj_to_dict())
893                 
894             #Get all the jobs reserved nodes
895             leases_list = self.GetReservedNodes()
896             
897
898             
899                 
900             for fixed_slicerec_dict in return_slicerec_dictlist:
901                 slicerec_dict = {} 
902                 owner = fixed_slicerec_dict['slice_hrn'].split(".")[1].split("_")[0] 
903                 for lease in leases_list:   
904                     if owner == lease['user']:
905                         slicerec_dict['oar_job_id'] = lease['lease_id']
906
907                         #for reserved_node in lease['reserved_nodes']:
908                         logger.debug("SLABDRIVER.PY  \tGetSlices lease %s "\
909                                                                  %(lease ))
910
911                         reserved_list = lease['reserved_nodes']
912
913                         slicerec_dict.update({'node_ids':lease['reserved_nodes']})
914                         slicerec_dict.update({'list_node_ids':{'hostname':reserved_list}}) 
915                         slicerec_dict.update(fixed_slicerec_dict)
916                         slicerec_dict.update({'hrn':\
917                                     str(fixed_slicerec_dict['slice_hrn'])})
918                         #return_slicerec_dictlist.append(slicerec_dict)
919                         fixed_slicerec_dict.update(slicerec_dict)
920                         
921             logger.debug("SLABDRIVER.PY  \tGetSlices RETURN return_slicerec_dictlist %s \
922                         slice_filter %s " %(return_slicerec_dictlist, slice_filter))
923
924         return return_slicerec_dictlist
925         
926     
927     def testbed_name (self): return self.hrn
928          
929     # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
930     def aggregate_version (self):
931         version_manager = VersionManager()
932         ad_rspec_versions = []
933         request_rspec_versions = []
934         for rspec_version in version_manager.versions:
935             if rspec_version.content_type in ['*', 'ad']:
936                 ad_rspec_versions.append(rspec_version.to_dict())
937             if rspec_version.content_type in ['*', 'request']:
938                 request_rspec_versions.append(rspec_version.to_dict()) 
939         return {
940             'testbed':self.testbed_name(),
941             'geni_request_rspec_versions': request_rspec_versions,
942             'geni_ad_rspec_versions': ad_rspec_versions,
943             }
944           
945           
946           
947           
948           
949           
950     ##
951     # Convert SFA fields to PLC fields for use when registering up updating
952     # registry record in the PLC database
953     #
954     # @param type type of record (user, slice, ...)
955     # @param hrn human readable name
956     # @param sfa_fields dictionary of SFA fields
957     # @param slab_fields dictionary of PLC fields (output)
958
959     def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
960
961
962         slab_record = {}
963         #for field in record:
964         #    slab_record[field] = record[field]
965  
966         if sfa_type == "slice":
967             #instantion used in get_slivers ? 
968             if not "instantiation" in slab_record:
969                 slab_record["instantiation"] = "senslab-instantiated"
970             #slab_record["hrn"] = hrn_to_pl_slicename(hrn)     
971             #Unused hrn_to_pl_slicename because Slab's hrn already in the appropriate form SA 23/07/12
972             slab_record["hrn"] = hrn 
973             logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
974                         slab_record %s  " %(slab_record['hrn']))
975             if "url" in record:
976                 slab_record["url"] = record["url"]
977             if "description" in record:
978                 slab_record["description"] = record["description"]
979             if "expires" in record:
980                 slab_record["expires"] = int(record["expires"])
981                 
982         #nodes added by OAR only and then imported to SFA
983         #elif type == "node":
984             #if not "hostname" in slab_record:
985                 #if not "hostname" in record:
986                     #raise MissingSfaInfo("hostname")
987                 #slab_record["hostname"] = record["hostname"]
988             #if not "model" in slab_record:
989                 #slab_record["model"] = "geni"
990                 
991         #One authority only 
992         #elif type == "authority":
993             #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
994
995             #if not "name" in slab_record:
996                 #slab_record["name"] = hrn
997
998             #if not "abbreviated_name" in slab_record:
999                 #slab_record["abbreviated_name"] = hrn
1000
1001             #if not "enabled" in slab_record:
1002                 #slab_record["enabled"] = True
1003
1004             #if not "is_public" in slab_record:
1005                 #slab_record["is_public"] = True
1006
1007         return slab_record
1008
1009     
1010
1011             
1012     def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
1013         """ Transforms unix timestamp into valid OAR date format """
1014         
1015         #Used in case of a scheduled experiment (not immediate)
1016         #To run an XP immediately, don't specify date and time in RSpec 
1017         #They will be set to None. 
1018         if xp_utc_timestamp:
1019             #transform the xp_utc_timestamp into server readable time  
1020             xp_server_readable_date = datetime.fromtimestamp(int(\
1021                                 xp_utc_timestamp)).strftime(self.time_format)
1022
1023             return xp_server_readable_date
1024             
1025         else:
1026             return None
1027         
1028    
1029
1030              
1031     def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
1032                         lease_start_time, lease_duration, slice_user=None):
1033         lease_dict = {}
1034         lease_dict['lease_start_time'] = lease_start_time
1035         lease_dict['lease_duration'] = lease_duration
1036         lease_dict['added_nodes'] = added_nodes
1037         lease_dict['slice_name'] = slice_name
1038         lease_dict['slice_user'] = slice_user
1039         lease_dict['grain'] = self.GetLeaseGranularity()
1040         lease_dict['time_format'] = self.time_format
1041         
1042         def __create_job_structure_request_for_OAR(lease_dict):
1043             """ Creates the structure needed for a correct POST on OAR.
1044             Makes the timestamp transformation into the appropriate format.
1045             Sends the POST request to create the job with the resources in 
1046             added_nodes.
1047             
1048             """
1049
1050             nodeid_list = []
1051             reqdict = {}
1052     
1053             
1054             reqdict['workdir'] = '/tmp'   
1055             reqdict['resource'] = "{network_address in ("   
1056     
1057             for node in lease_dict['added_nodes']: 
1058                 logger.debug("\r\n \r\n OARrestapi \t __create_job_structure_request_for_OAR \
1059                                                                 node %s" %(node))
1060     
1061                 # Get the ID of the node 
1062                 nodeid = node
1063                 reqdict['resource'] += "'" + nodeid + "', "
1064                 nodeid_list.append(nodeid)
1065     
1066             custom_length = len(reqdict['resource'])- 2
1067             reqdict['resource'] = reqdict['resource'][0:custom_length] + \
1068                                                 ")}/nodes=" + str(len(nodeid_list))
1069     
1070             def __process_walltime(duration):
1071                 """ Calculates the walltime in seconds from the duration in H:M:S
1072                     specified in the RSpec.
1073                     
1074                 """
1075                 if duration:
1076                     # Fixing the walltime by adding a few delays. 
1077                     # First put the walltime in seconds oarAdditionalDelay = 20;
1078                     #  additional delay for /bin/sleep command to
1079                     # take in account  prologue and epilogue scripts execution
1080                     # int walltimeAdditionalDelay = 240;  additional delay
1081                     desired_walltime = duration 
1082                     total_walltime = desired_walltime + 240 #+4 min Update SA 23/10/12
1083                     sleep_walltime = desired_walltime  # 0 sec added Update SA 23/10/12
1084                     walltime = []
1085                     #Put the walltime back in str form
1086                     #First get the hours
1087                     walltime.append(str(total_walltime / 3600))
1088                     total_walltime = total_walltime - 3600 * int(walltime[0])
1089                     #Get the remaining minutes
1090                     walltime.append(str(total_walltime / 60))
1091                     total_walltime = total_walltime - 60 * int(walltime[1])
1092                     #Get the seconds
1093                     walltime.append(str(total_walltime))
1094     
1095                 else:
1096                     logger.log_exc(" __process_walltime duration null")
1097                     
1098                 return walltime, sleep_walltime
1099                     
1100
1101             walltime, sleep_walltime = \
1102                         __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1103     
1104     
1105             reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1106                                 ":" + str(walltime[1]) + ":" + str(walltime[2])
1107             reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1108     
1109             #In case of a scheduled experiment (not immediate)
1110             #To run an XP immediately, don't specify date and time in RSpec 
1111             #They will be set to None.
1112             if lease_dict['lease_start_time'] is not '0':
1113                 #Readable time accepted by OAR
1114                 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1115                                                         strftime(lease_dict['time_format'])
1116                 reqdict['reservation'] = start_time
1117             #If there is not start time, Immediate XP. No need to add special 
1118             # OAR parameters
1119     
1120     
1121             reqdict['type'] = "deploy" 
1122             reqdict['directory'] = ""
1123             reqdict['name'] = "SFA_" + lease_dict['slice_user']
1124     
1125             return reqdict
1126         
1127                                    
1128         #Create the request for OAR
1129         reqdict = __create_job_structure_request_for_OAR(lease_dict)
1130          # first step : start the OAR job and update the job 
1131         logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1132                              \r\n "  %(reqdict))  
1133        
1134         answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1135                                                             reqdict, slice_user)
1136         logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid   %s " %(answer))
1137         try:       
1138             jobid = answer['id']
1139         except KeyError:
1140             logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1141                                 Impossible to create job  %s "  %(answer))
1142             return
1143         
1144         
1145         def __configure_experiment(jobid, added_nodes):
1146             # second step : configure the experiment
1147             # we need to store the nodes in a yaml (well...) file like this :
1148             # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1149             job_file = open('/tmp/sfa/'+ str(jobid) + '.json', 'w')
1150             job_file.write('[')
1151             job_file.write(str(added_nodes[0].strip('node')))
1152             for node in added_nodes[1:len(added_nodes)] :
1153                 job_file.write(', '+ node.strip('node'))
1154             job_file.write(']')
1155             job_file.close()
1156             return 
1157         
1158         def __launch_senslab_experiment(jobid):   
1159             # third step : call the senslab-experiment wrapper
1160             #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar 
1161             # "+str(jobid)+" "+slice_user
1162             javacmdline = "/usr/bin/java"
1163             jarname = \
1164                 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1165             #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", \
1166                                                         #str(jobid), slice_user])
1167             output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1168                                 slice_user],stdout=subprocess.PIPE).communicate()[0]
1169     
1170             logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1171                                                                     %(output))
1172             return 
1173         
1174         
1175         
1176         if jobid :
1177             logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1178                     added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1179             
1180         
1181             __configure_experiment(jobid, added_nodes)
1182             __launch_senslab_experiment(jobid) 
1183             
1184         return
1185         
1186     def AddLeases(self, hostname_list, slice_record, lease_start_time, lease_duration):
1187         logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s  \
1188                 slice_record %s lease_start_time %s lease_duration %s  "\
1189                  %( hostname_list, slice_record , lease_start_time, \
1190                  lease_duration))
1191
1192         tmp = slice_record['reg-researchers'][0].split(".")
1193         username = tmp[(len(tmp)-1)]
1194         self.LaunchExperimentOnOAR(hostname_list, slice_record['slice_hrn'], lease_start_time, lease_duration, username)
1195         start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1196         logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1197         
1198         return
1199     
1200     
1201     #Delete the jobs from job_senslab table
1202     def DeleteSliceFromNodes(self, slice_record):
1203
1204         self.DeleteJobs(slice_record['oar_job_id'], slice_record['hrn'])
1205         return   
1206     
1207  
1208     def GetLeaseGranularity(self):
1209         """ Returns the granularity of Senslab testbed.
1210         OAR returns seconds for experiments duration.
1211         Defined in seconds. """
1212         
1213         grain = 60 
1214         return grain
1215     
1216     def GetLeases(self, lease_filter_dict=None):
1217         
1218         
1219         unfiltered_reservation_list = self.GetReservedNodes()
1220
1221         reservation_list = []
1222         #Find the slice associated with this user senslab ldap uid
1223         logger.debug(" SLABDRIVER.PY \tGetLeases ")
1224         #Create user dict first to avoid looking several times for
1225         #the same user in LDAP SA 27/07/12
1226         resa_user_dict = {}
1227         for resa in unfiltered_reservation_list:
1228             logger.debug("SLABDRIVER \tGetLeases USER %s"\
1229                                             %(resa['user']))    
1230             if resa['user'] not in resa_user_dict: 
1231                 logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1232                 ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1233                 ldap_info = ldap_info[0][1]
1234                 user = dbsession.query(RegUser).filter_by(email = \
1235                                                     ldap_info['mail'][0]).first()
1236                 #Separated in case user not in database : 
1237                 #record_id not defined SA 17/07//12
1238                 query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1239                 if query_slice_info:
1240                     slice_info = query_slice_info.first()
1241                 else:
1242                     slice_info = None
1243                     
1244                 resa_user_dict[resa['user']] = {}
1245                 resa_user_dict[resa['user']]['ldap_info'] = user
1246                 resa_user_dict[resa['user']]['slice_info'] = slice_info
1247  
1248         logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1249                                             %(resa_user_dict))         
1250         for resa in unfiltered_reservation_list:
1251             
1252             
1253             #Put the slice_urn  
1254             resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info'].slice_hrn
1255             resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')    
1256             #Put the slice_urn 
1257             #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1258             resa['component_id_list'] = []
1259             #Transform the hostnames into urns (component ids)
1260             for node in resa['reserved_nodes']:
1261                 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1262                          #self.root_auth, node['hostname']))
1263                 slab_xrn = slab_xrn_object(self.root_auth, node)
1264                 resa['component_id_list'].append(slab_xrn.urn)
1265         
1266         #Filter the reservation list if necessary
1267         #Returns all the leases associated with a given slice
1268         if lease_filter_dict:
1269             logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1270                                             %(lease_filter_dict))
1271             for resa in unfiltered_reservation_list:
1272                 if lease_filter_dict['name'] == resa['slice_hrn']:
1273                     reservation_list.append(resa)
1274         else:
1275             reservation_list = unfiltered_reservation_list
1276             
1277         logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1278                                                     %(reservation_list))
1279         return reservation_list
1280             
1281     def augment_records_with_testbed_info (self, sfa_records):
1282         return self.fill_record_info (sfa_records)
1283     
1284     def fill_record_info(self, record_list):
1285         """
1286         Given a SFA record, fill in the senslab specific and SFA specific
1287         fields in the record. 
1288         """
1289                     
1290         logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1291         if not isinstance(record_list, list):
1292             record_list = [record_list]
1293             
1294         try:
1295             for record in record_list:
1296                 #If the record is a SFA slice record, then add information 
1297                 #about the user of this slice. This kind of 
1298                 #information is in the Senslab's DB.
1299                 if str(record['type']) == 'slice':
1300                     #Get slab slice record.
1301                     recslice_list = self.GetSlices(slice_filter = \
1302                                                 str(record['hrn']),\
1303                                                 slice_filter_type = 'slice_hrn')
1304                     
1305                     recuser = dbsession.query(RegRecord).filter_by(record_id = \
1306                                             recslice_list[0]['record_id_user']).first()
1307                     logger.debug("SLABDRIVER \tfill_record_info TYPE SLICE RECUSER %s " %(recuser))
1308                     record.update({'PI':[recuser.hrn],
1309                                 'researcher': [recuser.hrn],
1310                                 'name':record['hrn'], 
1311                                 'oar_job_id':[],
1312                                 'node_ids': [],
1313                                 'person_ids':[recslice_list[0]['record_id_user']],
1314                                 'geni_urn':'',  #For client_helper.py compatibility
1315                                 'keys':'',  #For client_helper.py compatibility
1316                                 'key_ids':''})  #For client_helper.py compatibility
1317                     
1318                     try:
1319                         for rec in recslice_list:
1320                             record['oar_job_id'].append(rec['oar_job_id'])
1321                             record['node_ids'] = [ self.root_auth + hostname for hostname in rec['node_ids']]
1322                     except KeyError:
1323                         pass
1324
1325                     logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1326                                                     recslice_list  %s \r\n \t RECORD %s \r\n \r\n" %(recslice_list,record)) 
1327                 if str(record['type']) == 'user':
1328                     #The record is a SFA user record.
1329                     #Get the information about his slice from Senslab's DB
1330                     #and add it to the user record.
1331                     recslice_list = self.GetSlices(\
1332                             slice_filter = record['record_id'],\
1333                             slice_filter_type = 'record_id_user')
1334                                             
1335                     logger.debug( "SLABDRIVER.PY \t fill_record_info TYPE USER \
1336                                                 recslice_list %s \r\n \t RECORD %s \r\n" %(recslice_list , record)) 
1337                     #Append slice record in records list, 
1338                     #therefore fetches user and slice info again(one more loop)
1339                     #Will update PIs and researcher for the slice
1340                     recuser = dbsession.query(RegRecord).filter_by(record_id = \
1341                                                 recslice_list[0]['record_id_user']).first()
1342                     logger.debug( "SLABDRIVER.PY \t fill_record_info USER  \
1343                                                 recuser %s \r\n \r\n" %(recuser)) 
1344                     recslice = {}
1345                     recslice = recslice_list[0]
1346                     recslice.update({'PI':[recuser.hrn],
1347                         'researcher': [recuser.hrn],
1348                         'name':record['hrn'], 
1349                         'node_ids': [],
1350                         'oar_job_id': [],
1351                         'person_ids':[recslice_list[0]['record_id_user']]}) 
1352                     try:
1353                         for rec in recslice_list:
1354                             recslice['oar_job_id'].append(rec['oar_job_id'])
1355                     except KeyError:
1356                         pass
1357                             
1358                     recslice.update({'type':'slice', \
1359                                                 'hrn':recslice_list[0]['slice_hrn']})
1360
1361
1362                     #GetPersons takes [] as filters 
1363                     #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1364                     user_slab = self.GetPersons([record])
1365     
1366                     
1367                     record.update(user_slab[0])
1368                     #For client_helper.py compatibility
1369                     record.update( { 'geni_urn':'',
1370                     'keys':'',
1371                     'key_ids':'' })                
1372                     record_list.append(recslice)
1373                     
1374                     logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1375                                 INFO TO USER records %s" %(record_list)) 
1376                 logger.debug("SLABDRIVER.PY \tfill_record_info END \
1377                                 #record %s \r\n \r\n " %(record))     
1378
1379         except TypeError, error:
1380             logger.log_exc("SLABDRIVER \t fill_record_info  EXCEPTION %s"\
1381                                                                      %(error))
1382         #logger.debug("SLABDRIVER.PY \t fill_record_info ENDENDEND ")
1383                               
1384         return
1385         
1386         #self.fill_record_slab_info(records)
1387     
1388     
1389         
1390
1391     
1392     #TODO Update membership?    update_membership_list SA 05/07/12
1393     #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1394                                                                 #delFunc):
1395         ## get a list of the HRNs tht are members of the old and new records
1396         #if oldRecord:
1397             #oldList = oldRecord.get(listName, [])
1398         #else:
1399             #oldList = []     
1400         #newList = record.get(listName, [])
1401
1402         ## if the lists are the same, then we don't have to update anything
1403         #if (oldList == newList):
1404             #return
1405
1406         ## build a list of the new person ids, by looking up each person to get
1407         ## their pointer
1408         #newIdList = []
1409         #table = SfaTable()
1410         #records = table.find({'type': 'user', 'hrn': newList})
1411         #for rec in records:
1412             #newIdList.append(rec['pointer'])
1413
1414         ## build a list of the old person ids from the person_ids field 
1415         #if oldRecord:
1416             #oldIdList = oldRecord.get("person_ids", [])
1417             #containerId = oldRecord.get_pointer()
1418         #else:
1419             ## if oldRecord==None, then we are doing a Register, instead of an
1420             ## update.
1421             #oldIdList = []
1422             #containerId = record.get_pointer()
1423
1424     ## add people who are in the new list, but not the oldList
1425         #for personId in newIdList:
1426             #if not (personId in oldIdList):
1427                 #addFunc(self.plauth, personId, containerId)
1428
1429         ## remove people who are in the old list, but not the new list
1430         #for personId in oldIdList:
1431             #if not (personId in newIdList):
1432                 #delFunc(self.plauth, personId, containerId)
1433
1434     #def update_membership(self, oldRecord, record):
1435        
1436         #if record.type == "slice":
1437             #self.update_membership_list(oldRecord, record, 'researcher',
1438                                         #self.users.AddPersonToSlice,
1439                                         #self.users.DeletePersonFromSlice)
1440         #elif record.type == "authority":
1441             ## xxx TODO
1442             #pass
1443
1444 ### thierry
1445 # I don't think you plan on running a component manager at this point
1446 # let me clean up the mess of ComponentAPI that is deprecated anyways
1447
1448
1449 #TODO FUNCTIONS SECTION 04/07/2012 SA
1450
1451     #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1452     #04/07/2012 SA
1453     def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1454         """ This method is a hopefully temporary hack to let the sfa correctly
1455         detach the objects it creates from a remote peer object. This is 
1456         needed so that the sfa federation link can work in parallel with 
1457         RefreshPeer, as RefreshPeer depends on remote objects being correctly 
1458         marked.
1459         Parameters:
1460         auth : struct, API authentication structure
1461             AuthMethod : string, Authentication method to use 
1462         object_type : string, Object type, among 'site','person','slice',
1463         'node','key'
1464         object_id : int, object_id
1465         shortname : string, peer shortname 
1466         FROM PLC DOC
1467         
1468         """
1469         logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1470                         DO NOTHING \r\n ")
1471         return 
1472     
1473     #TODO Is BindObjectToPeer still necessary ? Currently does nothing 
1474     #04/07/2012 SA
1475     def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1476                                                     remote_object_id=None):
1477         """This method is a hopefully temporary hack to let the sfa correctly 
1478         attach the objects it creates to a remote peer object. This is needed 
1479         so that the sfa federation link can work in parallel with RefreshPeer, 
1480         as RefreshPeer depends on remote objects being correctly marked.
1481         Parameters:
1482         shortname : string, peer shortname 
1483         remote_object_id : int, remote object_id, set to 0 if unknown 
1484         FROM PLC API DOC
1485         
1486         """
1487         logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1488         return
1489     
1490     #TODO UpdateSlice 04/07/2012 SA
1491     #Funciton should delete and create another job since oin senslab slice=job
1492     def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):    
1493         """Updates the parameters of an existing slice with the values in 
1494         slice_fields.
1495         Users may only update slices of which they are members. 
1496         PIs may update any of the slices at their sites, or any slices of 
1497         which they are members. Admins may update any slice.
1498         Only PIs and admins may update max_nodes. Slices cannot be renewed
1499         (by updating the expires parameter) more than 8 weeks into the future.
1500          Returns 1 if successful, faults otherwise.
1501         FROM PLC API DOC
1502         
1503         """  
1504         logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1505         return
1506     
1507     #TODO UpdatePerson 04/07/2012 SA
1508     def UpdatePerson(self, auth, person_id_or_email, person_fields=None):
1509         """Updates a person. Only the fields specified in person_fields 
1510         are updated, all other fields are left untouched.
1511         Users and techs can only update themselves. PIs can only update
1512         themselves and other non-PIs at their sites.
1513         Returns 1 if successful, faults otherwise.
1514         FROM PLC API DOC
1515          
1516         """
1517         logger.warning("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1518         return
1519     
1520     #TODO GetKeys 04/07/2012 SA
1521     def GetKeys(self, auth, key_filter=None, return_fields=None):
1522         """Returns an array of structs containing details about keys. 
1523         If key_filter is specified and is an array of key identifiers, 
1524         or a struct of key attributes, only keys matching the filter 
1525         will be returned. If return_fields is specified, only the 
1526         specified details will be returned.
1527
1528         Admin may query all keys. Non-admins may only query their own keys.
1529         FROM PLC API DOC
1530         
1531         """
1532         logger.warning("SLABDRIVER  GetKeys EMPTY - DO NOTHING \r\n ")
1533         return
1534     
1535     #TODO DeleteKey 04/07/2012 SA
1536     def DeleteKey(self, auth, key_id):
1537         """  Deletes a key.
1538          Non-admins may only delete their own keys.
1539          Returns 1 if successful, faults otherwise.
1540          FROM PLC API DOC
1541          
1542         """
1543         logger.warning("SLABDRIVER  DeleteKey EMPTY - DO NOTHING \r\n ")
1544         return
1545
1546     
1547     #TODO : Check rights to delete person 
1548     def DeletePerson(self, auth, person_record):
1549         """ Disable an existing account in senslab LDAP.
1550         Users and techs can only delete themselves. PIs can only 
1551         delete themselves and other non-PIs at their sites. 
1552         ins can delete anyone.
1553         Returns 1 if successful, faults otherwise.
1554         FROM PLC API DOC
1555         
1556         """
1557         #Disable user account in senslab LDAP
1558         ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1559         logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1560         return ret
1561     
1562     #TODO Check DeleteSlice, check rights 05/07/2012 SA
1563     def DeleteSlice(self, auth, slice_record):
1564         """ Deletes the specified slice.
1565          Senslab : Kill the job associated with the slice if there is one
1566          using DeleteSliceFromNodes.
1567          Updates the slice record in slab db to remove the slice nodes.
1568          
1569          Users may only delete slices of which they are members. PIs may 
1570          delete any of the slices at their sites, or any slices of which 
1571          they are members. Admins may delete any slice.
1572          Returns 1 if successful, faults otherwise.
1573          FROM PLC API DOC
1574         
1575         """
1576         self.DeleteSliceFromNodes(slice_record)
1577         logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1578         return
1579     
1580     #TODO AddPerson 04/07/2012 SA
1581     #def AddPerson(self, auth,  person_fields=None): 
1582     def AddPerson(self, record):#TODO fixing 28/08//2012 SA
1583         """Adds a new account. Any fields specified in records are used, 
1584         otherwise defaults are used.
1585         Accounts are disabled by default. To enable an account, 
1586         use UpdatePerson().
1587         Returns the new person_id (> 0) if successful, faults otherwise. 
1588         FROM PLC API DOC
1589         
1590         """
1591         ret = self.ldap.LdapAddUser(record)
1592         logger.warning("SLABDRIVER AddPerson return code %s \r\n ", ret)
1593         return
1594     
1595     #TODO AddPersonToSite 04/07/2012 SA
1596     def AddPersonToSite (self, auth, person_id_or_email, \
1597                                                 site_id_or_login_base=None):
1598         """  Adds the specified person to the specified site. If the person is 
1599         already a member of the site, no errors are returned. Does not change 
1600         the person's primary site.
1601         Returns 1 if successful, faults otherwise.
1602         FROM PLC API DOC
1603         
1604         """
1605         logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1606         return
1607     
1608     #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1609     def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1610         """Grants the specified role to the person.
1611         PIs can only grant the tech and user roles to users and techs at their 
1612         sites. Admins can grant any role to any user.
1613         Returns 1 if successful, faults otherwise.
1614         FROM PLC API DOC
1615         
1616         """
1617         logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1618         return
1619     
1620     #TODO AddPersonKey 04/07/2012 SA
1621     def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1622         """Adds a new key to the specified account.
1623         Non-admins can only modify their own keys.
1624         Returns the new key_id (> 0) if successful, faults otherwise.
1625         FROM PLC API DOC
1626         
1627         """
1628         logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1629         return
1630     
1631     def DeleteLeases(self, leases_id_list, slice_hrn ):
1632         for job_id in leases_id_list:
1633             self.DeleteJobs(job_id, slice_hrn)
1634         
1635         logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \
1636                 \r\n " %(leases_id_list, slice_hrn))
1637         return