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