New method GetReservedNodes that returns a list of nodes already involved in an oar...
[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         if job_id and resources is False:
473             req = "GET_jobs_id"
474             node_list_k = 'assigned_network_address'
475            
476         if job_id and resources :
477             req = "GET_jobs_id_resources"
478             node_list_k = 'reserved_resources' 
479                
480         #Get job info from OAR    
481         job_info = self.oar.parser.SendRequest(req, job_id, username)
482         print>>sys.stderr, "\r\n \r\n \t\t GetJobs  %s " %(job_info)
483         
484         if 'state' in job_info :
485             if job_info['state'] == 'Terminated':
486                 print>>sys.stderr, "\r\n \r\n \t\t GetJobs TERMINELEBOUSIN "
487                 return None
488             if job_info['state'] == 'Error':
489                 print>>sys.stderr, "\r\n \r\n \t\t GetJobs ERROR message %s " %(job_info)
490                 return None
491         
492         #Get a dict of nodes . Key :hostname of the node
493         node_list = self.GetNodes() 
494         node_hostname_list = []
495         for node in node_list:
496             node_hostname_list.append(node['hostname'])
497         node_dict = dict(zip(node_hostname_list,node_list))
498         try :
499             liste =job_info[node_list_k] 
500             print>>sys.stderr, "\r\n \r\n \t\t GetJobs resources  job_info liste%s" %(liste)
501             for k in range(len(liste)):
502                job_info[node_list_k][k] = node_dict[job_info[node_list_k][k]]['hostname']
503             
504             print>>sys.stderr, "\r\n \r\n \t\t YYYYYYYYYYYYGetJobs resources  job_info %s" %(job_info)  
505             #Replaces the previous entry "assigned_network_address" / "reserved_resources"
506             #with "node_ids"
507             job_info.update({'node_ids':job_info[node_list_k]})
508             del job_info[node_list_k]
509             return job_info
510             
511         except KeyError:
512             print>>sys.stderr, "\r\n \r\n \t\t GetJobs KEYERROR " 
513             
514     def GetReservedNodes(self):
515         # this function returns a list of all the nodes already involved in an oar job
516
517        jobs=self.oar.parser.SendRequest("GET_jobs_details") 
518        nodes=[]
519        for j in jobs :
520           nodes=j['assigned_network_address']+nodes
521        return nodes
522      
523     def GetNodes(self,node_filter= None, return_fields=None):
524                 
525         node_dict =self.oar.parser.SendRequest("GET_resources_full")
526         print>>sys.stderr, "\r\n \r\n \t\t  SLABDRIVER.PY GetNodes " 
527         return_node_list = []
528         if not (node_filter or return_fields):
529                 return_node_list = node_dict.values()
530                 return return_node_list
531     
532         return_node_list= parse_filter(node_dict.values(),node_filter ,'node', return_fields)
533         return return_node_list
534     
535   
536     def GetSites(self, site_filter = None, return_fields=None):
537         site_dict =self.oar.parser.SendRequest("GET_sites")
538         print>>sys.stderr, "\r\n \r\n \t\t  SLABDRIVER.PY GetSites " 
539         return_site_list = []
540         if not ( site_filter or return_fields):
541                 return_site_list = site_dict.values()
542                 return return_site_list
543     
544         return_site_list = parse_filter(site_dict.values(), site_filter,'site', return_fields)
545         return return_site_list
546         
547
548     def GetSlices(self,slice_filter = None, filter_type = None, return_fields=None):
549         return_slice_list = []
550         slicerec  = {}
551         rec = {}
552         ftypes = ['slice_hrn', 'record_id_user']
553         if filter_type and filter_type in ftypes:
554             if filter_type == 'slice_hrn':
555                 slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).first()    
556             if filter_type == 'record_id_user':
557                 slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).first()
558                 
559             if slicerec:
560                 rec = slicerec.dumpquerytodict()
561                 login = slicerec.slice_hrn.split(".")[1].split("_")[0]
562                 print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY slicerec GetSlices   %s " %(slicerec)
563                 if slicerec.oar_job_id is not -1:
564                     rslt = self.GetJobs( slicerec.oar_job_id, resources=False, username = login )
565                     print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY  GetSlices  GetJobs  %s " %(rslt)     
566                     if rslt :
567                         rec.update(rslt)
568                         rec.update({'hrn':str(rec['slice_hrn'])})
569                         #If GetJobs is empty, this means the job is now in the 'Terminated' state
570                         #Update the slice record
571                     else :
572                         self.db.update_job(slice_filter, job_id = -1)
573                         rec['oar_job_id'] = -1
574                         rec.update({'hrn':str(rec['slice_hrn'])})
575             
576                 print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY  GetSlices  rec  %s" %(rec)
577                               
578             return rec
579                 
580                 
581         else:
582             return_slice_list = slab_dbsession.query(SliceSenslab).all()
583
584         print >>sys.stderr, " \r\n \r\n \tSLABDRIVER.PY  GetSlices  slices %s slice_filter %s " %(return_slice_list,slice_filter)
585         
586         #if return_fields:
587             #return_slice_list  = parse_filter(sliceslist, slice_filter,'slice', return_fields)
588         
589         
590                     
591         return return_slice_list
592         
593
594         
595     
596     def testbed_name (self): return "senslab2" 
597          
598     # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
599     def aggregate_version (self):
600         version_manager = VersionManager()
601         ad_rspec_versions = []
602         request_rspec_versions = []
603         for rspec_version in version_manager.versions:
604             if rspec_version.content_type in ['*', 'ad']:
605                 ad_rspec_versions.append(rspec_version.to_dict())
606             if rspec_version.content_type in ['*', 'request']:
607                 request_rspec_versions.append(rspec_version.to_dict()) 
608         return {
609             'testbed':self.testbed_name(),
610             'geni_request_rspec_versions': request_rspec_versions,
611             'geni_ad_rspec_versions': ad_rspec_versions,
612             }
613           
614           
615           
616           
617           
618           
619     ##
620     # Convert SFA fields to PLC fields for use when registering up updating
621     # registry record in the PLC database
622     #
623     # @param type type of record (user, slice, ...)
624     # @param hrn human readable name
625     # @param sfa_fields dictionary of SFA fields
626     # @param slab_fields dictionary of PLC fields (output)
627
628     def sfa_fields_to_slab_fields(self, type, hrn, record):
629
630         def convert_ints(tmpdict, int_fields):
631             for field in int_fields:
632                 if field in tmpdict:
633                     tmpdict[field] = int(tmpdict[field])
634
635         slab_record = {}
636         #for field in record:
637         #    slab_record[field] = record[field]
638  
639         if type == "slice":
640             #instantion used in get_slivers ? 
641             if not "instantiation" in slab_record:
642                 slab_record["instantiation"] = "senslab-instantiated"
643             slab_record["hrn"] = hrn_to_pl_slicename(hrn)
644             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)
645             if "url" in record:
646                slab_record["url"] = record["url"]
647             if "description" in record:
648                 slab_record["description"] = record["description"]
649             if "expires" in record:
650                 slab_record["expires"] = int(record["expires"])
651                 
652         #nodes added by OAR only and then imported to SFA
653         #elif type == "node":
654             #if not "hostname" in slab_record:
655                 #if not "hostname" in record:
656                     #raise MissingSfaInfo("hostname")
657                 #slab_record["hostname"] = record["hostname"]
658             #if not "model" in slab_record:
659                 #slab_record["model"] = "geni"
660                 
661         #One authority only 
662         #elif type == "authority":
663             #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
664
665             #if not "name" in slab_record:
666                 #slab_record["name"] = hrn
667
668             #if not "abbreviated_name" in slab_record:
669                 #slab_record["abbreviated_name"] = hrn
670
671             #if not "enabled" in slab_record:
672                 #slab_record["enabled"] = True
673
674             #if not "is_public" in slab_record:
675                 #slab_record["is_public"] = True
676
677         return slab_record
678
679   
680                  
681                  
682     def AddSliceToNodes(self,  slice_name, added_nodes, slice_user=None):
683        
684         site_list = []
685         nodeid_list =[]
686         resource = ""
687         reqdict = {}
688         reqdict['property'] ="network_address in ("
689         for node in added_nodes:
690             #Get the ID of the node : remove the root auth and put the site in a separate list
691             s=node.split(".")
692             # NT: it's not clear for me if the nodenames will have the senslab prefix
693             # so lets take the last part only, for now.
694             lastpart=s[-1]
695             #if s[0] == self.root_auth :
696             # Again here it's not clear if nodes will be prefixed with <site>_, lets split and tanke the last part for now.
697             s=lastpart.split("_")
698             nodeid=s[-1]
699             reqdict['property'] += "'"+ nodeid +"', "
700             nodeid_list.append(nodeid)
701             #site_list.append( l[0] )
702         reqdict['property'] =  reqdict['property'][0: len( reqdict['property'])-2] +")"
703         reqdict['resource'] ="network_address="+ str(len(nodeid_list))
704         reqdict['resource']+= ",walltime=" + str(00) + ":" + str(12) + ":" + str(20) #+2 min 20
705         reqdict['script_path'] = "/bin/sleep 620" #+20 sec
706         reqdict['type'] = "deploy" 
707         reqdict['directory']= ""
708         reqdict['name']= "TestSandrine"
709         # reservations are performed in the oar server timebase, so :
710         # 1- we get the server time(in UTC tz )/server timezone
711         # 2- convert the server UTC time in its timezone
712         # 3- add a custom delay to this time
713         # 4- convert this time to a readable form and it for the reservation request.
714         server_timestamp,server_tz = self.GetTimezone()
715         s_tz=tz.gettz(server_tz)
716         UTC_zone = tz.gettz("UTC")
717         #weird... datetime.fromtimestamp should work since we do from datetime import datetime
718         utc_server= datetime.datetime.fromtimestamp(float(server_timestamp)+20,UTC_zone)
719         server_localtime=utc_server.astimezone(s_tz)
720
721         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)
722         readable_time = server_localtime.strftime(self.time_format)
723
724         print >>sys.stderr,"  \r\n \r\n \t\t\t\tAPRES ParseTimezone readable_time %s timestanp %s  " %(readable_time ,server_timestamp)
725         reqdict['reservation'] = readable_time
726          
727         # first step : start the OAR job
728         print>>sys.stderr, "\r\n \r\n AddSliceToNodes reqdict   %s \r\n site_list   %s"  %(reqdict,site_list)   
729         #OAR = OARrestapi()
730         answer = self.oar.POSTRequestToOARRestAPI('POST_job',reqdict,slice_user)
731         print>>sys.stderr, "\r\n \r\n AddSliceToNodes jobid   %s "  %(answer)
732         #self.db.update('slice',['oar_job_id'], [answer['id']], 'slice_hrn', slice_name)
733                
734
735         self.db.update_job( slice_name, job_id = answer['id'] )
736         jobid=answer['id']
737         print>>sys.stderr, "\r\n \r\n AddSliceToNodes jobid    %s added_nodes  %s slice_user %s"  %(jobid,added_nodes,slice_user)  
738         # second step : configure the experiment
739         # we need to store the nodes in a yaml (well...) file like this :
740         # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
741         f=open('/tmp/sfa/'+str(jobid)+'.json','w')
742         f.write('[')
743         f.write(str(added_nodes[0].strip('node')))
744         for node in added_nodes[1:len(added_nodes)] :
745             f.write(','+node.strip('node'))
746         f.write(']')
747         f.close()
748         
749         # third step : call the senslab-experiment wrapper
750         #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar "+str(jobid)+" "+slice_user
751         javacmdline="/usr/bin/java"
752         jarname="/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
753         #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", str(jobid), slice_user])
754         output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), slice_user],stdout=subprocess.PIPE).communicate()[0]
755
756         print>>sys.stderr, "\r\n \r\n AddSliceToNodes wrapper returns   %s "  %(output)
757         return 
758     
759
760         
761         
762     def DeleteSliceFromNodes(self, slice_name, deleted_nodes):
763         return   
764     
765  
766
767     def fill_record_sfa_info(self, records):
768
769         def startswith(prefix, values):
770             return [value for value in values if value.startswith(prefix)]
771
772         # get person ids
773         person_ids = []
774         site_ids = []
775         for record in records:
776             person_ids.extend(record.get("person_ids", []))
777             site_ids.extend(record.get("site_ids", [])) 
778             if 'site_id' in record:
779                 site_ids.append(record['site_id']) 
780                 
781         #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)
782         
783         # get all pis from the sites we've encountered
784         # and store them in a dictionary keyed on site_id 
785         site_pis = {}
786         if site_ids:
787             pi_filter = {'|roles': ['pi'], '|site_ids': site_ids} 
788             pi_list = self.GetPersons( pi_filter, ['person_id', 'site_ids'])
789             #print>>sys.stderr, "\r\n \r\n _fill_record_sfa_info ___ GetPersons ['person_id', 'site_ids'] pi_ilist %s" %(pi_list)
790
791             for pi in pi_list:
792                 # we will need the pi's hrns also
793                 person_ids.append(pi['person_id'])
794                 
795                 # we also need to keep track of the sites these pis
796                 # belong to
797                 for site_id in pi['site_ids']:
798                     if site_id in site_pis:
799                         site_pis[site_id].append(pi)
800                     else:
801                         site_pis[site_id] = [pi]
802                  
803         # get sfa records for all records associated with these records.   
804         # we'll replace pl ids (person_ids) with hrns from the sfa records
805         # we obtain
806         
807         # get the sfa records
808         #table = SfaTable()
809         existing_records = {}
810         all_records = dbsession.query(RegRecord).all()
811         for record in all_records:
812             existing_records[(record.type,record.pointer)] = record
813             
814         print >>sys.stderr, " \r\r\n SLABDRIVER fill_record_sfa_info existing_records %s "  %(existing_records)
815         person_list, persons = [], {}
816         #person_list = table.find({'type': 'user', 'pointer': person_ids})
817         try:
818             for p_id in person_ids:
819                 person_list.append( existing_records.get(('user',p_id)))
820         except KeyError:
821             print >>sys.stderr, " \r\r\n SLABDRIVER fill_record_sfa_info ERRRRRRRRRROR"
822                  
823         # create a hrns keyed on the sfa record's pointer.
824         # Its possible for  multiple records to have the same pointer so
825         # the dict's value will be a list of hrns.
826         persons = defaultdict(list)
827         for person in person_list:
828             persons[person['pointer']].append(person)
829
830         # get the pl records
831         slab_person_list, slab_persons = [], {}
832         slab_person_list = self.GetPersons(person_ids, ['person_id', 'roles'])
833         slab_persons = list_to_dict(slab_person_list, 'person_id')
834         #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) 
835         # fill sfa info
836         
837         for record in records:
838             # skip records with no pl info (top level authorities)
839             #Sandrine 24 oct 11 2 lines
840             #if record['pointer'] == -1:
841                 #continue 
842             sfa_info = {}
843             type = record['type']
844             if (type == "slice"):
845                 # all slice users are researchers
846                 #record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')  ? besoin ou pas ?
847                 record['PI'] = []
848                 record['researcher'] = []
849                 for person_id in record.get('person_ids', []):
850                          #Sandrine 24 oct 11 line
851                 #for person_id in record['person_ids']:
852                     hrns = [person['hrn'] for person in persons[person_id]]
853                     record['researcher'].extend(hrns)                
854
855                 # pis at the slice's site
856                 slab_pis = site_pis[record['site_id']]
857                 pi_ids = [pi['person_id'] for pi in slab_pis]
858                 for person_id in pi_ids:
859                     hrns = [person['hrn'] for person in persons[person_id]]
860                     record['PI'].extend(hrns)
861                 record['geni_urn'] = hrn_to_urn(record['hrn'], 'slice')
862                 record['geni_creator'] = record['PI'] 
863                 
864             elif (type == "authority"):
865                 record['PI'] = []
866                 record['operator'] = []
867                 record['owner'] = []
868                 for pointer in record['person_ids']:
869                     if pointer not in persons or pointer not in slab_persons:
870                         # this means there is not sfa or pl record for this user
871                         continue   
872                     hrns = [person['hrn'] for person in persons[pointer]] 
873                     roles = slab_persons[pointer]['roles']   
874                     if 'pi' in roles:
875                         record['PI'].extend(hrns)
876                     if 'tech' in roles:
877                         record['operator'].extend(hrns)
878                     if 'admin' in roles:
879                         record['owner'].extend(hrns)
880                     # xxx TODO: OrganizationName
881             elif (type == "node"):
882                 sfa_info['dns'] = record.get("hostname", "")
883                 # xxx TODO: URI, LatLong, IP, DNS
884     
885             elif (type == "user"):
886                  sfa_info['email'] = record.get("email", "")
887                  sfa_info['geni_urn'] = hrn_to_urn(record['hrn'], 'user')
888                  sfa_info['geni_certificate'] = record['gid'] 
889                 # xxx TODO: PostalAddress, Phone
890                 
891             #print>>sys.stderr, "\r\n \r\rn \t\t \t <<<<<<<<<<<<<<<<<<<<<<<<  fill_record_sfa_info sfa_info %s  \r\n record %s : "%(sfa_info,record)  
892             record.update(sfa_info)
893             
894     def augment_records_with_testbed_info (self, sfa_records):
895         return self.fill_record_info (sfa_records)
896     
897     def fill_record_info(self, records):
898         """
899         Given a SFA record, fill in the senslab specific and SFA specific
900         fields in the record. 
901         """
902                     
903         print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info 000000000 fill_record_info %s  " %(records)
904         if not isinstance(records, list):
905             records = [records]
906
907         parkour = records 
908         try:
909             for record in parkour:
910                     
911                 if str(record['type']) == 'slice':
912                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY  fill_record_info \t \t record %s" %(record)
913                     #sfatable = SfaTable()
914                     
915                     #existing_records_by_id = {}
916                     #all_records = dbsession.query(RegRecord).all()
917                     #for rec in all_records:
918                         #existing_records_by_id[rec.record_id] = rec
919                     #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']])
920                         
921                     #recslice = self.db.find('slice',{'slice_hrn':str(record['hrn'])}) 
922                     #recslice = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = str(record['hrn'])).first()
923                     recslice = self.GetSlices(slice_filter =  str(record['hrn']), filter_type = 'slice_hrn')
924                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info \t\t HOY HOY reclise %s" %(recslice)
925                     #if isinstance(recslice,list) and len(recslice) == 1:
926                         #recslice = recslice[0]
927                    
928                     recuser = dbsession.query(RegRecord).filter_by(record_id = recslice['record_id_user']).first()
929                     #existing_records_by_id[recslice['record_id_user']]
930                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info \t\t recuser %s" %(recuser)
931                     
932           
933                     record.update({'PI':[recuser.hrn],
934                     'researcher': [recuser.hrn],
935                     'name':record['hrn'], 
936                     'oar_job_id':recslice['oar_job_id'],
937                     'node_ids': [],
938                     'person_ids':[recslice['record_id_user']]})
939                     
940                 elif str(record['type']) == 'user':
941                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info USEEEEEEEEEERDESU!" 
942
943                     rec = self.GetSlices(slice_filter = record['record_id'], filter_type = 'record_id_user')
944                     #Append record in records list, therfore fetches user and slice info again(one more loop)
945                     #Will update PIs and researcher for the slice
946
947                     rec.update({'type':'slice','hrn':rec['slice_hrn']})
948                     records.append(rec)
949                     print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info ADDING SLIC EINFO rec %s" %(rec) 
950                     
951             print >>sys.stderr, "\r\n \t\t  SLABDRIVER.PY fill_record_info OKrecords %s" %(records) 
952         except TypeError:
953             print >>sys.stderr, "\r\n \t\t SLABDRIVER fill_record_info  EXCEPTION RECORDS : %s" %(records)      
954             return
955         
956         #self.fill_record_slab_info(records)
957         ##print >>sys.stderr, "\r\n \t\t after fill_record_slab_info %s" %(records)     
958         #self.fill_record_sfa_info(records)
959         #print >>sys.stderr, "\r\n \t\t after fill_record_sfa_info"
960         
961         
962
963     
964         
965     #def update_membership_list(self, oldRecord, record, listName, addFunc, delFunc):
966         ## get a list of the HRNs tht are members of the old and new records
967         #if oldRecord:
968             #oldList = oldRecord.get(listName, [])
969         #else:
970             #oldList = []     
971         #newList = record.get(listName, [])
972
973         ## if the lists are the same, then we don't have to update anything
974         #if (oldList == newList):
975             #return
976
977         ## build a list of the new person ids, by looking up each person to get
978         ## their pointer
979         #newIdList = []
980         #table = SfaTable()
981         #records = table.find({'type': 'user', 'hrn': newList})
982         #for rec in records:
983             #newIdList.append(rec['pointer'])
984
985         ## build a list of the old person ids from the person_ids field 
986         #if oldRecord:
987             #oldIdList = oldRecord.get("person_ids", [])
988             #containerId = oldRecord.get_pointer()
989         #else:
990             ## if oldRecord==None, then we are doing a Register, instead of an
991             ## update.
992             #oldIdList = []
993             #containerId = record.get_pointer()
994
995     ## add people who are in the new list, but not the oldList
996         #for personId in newIdList:
997             #if not (personId in oldIdList):
998                 #addFunc(self.plauth, personId, containerId)
999
1000         ## remove people who are in the old list, but not the new list
1001         #for personId in oldIdList:
1002             #if not (personId in newIdList):
1003                 #delFunc(self.plauth, personId, containerId)
1004
1005     #def update_membership(self, oldRecord, record):
1006         #print >>sys.stderr, " \r\n \r\n ***SLABDRIVER.PY update_membership record ", record
1007         #if record.type == "slice":
1008             #self.update_membership_list(oldRecord, record, 'researcher',
1009                                         #self.users.AddPersonToSlice,
1010                                         #self.users.DeletePersonFromSlice)
1011         #elif record.type == "authority":
1012             ## xxx TODO
1013             #pass
1014
1015 ### thierry
1016 # I don't think you plan on running a component manager at this point
1017 # let me clean up the mess of ComponentAPI that is deprecated anyways