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