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