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