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