dbafef89cd7be80a513d9504ce8b89ac0640b5e2
[sfa.git] / sfa / senslab / slabdriver.py
1 import sys
2 import subprocess
3
4 from datetime import datetime
5 from dateutil import tz 
6 from time import strftime,gmtime
7
8 from sfa.util.faults import MissingSfaInfo , SliverDoesNotExist
9 from sfa.util.sfalogging import logger
10 from sfa.util.defaultdict import defaultdict
11
12 from sfa.storage.record import Record
13 from sfa.storage.alchemy import dbsession
14 from sfa.storage.model import RegRecord
15
16
17 from sfa.trust.certificate import *
18 from sfa.trust.credential import *
19 from sfa.trust.gid import GID
20
21 from sfa.managers.driver import Driver
22 from sfa.rspecs.version_manager import VersionManager
23 from sfa.rspecs.rspec import RSpec
24
25 from sfa.util.xrn import hrn_to_urn, urn_to_sliver_id
26 from sfa.util.plxrn import slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename
27
28 ## thierry: everything that is API-related (i.e. handling incoming requests) 
29 # is taken care of 
30 # SlabDriver should be really only about talking to the senslab testbed
31
32 ## thierry : please avoid wildcard imports :)
33 from sfa.senslab.OARrestapi import  OARrestapi
34 from sfa.senslab.LDAPapi import LDAPapi
35
36 from sfa.senslab.parsing import parse_filter
37 from sfa.senslab.slabpostgres import SlabDB, slab_dbsession,SliceSenslab
38 from sfa.senslab.slabaggregate import SlabAggregate
39 from sfa.senslab.slabslices import SlabSlices
40
41 def list_to_dict(recs, key):
42     """
43     convert a list of dictionaries into a dictionary keyed on the 
44     specified dictionary key 
45     """
46    # print>>sys.stderr, " \r\n \t\t 1list_to_dict : rec %s  \r\n \t\t list_to_dict key %s" %(recs,key)   
47     keys = [rec[key] for rec in recs]
48     #print>>sys.stderr, " \r\n \t\t list_to_dict : rec %s  \r\n \t\t list_to_dict keys %s" %(recs,keys)   
49     return dict(zip(keys, recs))
50
51 # thierry : note
52 # this inheritance scheme is so that the driver object can receive
53 # GetNodes or GetSites sorts of calls directly
54 # and thus minimize the differences in the managers with the pl version
55 class SlabDriver(Driver):
56
57     def __init__(self, config):
58         Driver.__init__ (self, config)
59         self.config=config
60         self.hrn = config.SFA_INTERFACE_HRN
61     
62         self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
63
64         
65         print >>sys.stderr, "\r\n_____________ SFA SENSLAB DRIVER \r\n" 
66         # thierry - just to not break the rest of this code
67
68
69         #self.oar = OARapi()
70         self.oar = OARrestapi()
71         self.ldap = LDAPapi()
72         #self.users = SenslabImportUsers()
73         self.time_format = "%Y-%m-%d %H:%M:%S"
74         self.db = SlabDB(config)
75         #self.logger=sfa_logger()
76         self.cache=None
77         
78
79     def sliver_status(self,slice_urn,slice_hrn):
80         # receive a status request for slice named urn/hrn urn:publicid:IDN+senslab+nturro_slice hrn senslab.nturro_slice
81         # shall return a structure as described in
82         # http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
83         # NT : not sure if we should implement this or not, but used by sface.
84         
85
86         sl = self.GetSlices(slice_filter= slice_hrn, filter_type = 'slice_hrn')
87         if len(sl) is 0:
88             raise SliverDoesNotExist("%s  slice_hrn" % (slice_hrn))
89
90         print >>sys.stderr, "\r\n \r\n_____________ Sliver status urn %s hrn %s sl %s \r\n " %(slice_urn,slice_hrn,sl)
91         if sl['oar_job_id'] is not -1:
92     
93             # report about the local nodes only
94             nodes_all = self.GetNodes({'hostname':sl['node_ids']},
95                             ['node_id', 'hostname','site','boot_state'])
96             nodeall_byhostname = dict([(n['hostname'], n) for n in nodes_all])
97             nodes = sl['node_ids']
98             if len(nodes) is 0:
99                 raise SliverDoesNotExist("No slivers allocated ") 
100                     
101              
102            
103     
104             result = {}
105             top_level_status = 'unknown'
106             if nodes:
107                 top_level_status = 'ready'
108             result['geni_urn'] = slice_urn
109             result['pl_login'] = sl['job_user']
110             #result['slab_login'] = sl['job_user']
111             
112             timestamp = float(sl['startTime']) + float(sl['walltime']) 
113             result['pl_expires'] = strftime(self.time_format, gmtime(float(timestamp)))
114             #result['slab_expires'] = strftime(self.time_format, gmtime(float(timestamp)))
115             
116             resources = []
117             for node in nodes:
118                 res = {}
119                 #res['slab_hostname'] = node['hostname']
120                 #res['slab_boot_state'] = node['boot_state']
121                 
122                 res['pl_hostname'] = nodeall_byhostname[node]['hostname']
123                 res['pl_boot_state'] = nodeall_byhostname[node]['boot_state']
124                 res['pl_last_contact'] = strftime(self.time_format, gmtime(float(timestamp)))
125                 sliver_id = urn_to_sliver_id(slice_urn, sl['record_id_slice'],nodeall_byhostname[node]['node_id'] ) 
126                 res['geni_urn'] = sliver_id 
127                 if nodeall_byhostname[node]['boot_state'] == 'Alive':
128                 #if node['boot_state'] == 'Alive':
129                     res['geni_status'] = 'ready'
130                 else:
131                     res['geni_status'] = 'failed'
132                     top_level_status = 'failed' 
133                     
134                 res['geni_error'] = ''
135         
136                 resources.append(res)
137                 
138             result['geni_status'] = top_level_status
139             result['geni_resources'] = resources 
140             print >>sys.stderr, "\r\n \r\n_____________ Sliver status resources %s res %s \r\n " %(resources,res)
141             return result        
142         
143         
144     def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, users, options):
145         aggregate = SlabAggregate(self)
146
147         slices = SlabSlices(self)
148         peer = slices.get_peer(slice_hrn)
149         sfa_peer = slices.get_sfa_peer(slice_hrn)
150         slice_record=None 
151
152        
153         if not isinstance(creds, list):
154             creds = [creds]
155
156            
157         if users:
158             slice_record = users[0].get('slice_record', {})
159     
160         # parse rspec
161         rspec = RSpec(rspec_string)
162         requested_attributes = rspec.version.get_slice_attributes()
163         
164         # ensure site record exists
165         #site = slices.verify_site(slice_hrn, slice_record, peer, sfa_peer, options=options)
166         # ensure slice record exists
167         slice = slices.verify_slice(slice_hrn, slice_record, peer, sfa_peer, options=options)
168         # ensure person records exists
169         persons = slices.verify_persons(slice_hrn, slice, users, peer, sfa_peer, options=options)
170         # ensure slice attributes exists
171         #slices.verify_slice_attributes(slice, requested_attributes, options=options)
172         
173         # add/remove slice from nodes
174         requested_slivers = [node.get('component_name') for node in rspec.version.get_nodes_with_slivers()]
175         nodes = slices.verify_slice_nodes(slice, requested_slivers, peer) 
176     
177       
178     
179         # handle MyPLC peer association.
180         # only used by plc and ple.
181         #slices.handle_peer(site, slice, persons, peer)
182         
183         return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
184         
185         
186     def delete_sliver (self, slice_urn, slice_hrn, creds, options):
187         
188         slices = self.GetSlices(slice_filter= slice_hrn, filter_type = 'slice_hrn')
189         if not slices:
190             return 1
191         slice = slices[0]
192     
193         # determine if this is a peer slice
194         # xxx I wonder if this would not need to use PlSlices.get_peer instead 
195         # in which case plc.peers could be deprecated as this here
196         # is the only/last call to this last method in plc.peers
197         peer = peers.get_peer(self, slice_hrn)
198         try:
199             if peer:
200                 self.UnBindObjectFromPeer('slice', slice['slice_id'], peer)
201             self.DeleteSliceFromNodes(slice_hrn, slice['node_ids'])
202         finally:
203             if peer:
204                 self.BindObjectToPeer('slice', slice['slice_id'], peer, slice['peer_slice_id'])
205         return 1
206             
207             
208             
209             
210     # first 2 args are None in case of resource discovery
211     def list_resources (self, slice_urn, slice_hrn, creds, options):
212         #cached_requested = options.get('cached', True) 
213     
214         version_manager = VersionManager()
215         # get the rspec's return format from options
216         rspec_version = version_manager.get_version(options.get('geni_rspec_version'))
217         version_string = "rspec_%s" % (rspec_version)
218     
219         #panos adding the info option to the caching key (can be improved)
220         if options.get('info'):
221             version_string = version_string + "_"+options.get('info', 'default')
222     
223         # look in cache first
224         #if cached_requested and self.cache and not slice_hrn:
225             #rspec = self.cache.get(version_string)
226             #if rspec:
227                 #logger.debug("SlabDriver.ListResources: returning cached advertisement")
228                 #return rspec 
229     
230         #panos: passing user-defined options
231         #print "manager options = ",options
232         aggregate = SlabAggregate(self)
233         origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
234         print>>sys.stderr, " \r\n \r\n \t SLABDRIVER get_rspec origin_hrn %s" %(origin_hrn)
235         options.update({'origin_hrn':origin_hrn})
236         print>>sys.stderr, " \r\n \r\n \t SLABDRIVER get_rspec options %s" %(options)
237         rspec =  aggregate.get_rspec(slice_xrn=slice_urn, version=rspec_version, 
238                                      options=options)
239     
240         # cache the result
241         #if self.cache and not slice_hrn:
242             #logger.debug("Slab.ListResources: stores advertisement in cache")
243             #self.cache.add(version_string, rspec)
244     
245         return rspec
246         
247         
248     def list_slices (self, creds, options):
249         # look in cache first
250         #if self.cache:
251             #slices = self.cache.get('slices')
252             #if slices:
253                 #logger.debug("PlDriver.list_slices returns from cache")
254                 #return slices
255     
256         # get data from db 
257         print>>sys.stderr, " \r\n \t\t SLABDRIVER.PY list_slices"
258         slices = self.GetSlices()
259         slice_hrns = [slicename_to_hrn(self.hrn, slice['slice_hrn']) for slice in slices]
260         slice_urns = [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slice_hrns]
261     
262         # cache the result
263         #if self.cache:
264             #logger.debug ("SlabDriver.list_slices stores value in cache")
265             #self.cache.add('slices', slice_urns) 
266     
267         return slice_urns
268     
269     #No site or node register supported
270     def register (self, sfa_record, hrn, pub_key):
271         type = sfa_record['type']
272         slab_record = self.sfa_fields_to_slab_fields(type, hrn, sfa_record)
273     
274         #if type == 'authority':
275             #sites = self.shell.GetSites([slab_record['login_base']])
276             #if not sites:
277                 #pointer = self.shell.AddSite(slab_record)
278             #else:
279                 #pointer = sites[0]['site_id']
280     
281         if type == 'slice':
282             acceptable_fields=['url', 'instantiation', 'name', 'description']
283             for key in slab_record.keys():
284                 if key not in acceptable_fields:
285                     slab_record.pop(key) 
286             print>>sys.stderr, " \r\n \t\t SLABDRIVER.PY register"
287             slices = self.GetSlices(slice_filter =slab_record['hrn'], filter_type = 'slice_hrn')
288             if not slices:
289                     pointer = self.AddSlice(slab_record)
290             else:
291                     pointer = slices[0]['slice_id']
292     
293         elif type == 'user':
294             persons = self.GetPersons([sfa_record['hrn']])
295             if not persons:
296                 pointer = self.AddPerson(dict(sfa_record))
297                 #add in LDAP 
298             else:
299                 pointer = persons[0]['person_id']
300                 
301             #Does this make sense to senslab ?
302             #if 'enabled' in sfa_record and sfa_record['enabled']:
303                 #self.UpdatePerson(pointer, {'enabled': sfa_record['enabled']})
304                 
305             # add this person to the site only if she is being added for the first
306             # time by sfa and doesont already exist in plc
307             if not persons or not persons[0]['site_ids']:
308                 login_base = get_leaf(sfa_record['authority'])
309                 self.AddPersonToSite(pointer, login_base)
310     
311             # What roles should this user have?
312             self.AddRoleToPerson('user', pointer)
313             # Add the user's key
314             if pub_key:
315                 self.AddPersonKey(pointer, {'key_type' : 'ssh', 'key' : pub_key})
316                 
317         #No node adding outside OAR
318         #elif type == 'node':
319             #login_base = hrn_to_slab_login_base(sfa_record['authority'])
320             #nodes = self.GetNodes([slab_record['hostname']])
321             #if not nodes:
322                 #pointer = self.AddNode(login_base, slab_record)
323             #else:
324                 #pointer = nodes[0]['node_id']
325     
326         return pointer
327             
328     #No site or node record update allowed       
329     def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
330         pointer = old_sfa_record['pointer']
331         type = old_sfa_record['type']
332
333         # new_key implemented for users only
334         if new_key and type not in [ 'user' ]:
335             raise UnknownSfaType(type)
336         
337         #if (type == "authority"):
338             #self.shell.UpdateSite(pointer, new_sfa_record)
339     
340         if type == "slice":
341             slab_record=self.sfa_fields_to_slab_fields(type, hrn, new_sfa_record)
342             if 'name' in slab_record:
343                 slab_record.pop('name')
344                 self.UpdateSlice(pointer, slab_record)
345     
346         elif type == "user":
347             update_fields = {}
348             all_fields = new_sfa_record
349             for key in all_fields.keys():
350                 if key in ['first_name', 'last_name', 'title', 'email',
351                            'password', 'phone', 'url', 'bio', 'accepted_aup',
352                            'enabled']:
353                     update_fields[key] = all_fields[key]
354             self.UpdatePerson(pointer, update_fields)
355     
356             if new_key:
357                 # must check this key against the previous one if it exists
358                 persons = self.GetPersons([pointer], ['key_ids'])
359                 person = persons[0]
360                 keys = person['key_ids']
361                 keys = self.GetKeys(person['key_ids'])
362                 
363                 # Delete all stale keys
364                 key_exists = False
365                 for key in keys:
366                     if new_key != key['key']:
367                         self.DeleteKey(key['key_id'])
368                     else:
369                         key_exists = True
370                 if not key_exists:
371                     self.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
372     
373         #elif type == "node":
374             #self.UpdateNode(pointer, new_sfa_record)
375
376         return True
377         
378
379     def remove (self, sfa_record):
380         type=sfa_record['type']
381         hrn=sfa_record['hrn']
382         record_id= sfa_record['record_id']
383         if type == 'user':
384             username = hrn.split(".")[len(hrn.split(".")) -1]
385             #get user in ldap
386             persons = self.GetPersons(username)
387             # only delete this person if he has site ids. if he doesnt, it probably means
388             # he was just removed from a site, not actually deleted
389             if persons and persons[0]['site_ids']:
390                 self.DeletePerson(username)
391         elif type == 'slice':
392             if self.GetSlices(slice_filter = hrn, filter_type = 'slice_hrn'):
393                 self.DeleteSlice(hrn)
394
395         #elif type == 'authority':
396             #if self.GetSites(pointer):
397                 #self.DeleteSite(pointer)
398
399         return True
400             
401     def GetPeers (self,auth = None, peer_filter=None, return_fields=None):
402
403         existing_records = {}
404         existing_hrns_by_types= {}
405         print >>sys.stderr, "\r\n \r\n SLABDRIVER GetPeers auth = %s, peer_filter %s, return_field %s " %(auth , peer_filter, return_fields)
406         all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
407         for record in all_records:
408             existing_records[record.hrn] = record
409             if record.type not in existing_hrns_by_types:
410                 existing_hrns_by_types[record.type] = [record.hrn]
411                 print >>sys.stderr, "\r\n \r\n SLABDRIVER GetPeers \t NOT IN existing_hrns_by_types %s " %( existing_hrns_by_types)
412             else:
413                 
414                 print >>sys.stderr, "\r\n \r\n SLABDRIVER GetPeers \t INNN  type %s hrn %s " %( record.type,record.hrn )
415                 existing_hrns_by_types.update({record.type:(existing_hrns_by_types[record.type].append(record.hrn))})
416                         
417         print >>sys.stderr, "\r\n \r\n SLABDRIVER GetPeers        existing_hrns_by_types %s " %( existing_hrns_by_types)
418         records_list= [] 
419       
420         try:
421             for hrn in existing_hrns_by_types['authority+sa']:
422                 records_list.append(existing_records[hrn])
423                 print >>sys.stderr, "\r\n \r\n SLABDRIVER GetPeers  records_list  %s " %(records_list)
424                 
425         except:
426                 pass
427
428         if not peer_filter and not return_fields:
429             return records_list
430         return_records = parse_filter(records_list,peer_filter, 'peers', return_fields) 
431  
432         return return_records
433         
434      
435             
436     def GetPersons(self, person_filter=None, return_fields=None):
437         
438         person_list = self.ldap.ldapFind({'authority': self.root_auth })
439         
440         #check = False
441         #if person_filter and isinstance(person_filter, dict):
442             #for k in  person_filter.keys():
443                 #if k in person_list[0].keys():
444                     #check = True
445                     
446         return_person_list = parse_filter(person_list,person_filter ,'persons', return_fields)
447         if return_person_list:
448             print>>sys.stderr, " \r\n GetPersons person_filter %s return_fields %s  " %(person_filter,return_fields)
449             return return_person_list
450
451     def GetTimezone(self):
452         server_timestamp,server_tz = self.oar.parser.SendRequest("GET_timezone")
453         return server_timestamp,server_tz
454     
455
456     def DeleteJobs(self, job_id, username):
457         if not job_id:
458             return
459         reqdict = {}
460         reqdict['method'] = "delete"
461         reqdict['strval'] = str(job_id)
462         answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id',reqdict,username)
463         print>>sys.stderr, "\r\n \r\n  jobid  DeleteJobs %s "  %(answer)
464         
465                 
466     def GetJobs(self,job_id= None, resources=True,return_fields=None, username = None):
467         #job_resources=['reserved_resources', 'assigned_resources','job_id', 'job_uri', 'assigned_nodes',\
468         #'api_timestamp']
469         #assigned_res = ['resource_id', 'resource_uri']
470         #assigned_n = ['node', 'node_uri']
471       
472      
473         if job_id and resources is False:
474             req = "GET_jobs_id"
475             node_list_k = 'assigned_network_address'
476            
477         if job_id and resources :
478             req = "GET_jobs_id_resources"
479             node_list_k = 'reserved_resources' 
480
481       
482                
483         #Get job info from OAR    
484         job_info = self.oar.parser.SendRequest(req, job_id, username)
485         print>>sys.stderr, "\r\n \r\n \t\t GetJobs  %s " %(job_info)
486         
487         if 'state' in job_info :
488             if job_info['state'] == 'Terminated':
489                 print>>sys.stderr, "\r\n \r\n \t\t GetJobs TERMINELEBOUSIN "
490                 return None
491             if job_info['state'] == 'Error':
492                 print>>sys.stderr, "\r\n \r\n \t\t GetJobs ERROR message %s " %(job_info)
493                 return None
494         
495         #Get a dict of nodes . Key :hostname of the node
496         node_list = self.GetNodes() 
497         node_hostname_list = []
498         for node in node_list:
499             node_hostname_list.append(node['hostname'])
500         node_dict = dict(zip(node_hostname_list,node_list))
501         
502
503         try :
504
505
506             liste =job_info[node_list_k] 
507             print>>sys.stderr, "\r\n \r\n \t\t GetJobs resources  job_info liste%s" %(liste)
508             for k in range(len(liste)):
509                job_info[node_list_k][k] = node_dict[job_info[node_list_k][k]]['hostname']
510             
511             print>>sys.stderr, "\r\n \r\n \t\t YYYYYYYYYYYYGetJobs resources  job_info %s" %(job_info)  
512             #Replaces the previous entry "assigned_network_address" / "reserved_resources"
513             #with "node_ids"
514             job_info.update({'node_ids':job_info[node_list_k]})
515             del job_info[node_list_k]
516             return job_info
517             
518         except KeyError:
519             print>>sys.stderr, "\r\n \r\n \t\t GetJobs KEYERROR " 
520             
521   
522             
523
524        
525      
526     def GetNodes(self,node_filter= None, return_fields=None):
527                 
528         node_dict =self.oar.parser.SendRequest("GET_resources_full")
529         print>>sys.stderr, "\r\n \r\n \t\t  SLABDRIVER.PY GetNodes " 
530         return_node_list = []
531         if not (node_filter or return_fields):
532                 return_node_list = node_dict.values()
533                 return return_node_list
534     
535         return_node_list= parse_filter(node_dict.values(),node_filter ,'node', return_fields)
536         return return_node_list
537     
538   
539     def GetSites(self, site_filter = None, return_fields=None):
540         site_dict =self.oar.parser.SendRequest("GET_sites")
541         print>>sys.stderr, "\r\n \r\n \t\t  SLABDRIVER.PY GetSites " 
542         return_site_list = []
543         if not ( site_filter or return_fields):
544                 return_site_list = site_dict.values()
545                 return return_site_list
546     
547         return_site_list = parse_filter(site_dict.values(), site_filter,'site', return_fields)
548         return return_site_list
549         
550
551     def GetSlices(self,slice_filter = None, filter_type = None, return_fields=None):
552         return_slice_list = []
553         slicerec  = {}
554         rec = {}
555         ftypes = ['slice_hrn', 'record_id_user']
556         if filter_type and filter_type in ftypes:
557             if filter_type == 'slice_hrn':
558                 slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).first()    
559             if filter_type == 'record_id_user':
560                 slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).first()
561                 
562             if slicerec:
563                 rec = slicerec.dumpquerytodict()
564                 login = slicerec.slice_hrn.split(".")[1].split("_")[0]
565                 print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY slicerec GetSlices   %s " %(slicerec)
566                 if slicerec.oar_job_id is not -1:
567                     rslt = self.GetJobs( slicerec.oar_job_id, resources=False, username = login )
568                     print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY  GetSlices  GetJobs  %s " %(rslt)     
569                     if rslt :
570                         rec.update(rslt)
571                         rec.update({'hrn':str(rec['slice_hrn'])})
572                         #If GetJobs is empty, this means the job is now in the 'Terminated' state
573                         #Update the slice record
574                     else :
575                         self.db.update_job(slice_filter, job_id = -1)
576                         rec['oar_job_id'] = -1
577                         rec.update({'hrn':str(rec['slice_hrn'])})
578             
579                 print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY  GetSlices  rec  %s" %(rec)
580                               
581             return rec
582                 
583                 
584         else:
585             return_slice_list = slab_dbsession.query(SliceSenslab).all()
586
587         print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY  GetSlices  slices %s slice_filter %s " %(return_slice_list,slice_filter)
588         
589         #if return_fields:
590             #return_slice_list  = parse_filter(sliceslist, slice_filter,'slice', return_fields)
591         
592         
593                     
594         return return_slice_list
595         
596
597         
598     
599     def testbed_name (self): return "senslab2" 
600          
601     # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
602     def aggregate_version (self):
603         version_manager = VersionManager()
604         ad_rspec_versions = []
605         request_rspec_versions = []
606         for rspec_version in version_manager.versions:
607             if rspec_version.content_type in ['*', 'ad']:
608                 ad_rspec_versions.append(rspec_version.to_dict())
609             if rspec_version.content_type in ['*', 'request']:
610                 request_rspec_versions.append(rspec_version.to_dict()) 
611         return {
612             'testbed':self.testbed_name(),
613             'geni_request_rspec_versions': request_rspec_versions,
614             'geni_ad_rspec_versions': ad_rspec_versions,
615             }
616           
617           
618           
619           
620           
621           
622     ##
623     # Convert SFA fields to PLC fields for use when registering up updating
624     # registry record in the PLC database
625     #
626     # @param type type of record (user, slice, ...)
627     # @param hrn human readable name
628     # @param sfa_fields dictionary of SFA fields
629     # @param slab_fields dictionary of PLC fields (output)
630
631     def sfa_fields_to_slab_fields(self, type, hrn, record):
632
633         def convert_ints(tmpdict, int_fields):
634             for field in int_fields:
635                 if field in tmpdict:
636                     tmpdict[field] = int(tmpdict[field])
637
638         slab_record = {}
639         #for field in record:
640         #    slab_record[field] = record[field]
641  
642         if type == "slice":
643             #instantion used in get_slivers ? 
644             if not "instantiation" in slab_record:
645                 slab_record["instantiation"] = "senslab-instantiated"
646             slab_record["hrn"] = hrn_to_pl_slicename(hrn)
647             print >>sys.stderr, "\r\n \r\n \t SLABDRIVER.PY sfa_fields_to_slab_fields slab_record %s hrn_to_pl_slicename(hrn) hrn %s " %(slab_record['hrn'], hrn)
648             if "url" in record:
649                slab_record["url"] = record["url"]
650             if "description" in record:
651                 slab_record["description"] = record["description"]
652             if "expires" in record:
653                 slab_record["expires"] = int(record["expires"])
654                 
655         #nodes added by OAR only and then imported to SFA
656         #elif type == "node":
657             #if not "hostname" in slab_record:
658                 #if not "hostname" in record:
659                     #raise MissingSfaInfo("hostname")
660                 #slab_record["hostname"] = record["hostname"]
661             #if not "model" in slab_record:
662                 #slab_record["model"] = "geni"
663                 
664         #One authority only 
665         #elif type == "authority":
666             #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
667
668             #if not "name" in slab_record:
669                 #slab_record["name"] = hrn
670
671             #if not "abbreviated_name" in slab_record:
672                 #slab_record["abbreviated_name"] = hrn
673
674             #if not "enabled" in slab_record:
675                 #slab_record["enabled"] = True
676
677             #if not "is_public" in slab_record:
678                 #slab_record["is_public"] = True
679
680         return slab_record
681
682   
683                  
684                  
685     def AddSliceToNodes(self,  slice_name, added_nodes, slice_user=None):
686        
687         site_list = []
688         nodeid_list =[]
689         resource = ""
690         reqdict = {}
691         reqdict['property'] ="network_address in ("
692         for node in added_nodes:
693             #Get the ID of the node : remove the root auth and put the site in a separate list
694             s=node.split(".")
695             # NT: it's not clear for me if the nodenames will have the senslab prefix
696             # so lets take the last part only, for now.
697             lastpart=s[-1]
698             #if s[0] == self.root_auth :
699             # Again here it's not clear if nodes will be prefixed with <site>_, lets split and tanke the last part for now.
700             s=lastpart.split("_")
701             nodeid=s[-1]
702             reqdict['property'] += "'"+ nodeid +"', "
703             nodeid_list.append(nodeid)
704             #site_list.append( l[0] )
705         reqdict['property'] =  reqdict['property'][0: len( reqdict['property'])-2] +")"
706         reqdict['resource'] ="network_address="+ str(len(nodeid_list))
707         reqdict['resource']+= ",walltime=" + str(00) + ":" + str(12) + ":" + str(20) #+2 min 20
708         reqdict['script_path'] = "/bin/sleep 620" #+20 sec
709         reqdict['type'] = "deploy" 
710         reqdict['directory']= ""
711         reqdict['name']= "TestSandrine"
712         # reservations are performed in the oar server timebase, so :
713         # 1- we get the server time(in UTC tz )/server timezone
714         # 2- convert the server UTC time in its timezone
715         # 3- add a custom delay to this time
716         # 4- convert this time to a readable form and it for the reservation request.
717         server_timestamp,server_tz = self.GetTimezone()
718         s_tz=tz.gettz(server_tz)
719         UTC_zone = tz.gettz("UTC")
720         #weird... datetime.fromtimestamp should work since we do from datetime import datetime
721         utc_server= datetime.datetime.fromtimestamp(float(server_timestamp)+20,UTC_zone)
722         server_localtime=utc_server.astimezone(s_tz)
723
724         print>>sys.stderr, "\r\n \r\n AddSliceToNodes  slice_name %s added_nodes %s username %s reqdict %s " %(slice_name,added_nodes,slice_user, reqdict)
725         readable_time = server_localtime.strftime(self.time_format)
726
727         print >>sys.stderr,"  \r\n \r\n \t\t\t\tAPRES ParseTimezone readable_time %s timestanp %s  " %(readable_time ,server_timestamp)
728         reqdict['reservation'] = readable_time
729          
730         # first step : start the OAR job
731         print>>sys.stderr, "\r\n \r\n AddSliceToNodes reqdict   %s \r\n site_list   %s"  %(reqdict,site_list)   
732         #OAR = OARrestapi()
733         answer = self.oar.POSTRequestToOARRestAPI('POST_job',reqdict,slice_user)
734         print>>sys.stderr, "\r\n \r\n AddSliceToNodes jobid   %s "  %(answer)
735         #self.db.update('slice',['oar_job_id'], [answer['id']], 'slice_hrn', slice_name)
736                
737
738         self.db.update_job( slice_name, job_id = answer['id'] )
739         jobid=answer['id']
740         print>>sys.stderr, "\r\n \r\n AddSliceToNodes jobid    %s added_nodes  %s slice_user %s"  %(jobid,added_nodes,slice_user)  
741         # second step : configure the experiment
742         # we need to store the nodes in a yaml (well...) file like this :
743         # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
744         f=open('/tmp/sfa/'+str(jobid)+'.json','w')
745         f.write('[')
746         f.write(str(added_nodes[0].strip('node')))
747         for node in added_nodes[1:len(added_nodes)] :
748             f.write(','+node.strip('node'))
749         f.write(']')
750         f.close()
751         
752         # third step : call the senslab-experiment wrapper
753         #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar "+str(jobid)+" "+slice_user
754         javacmdline="/usr/bin/java"
755         jarname="/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
756         #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", str(jobid), slice_user])
757         output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), slice_user],stdout=subprocess.PIPE).communicate()[0]
758
759         print>>sys.stderr, "\r\n \r\n AddSliceToNodes wrapper returns   %s "  %(output)
760         return 
761     
762
763         
764         
765     def DeleteSliceFromNodes(self, slice_name, deleted_nodes):
766         return   
767     
768  
769
770     def fill_record_sfa_info(self, records):
771
772         def startswith(prefix, values):
773             return [value for value in values if value.startswith(prefix)]
774
775         # get person ids
776         person_ids = []
777         site_ids = []
778         for record in records:
779             person_ids.extend(record.get("person_ids", []))
780             site_ids.extend(record.get("site_ids", [])) 
781             if 'site_id' in record:
782                 site_ids.append(record['site_id']) 
783                 
784         #print>>sys.stderr, "\r\n \r\n _fill_record_sfa_info ___person_ids %s \r\n \t\t site_ids %s " %(person_ids, site_ids)
785         
786         # get all pis from the sites we've encountered
787         # and store them in a dictionary keyed on site_id 
788         site_pis = {}
789         if site_ids:
790             pi_filter = {'|roles': ['pi'], '|site_ids': site_ids} 
791             pi_list = self.GetPersons( pi_filter, ['person_id', 'site_ids'])
792             #print>>sys.stderr, "\r\n \r\n _fill_record_sfa_info ___ GetPersons ['person_id', 'site_ids'] pi_ilist %s" %(pi_list)
793
794             for pi in pi_list:
795                 # we will need the pi's hrns also
796                 person_ids.append(pi['person_id'])
797                 
798                 # we also need to keep track of the sites these pis
799                 # belong to
800                 for site_id in pi['site_ids']:
801                     if site_id in site_pis:
802                         site_pis[site_id].append(pi)
803                     else:
804                         site_pis[site_id] = [pi]
805                  
806         # get sfa records for all records associated with these records.   
807         # we'll replace pl ids (person_ids) with hrns from the sfa records
808         # we obtain
809         
810         # get the sfa records
811         #table = SfaTable()
812         existing_records = {}
813         all_records = dbsession.query(RegRecord).all()
814         for record in all_records:
815             existing_records[(record.type,record.pointer)] = record
816             
817         print >>sys.stderr, " \r\r\n SLABDRIVER fill_record_sfa_info existing_records %s "  %(existing_records)
818         person_list, persons = [], {}
819         #person_list = table.find({'type': 'user', 'pointer': person_ids})
820         try:
821             for p_id in person_ids:
822                 person_list.append( existing_records.get(('user',p_id)))
823         except KeyError:
824             print >>sys.stderr, " \r\r\n SLABDRIVER fill_record_sfa_info ERRRRRRRRRROR"
825                  
826         # create a hrns keyed on the sfa record's pointer.
827         # Its possible for  multiple records to have the same pointer so
828         # the dict's value will be a list of hrns.
829         persons = defaultdict(list)
830         for person in person_list:
831             persons[person['pointer']].append(person)
832
833         # get the pl records
834         slab_person_list, slab_persons = [], {}
835         slab_person_list = self.GetPersons(person_ids, ['person_id', 'roles'])
836         slab_persons = list_to_dict(slab_person_list, 'person_id')
837         #print>>sys.stderr, "\r\n \r\n _fill_record_sfa_info ___  _list %s \r\n \t\t SenslabUsers.GetPersons ['person_id', 'roles'] slab_persons %s \r\n records %s" %(slab_person_list, slab_persons,records) 
838         # fill sfa info
839         
840         for record in records:
841             # skip records with no pl info (top level authorities)
842             #Sandrine 24 oct 11 2 lines
843             #if record['pointer'] == -1:
844                 #continue 
845             sfa_info = {}
846             type = record['type']
847             if (type == "slice"):
848                 # all slice users are researchers
849                 #record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')  ? besoin ou pas ?
850                 record['PI'] = []
851                 record['researcher'] = []
852                 for person_id in record.get('person_ids', []):
853                          #Sandrine 24 oct 11 line
854                 #for person_id in record['person_ids']:
855                     hrns = [person['hrn'] for person in persons[person_id]]
856                     record['researcher'].extend(hrns)                
857
858                 # pis at the slice's site
859                 slab_pis = site_pis[record['site_id']]
860                 pi_ids = [pi['person_id'] for pi in slab_pis]
861                 for person_id in pi_ids:
862                     hrns = [person['hrn'] for person in persons[person_id]]
863                     record['PI'].extend(hrns)
864                 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
865                 record['geni_creator'] = record['PI'] 
866                 
867             elif (type == "authority"):
868                 record['PI'] = []
869                 record['operator'] = []
870                 record['owner'] = []
871                 for pointer in record['person_ids']:
872                     if pointer not in persons or pointer not in slab_persons:
873                         # this means there is not sfa or pl record for this user
874                         continue   
875                     hrns = [person['hrn'] for person in persons[pointer]] 
876                     roles = slab_persons[pointer]['roles']   
877                     if 'pi' in roles:
878                         record['PI'].extend(hrns)
879                     if 'tech' in roles:
880                         record['operator'].extend(hrns)
881                     if 'admin' in roles:
882                         record['owner'].extend(hrns)
883                     # xxx TODO: OrganizationName
884             elif (type == "node"):
885                 sfa_info['dns'] = record.get("hostname", "")
886                 # xxx TODO: URI, LatLong, IP, DNS
887     
888             elif (type == "user"):
889                  sfa_info['email'] = record.get("email", "")
890                  sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
891                  sfa_info['geni_certificate'] = record['gid'] 
892                 # xxx TODO: PostalAddress, Phone
893                 
894             #print>>sys.stderr, "\r\n \r\rn \t\t \t <<<<<<<<<<<<<<<<<<<<<<<<  fill_record_sfa_info sfa_info %s  \r\n record %s : "%(sfa_info,record)  
895             record.update(sfa_info)
896             
897     def augment_records_with_testbed_info (self, sfa_records):
898         return self.fill_record_info (sfa_records)
899     
900     def fill_record_info(self, records):
901         """
902         Given a SFA record, fill in the senslab specific and SFA specific
903         fields in the record. 
904         """
905                     
906         print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info 000000000 fill_record_info %s  " %(records)
907         if not isinstance(records, list):
908             records = [records]
909
910         parkour = records 
911         try:
912             for record in parkour:
913                     
914                 if str(record['type']) == 'slice':
915                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY  fill_record_info \t \t record %s" %(record)
916                     #sfatable = SfaTable()
917                     
918                     #existing_records_by_id = {}
919                     #all_records = dbsession.query(RegRecord).all()
920                     #for rec in all_records:
921                         #existing_records_by_id[rec.record_id] = rec
922                     #print >>sys.stderr, "\r\n \t\t SLABDRIVER.PY  fill_record_info \t\t existing_records_by_id %s" %(existing_records_by_id[record['record_id']])
923                         
924                     #recslice = self.db.find('slice',{'slice_hrn':str(record['hrn'])}) 
925                     #recslice = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = str(record['hrn'])).first()
926                     recslice = self.GetSlices(slice_filter =  str(record['hrn']), filter_type = 'slice_hrn')
927                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info \t\t HOY HOY reclise %s" %(recslice)
928                     #if isinstance(recslice,list) and len(recslice) == 1:
929                         #recslice = recslice[0]
930                    
931                     recuser = dbsession.query(RegRecord).filter_by(record_id = recslice['record_id_user']).first()
932                     #existing_records_by_id[recslice['record_id_user']]
933                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info \t\t recuser %s" %(recuser)
934                     
935           
936                     record.update({'PI':[recuser.hrn],
937                     'researcher': [recuser.hrn],
938                     'name':record['hrn'], 
939                     'oar_job_id':recslice['oar_job_id'],
940                     'node_ids': [],
941                     'person_ids':[recslice['record_id_user']]})
942                     
943                 elif str(record['type']) == 'user':
944                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info USEEEEEEEEEERDESU!" 
945
946                     rec = self.GetSlices(slice_filter = record['record_id'], filter_type = 'record_id_user')
947                     #Append record in records list, therfore fetches user and slice info again(one more loop)
948                     #Will update PIs and researcher for the slice
949
950                     rec.update({'type':'slice','hrn':rec['slice_hrn']})
951                     records.append(rec)
952                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info ADDING SLIC EINFO rec %s" %(rec) 
953                     
954             print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info OKrecords %s" %(records) 
955         except TypeError:
956             print >>sys.stderr, "\r\n \t\t SLABDRIVER fill_record_info  EXCEPTION RECORDS : %s" %(records)      
957             return
958         
959         #self.fill_record_slab_info(records)
960         ##print >>sys.stderr, "\r\n \t\t after fill_record_slab_info %s" %(records)     
961         #self.fill_record_sfa_info(records)
962         #print >>sys.stderr, "\r\n \t\t after fill_record_sfa_info"
963         
964         
965
966     
967         
968     #def update_membership_list(self, oldRecord, record, listName, addFunc, delFunc):
969         ## get a list of the HRNs tht are members of the old and new records
970         #if oldRecord:
971             #oldList = oldRecord.get(listName, [])
972         #else:
973             #oldList = []     
974         #newList = record.get(listName, [])
975
976         ## if the lists are the same, then we don't have to update anything
977         #if (oldList == newList):
978             #return
979
980         ## build a list of the new person ids, by looking up each person to get
981         ## their pointer
982         #newIdList = []
983         #table = SfaTable()
984         #records = table.find({'type': 'user', 'hrn': newList})
985         #for rec in records:
986             #newIdList.append(rec['pointer'])
987
988         ## build a list of the old person ids from the person_ids field 
989         #if oldRecord:
990             #oldIdList = oldRecord.get("person_ids", [])
991             #containerId = oldRecord.get_pointer()
992         #else:
993             ## if oldRecord==None, then we are doing a Register, instead of an
994             ## update.
995             #oldIdList = []
996             #containerId = record.get_pointer()
997
998     ## add people who are in the new list, but not the oldList
999         #for personId in newIdList:
1000             #if not (personId in oldIdList):
1001                 #addFunc(self.plauth, personId, containerId)
1002
1003         ## remove people who are in the old list, but not the new list
1004         #for personId in oldIdList:
1005             #if not (personId in newIdList):
1006                 #delFunc(self.plauth, personId, containerId)
1007
1008     #def update_membership(self, oldRecord, record):
1009         #print >>sys.stderr, " \r\n \r\n ***SLABDRIVER.PY update_membership record ", record
1010         #if record.type == "slice":
1011             #self.update_membership_list(oldRecord, record, 'researcher',
1012                                         #self.users.AddPersonToSlice,
1013                                         #self.users.DeletePersonFromSlice)
1014         #elif record.type == "authority":
1015             ## xxx TODO
1016             #pass
1017
1018 ### thierry
1019 # I don't think you plan on running a component manager at this point
1020 # let me clean up the mess of ComponentAPI that is deprecated anyways