3 from datetime import datetime
4 from dateutil import tz
5 from time import strftime, gmtime
7 from sfa.util.faults import SliverDoesNotExist, UnknownSfaType
8 from sfa.util.sfalogging import logger
10 from sfa.storage.alchemy import dbsession
11 from sfa.storage.model import RegRecord, RegUser, RegSlice
13 from sfa.trust.credential import Credential
16 from sfa.managers.driver import Driver
17 from sfa.rspecs.version_manager import VersionManager
18 from sfa.rspecs.rspec import RSpec
20 from sfa.util.xrn import hrn_to_urn, urn_to_sliver_id, get_leaf
23 ## thierry: everything that is API-related (i.e. handling incoming requests)
25 # SlabDriver should be really only about talking to the senslab testbed
28 from sfa.senslab.OARrestapi import OARrestapi
29 from sfa.senslab.LDAPapi import LDAPapi
31 from sfa.senslab.slabpostgres import SlabDB, slab_dbsession, SliceSenslab, JobSenslab
32 from sfa.senslab.slabaggregate import SlabAggregate, slab_xrn_to_hostname, slab_xrn_object
33 from sfa.senslab.slabslices import SlabSlices
40 # this inheritance scheme is so that the driver object can receive
41 # GetNodes or GetSites sorts of calls directly
42 # and thus minimize the differences in the managers with the pl version
43 class SlabDriver(Driver):
45 def __init__(self, config):
46 Driver.__init__ (self, config)
48 self.hrn = config.SFA_INTERFACE_HRN
50 self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
52 self.oar = OARrestapi()
54 self.time_format = "%Y-%m-%d %H:%M:%S"
55 self.db = SlabDB(config,debug = True)
59 def sliver_status(self, slice_urn, slice_hrn):
60 """Receive a status request for slice named urn/hrn
61 urn:publicid:IDN+senslab+nturro_slice hrn senslab.nturro_slice
62 shall return a structure as described in
63 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
64 NT : not sure if we should implement this or not, but used by sface.
68 #First get the slice with the slice hrn
69 sl = self.GetSlices(slice_filter = slice_hrn, \
70 slice_filter_type = 'slice_hrn')
73 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
75 if isinstance(sl,list):
79 top_level_status = 'unknown'
80 nodes_in_slice = sl['node_ids']
81 recuser = dbsession.query(RegRecord).filter_by(record_id = \
82 sl['record_id_user']).first()
83 sl.update({'user':recuser.hrn})
84 if len(nodes_in_slice) is 0:
85 raise SliverDoesNotExist("No slivers allocated ")
87 top_level_status = 'ready'
89 logger.debug("Slabdriver - sliver_status Sliver status urn %s hrn %s sl\
90 %s \r\n " %(slice_urn, slice_hrn, sl))
92 if sl['oar_job_id'] is not []:
93 #A job is running on Senslab for this slice
94 # report about the local nodes that are in the slice only
96 nodes_all = self.GetNodes({'hostname':nodes_in_slice},
97 ['node_id', 'hostname','site','boot_state'])
98 nodeall_byhostname = dict([(n['hostname'], n) for n in nodes_all])
102 result['geni_urn'] = slice_urn
103 result['pl_login'] = sl['user'] #For compatibility
106 #timestamp = float(sl['startTime']) + float(sl['walltime'])
107 #result['pl_expires'] = strftime(self.time_format, \
108 #gmtime(float(timestamp)))
109 #result['slab_expires'] = strftime(self.time_format,\
110 #gmtime(float(timestamp)))
113 for node in nodeall_byhostname:
115 #res['slab_hostname'] = node['hostname']
116 #res['slab_boot_state'] = node['boot_state']
118 res['pl_hostname'] = nodeall_byhostname[node]['hostname']
119 res['pl_boot_state'] = nodeall_byhostname[node]['boot_state']
120 #res['pl_last_contact'] = strftime(self.time_format, \
121 #gmtime(float(timestamp)))
122 sliver_id = urn_to_sliver_id(slice_urn, sl['record_id_slice'], \
123 nodeall_byhostname[node]['node_id'])
124 res['geni_urn'] = sliver_id
125 if nodeall_byhostname[node]['boot_state'] == 'Alive':
127 res['geni_status'] = 'ready'
129 res['geni_status'] = 'failed'
130 top_level_status = 'failed'
132 res['geni_error'] = ''
134 resources.append(res)
136 result['geni_status'] = top_level_status
137 result['geni_resources'] = resources
138 logger.debug("SLABDRIVER \tsliver_statusresources %s res %s "\
143 def synchronize_oar_and_slice_table(self, slice_hrn = None):
145 oar_leases_list = self.GetReservedNodes()
147 logger.debug("SLABDRIVER \tsynchronize_oar_and_slice_table \r\n \r\n : oar_leases_list %s\r\n" %( oar_leases_list))
148 #Get list of slices/leases . multiple entry per user depending on number of jobs
149 #At this point we don't have the slice_hrn so that's why
150 #we are calling Getslices, which holds a field with slice_hrn
153 sfa_slices_list = self.GetSlices(slice_filter = slice_hrn, slice_filter_type = 'slice_hrn')
154 self.synchronize_oar_and_slice_table_for_slice_hrn(slice_hrn, oar_leases_list, sfa_slices_list)
156 sfa_slices_list = self.GetSlices()
158 sfa_slices_dict_by_slice_hrn = {}
159 for sfa_slice in sfa_slices_list:
160 if sfa_slice['slice_hrn'] not in sfa_slices_dict_by_slice_hrn:
161 sfa_slices_dict_by_slice_hrn[sfa_slice['slice_hrn']] = []
162 sfa_slices_dict_by_slice_hrn[sfa_slice['slice_hrn']].append(sfa_slice)
164 sfa_slices_dict_by_slice_hrn[sfa_slice['slice_hrn']].append(sfa_slice)
166 for slice_hrn in sfa_slices_dict_by_slice_hrn:
167 list_slices_sfa = sfa_slices_dict_by_slice_hrn[slice_hrn]
168 if slice_hrn =='senslab2.avakian_slice':
169 logger.debug("SLABDRIVER \tsynchronize_oar_and_slice_table slice_hrn %s list_slices_sfa %s\r\n \r\n" %( slice_hrn,list_slices_sfa))
170 self.synchronize_oar_and_slice_table_for_slice_hrn(slice_hrn, oar_leases_list, list_slices_sfa)
175 def synchronize_oar_and_slice_table_for_slice_hrn(self,slice_hrn, oar_leases_list, sfa_slices_list):
177 #Get list of slices/leases . multiple entry per user depending on number of jobs
178 #sfa_slices_list = self.GetSlices(slice_filter = slice_hrn, slice_filter_type = 'slice_hrn')
181 login = slice_hrn.split(".")[1].split("_")[0]
183 #Create dictionnaries based on the tuple user login/ job id
184 #for the leases list and the slices list
186 for sl in sfa_slices_list:
187 if sl['oar_job_id'] != [] :
188 for oar_jobid in sl['oar_job_id']:
189 if (login, oar_jobid) not in sfa_slices_dict:
190 sfa_slices_dict[(login,oar_jobid)] = sl
192 for lease in oar_leases_list:
193 if (lease['user'], lease['lease_id']) not in oar_leases_dict:
194 oar_leases_dict[(lease['user'], lease['lease_id'])] = lease
196 #Find missing entries in the sfa slices list dict by comparing
197 #the keys in both dictionnaries
198 #Add the missing entries in the slice sneslab table
200 for lease in oar_leases_dict :
201 logger.debug(" =============SLABDRIVER \t\t\ synchronize_oar_and_slice_table_for_slice_hrn oar_leases_list %s \r\n \t\t\t SFA_SLICES_DICT %s \r\n \r\n LOGIN %s \r\n " %( oar_leases_list,sfa_slices_dict,login))
202 if lease not in sfa_slices_dict and login == lease[0]:
204 #if lease in GetReservedNodes not in GetSlices update the db
205 #First get the list of nodes hostnames for this job
206 oar_reserved_nodes_listdict = oar_leases_dict[lease]['reserved_nodes']
207 oar_reserved_nodes_list = []
208 for node_dict in oar_reserved_nodes_listdict:
209 oar_reserved_nodes_list.append(node_dict['hostname'])
210 #And update the db with slice hrn, job id and node list
211 self.db.add_job(slice_hrn, lease[1], oar_reserved_nodes_list)
213 for lease in sfa_slices_dict:
214 #Job is now terminated or in Error, either way ot is not going to run again
215 #Remove it from the db
216 if lease not in oar_leases_dict:
217 self.db.delete_job( slice_hrn, lease[1])
221 def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, \
223 aggregate = SlabAggregate(self)
225 slices = SlabSlices(self)
226 peer = slices.get_peer(slice_hrn)
227 sfa_peer = slices.get_sfa_peer(slice_hrn)
230 if not isinstance(creds, list):
234 slice_record = users[0].get('slice_record', {})
237 rspec = RSpec(rspec_string)
238 logger.debug("SLABDRIVER.PY \tcreate_sliver \trspec.version %s " \
241 self.synchronize_oar_and_slice_table(slice_hrn)
242 # ensure site record exists?
243 # ensure slice record exists
244 sfa_slice = slices.verify_slice(slice_hrn, slice_record, peer, \
245 sfa_peer, options=options)
246 requested_attributes = rspec.version.get_slice_attributes()
248 logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice))
250 # ensure person records exists
251 persons = slices.verify_persons(slice_hrn, sfa_slice, users, peer, \
252 sfa_peer, options=options)
256 # add/remove slice from nodes
258 requested_slivers = [node.get('component_name') \
259 for node in rspec.version.get_nodes_with_slivers()]
260 l = [ node for node in rspec.version.get_nodes_with_slivers() ]
261 logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
262 requested_slivers %s listnodes %s" %(requested_slivers,l))
264 nodes = slices.verify_slice_nodes(sfa_slice, requested_slivers, peer)
267 requested_lease_list = []
269 for lease in rspec.version.get_leases():
270 single_requested_lease = {}
271 logger.debug("SLABDRIVER.PY \tcreate_sliver lease %s " %(lease))
272 if not lease.get('lease_id'):
273 single_requested_lease['hostname'] = \
274 slab_xrn_to_hostname(lease.get('component_id').strip())
275 single_requested_lease['start_time'] = lease.get('start_time')
276 single_requested_lease['duration'] = lease.get('duration')
278 kept_leases.append(int(lease['lease_id']))
279 if single_requested_lease.get('hostname'):
280 requested_lease_list.append(single_requested_lease)
282 #dCreate dict of leases by start_time, regrouping nodes reserved at the same
283 #time, for the same amount of time = one job on OAR
284 requested_job_dict = {}
285 for lease in requested_lease_list:
287 #In case it is an asap experiment start_time is empty
288 if lease['start_time'] == '':
289 lease['start_time'] = '0'
291 if lease['start_time'] not in requested_job_dict:
292 if isinstance(lease['hostname'], str):
293 lease['hostname'] = [lease['hostname']]
295 requested_job_dict[lease['start_time']] = lease
298 job_lease = requested_job_dict[lease['start_time']]
299 if lease['duration'] == job_lease['duration'] :
300 job_lease['hostname'].append(lease['hostname'])
305 logger.debug("SLABDRIVER.PY \tcreate_sliver requested_job_dict %s " %(requested_job_dict))
307 leases = slices.verify_slice_leases(sfa_slice, \
308 requested_job_dict, kept_leases, peer)
310 return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
313 def delete_sliver (self, slice_urn, slice_hrn, creds, options):
315 sfa_slice = self.GetSlices(slice_filter = slice_hrn, \
316 slice_filter_type = 'slice_hrn')
317 logger.debug("SLABDRIVER.PY delete_sliver slice %s" %(sfa_slice))
321 slices = SlabSlices(self)
322 # determine if this is a peer slice
324 peer = slices.get_peer(slice_hrn)
325 logger.debug("SLABDRIVER.PY delete_sliver peer %s" %(peer))
328 self.UnBindObjectFromPeer('slice', \
329 sfa_slice['record_id_slice'], peer)
330 self.DeleteSliceFromNodes(sfa_slice)
333 self.BindObjectToPeer('slice', sfa_slice['record_id_slice'], \
334 peer, sfa_slice['peer_slice_id'])
338 def AddSlice(self, slice_record):
339 slab_slice = SliceSenslab( slice_hrn = slice_record['slice_hrn'], \
340 record_id_slice= slice_record['record_id_slice'] , \
341 record_id_user= slice_record['record_id_user'], \
342 peer_authority = slice_record['peer_authority'])
343 logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s slab_slice %s" \
344 %(slice_record,slab_slice))
345 slab_dbsession.add(slab_slice)
346 slab_dbsession.commit()
349 # first 2 args are None in case of resource discovery
350 def list_resources (self, slice_urn, slice_hrn, creds, options):
351 #cached_requested = options.get('cached', True)
353 version_manager = VersionManager()
354 # get the rspec's return format from options
356 version_manager.get_version(options.get('geni_rspec_version'))
357 version_string = "rspec_%s" % (rspec_version)
359 #panos adding the info option to the caching key (can be improved)
360 if options.get('info'):
361 version_string = version_string + "_" + \
362 options.get('info', 'default')
364 # look in cache first
365 #if cached_requested and self.cache and not slice_hrn:
366 #rspec = self.cache.get(version_string)
368 #logger.debug("SlabDriver.ListResources: \
369 #returning cached advertisement")
372 #panos: passing user-defined options
373 aggregate = SlabAggregate(self)
374 origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
375 options.update({'origin_hrn':origin_hrn})
376 rspec = aggregate.get_rspec(slice_xrn=slice_urn, \
377 version=rspec_version, options=options)
380 #if self.cache and not slice_hrn:
381 #logger.debug("Slab.ListResources: stores advertisement in cache")
382 #self.cache.add(version_string, rspec)
387 def list_slices (self, creds, options):
388 # look in cache first
390 #slices = self.cache.get('slices')
392 #logger.debug("PlDriver.list_slices returns from cache")
397 slices = self.GetSlices()
398 logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices))
399 slice_hrns = [slab_slice['slice_hrn'] for slab_slice in slices]
400 #slice_hrns = [slicename_to_hrn(self.hrn, slab_slice['slice_hrn']) \
401 #for slab_slice in slices]
402 slice_urns = [hrn_to_urn(slice_hrn, 'slice') \
403 for slice_hrn in slice_hrns]
407 #logger.debug ("SlabDriver.list_slices stores value in cache")
408 #self.cache.add('slices', slice_urns)
412 #No site or node register supported
413 def register (self, sfa_record, hrn, pub_key):
414 record_type = sfa_record['type']
415 slab_record = self.sfa_fields_to_slab_fields(record_type, hrn, \
419 if record_type == 'slice':
420 acceptable_fields = ['url', 'instantiation', 'name', 'description']
421 for key in slab_record.keys():
422 if key not in acceptable_fields:
424 logger.debug("SLABDRIVER.PY register")
425 slices = self.GetSlices(slice_filter =slab_record['hrn'], \
426 slice_filter_type = 'slice_hrn')
428 pointer = self.AddSlice(slab_record)
430 pointer = slices[0]['slice_id']
432 elif record_type == 'user':
433 persons = self.GetPersons([sfa_record])
434 #persons = self.GetPersons([sfa_record['hrn']])
436 pointer = self.AddPerson(dict(sfa_record))
439 pointer = persons[0]['person_id']
441 #Does this make sense to senslab ?
442 #if 'enabled' in sfa_record and sfa_record['enabled']:
443 #self.UpdatePerson(pointer, \
444 #{'enabled': sfa_record['enabled']})
446 #TODO register Change this AddPersonToSite stuff 05/07/2012 SA
447 # add this person to the site only if
448 # she is being added for the first
449 # time by sfa and doesnt already exist in plc
450 if not persons or not persons[0]['site_ids']:
451 login_base = get_leaf(sfa_record['authority'])
452 self.AddPersonToSite(pointer, login_base)
454 # What roles should this user have?
455 #TODO : DElete this AddRoleToPerson 04/07/2012 SA
456 #Function prototype is :
457 #AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email)
458 #what's the pointer doing here?
459 self.AddRoleToPerson('user', pointer)
462 self.AddPersonKey(pointer, {'key_type' : 'ssh', \
465 #No node adding outside OAR
469 #No site or node record update allowed
470 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
471 pointer = old_sfa_record['pointer']
472 old_sfa_record_type = old_sfa_record['type']
474 # new_key implemented for users only
475 if new_key and old_sfa_record_type not in [ 'user' ]:
476 raise UnknownSfaType(old_sfa_record_type)
478 #if (type == "authority"):
479 #self.shell.UpdateSite(pointer, new_sfa_record)
481 if old_sfa_record_type == "slice":
482 slab_record = self.sfa_fields_to_slab_fields(old_sfa_record_type, \
484 if 'name' in slab_record:
485 slab_record.pop('name')
486 #Prototype should be UpdateSlice(self,
487 #auth, slice_id_or_name, slice_fields)
488 #Senslab cannot update slice since slice = job
489 #so we must delete and create another job
490 self.UpdateSlice(pointer, slab_record)
492 elif old_sfa_record_type == "user":
494 all_fields = new_sfa_record
495 for key in all_fields.keys():
496 if key in ['first_name', 'last_name', 'title', 'email',
497 'password', 'phone', 'url', 'bio', 'accepted_aup',
499 update_fields[key] = all_fields[key]
500 self.UpdatePerson(pointer, update_fields)
503 # must check this key against the previous one if it exists
504 persons = self.GetPersons([pointer], ['key_ids'])
506 keys = person['key_ids']
507 keys = self.GetKeys(person['key_ids'])
509 # Delete all stale keys
512 if new_key != key['key']:
513 self.DeleteKey(key['key_id'])
517 self.AddPersonKey(pointer, {'key_type': 'ssh', \
524 def remove (self, sfa_record):
525 sfa_record_type = sfa_record['type']
526 hrn = sfa_record['hrn']
527 record_id = sfa_record['record_id']
528 if sfa_record_type == 'user':
530 #get user from senslab ldap
531 person = self.GetPersons(sfa_record)
532 #No registering at a given site in Senslab.
533 #Once registered to the LDAP, all senslab sites are
536 #Mark account as disabled in ldap
537 self.DeletePerson(sfa_record)
538 elif sfa_record_type == 'slice':
539 if self.GetSlices(slice_filter = hrn, \
540 slice_filter_type = 'slice_hrn'):
541 self.DeleteSlice(sfa_record_type)
543 #elif type == 'authority':
544 #if self.GetSites(pointer):
545 #self.DeleteSite(pointer)
551 #TODO clean GetPeers. 05/07/12SA
552 def GetPeers (self, auth = None, peer_filter=None, return_fields_list=None):
554 existing_records = {}
555 existing_hrns_by_types = {}
556 logger.debug("SLABDRIVER \tGetPeers auth = %s, peer_filter %s, \
557 return_field %s " %(auth , peer_filter, return_fields_list))
558 all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
559 for record in all_records:
560 existing_records[(record.hrn, record.type)] = record
561 if record.type not in existing_hrns_by_types:
562 existing_hrns_by_types[record.type] = [record.hrn]
563 logger.debug("SLABDRIVER \tGetPeer\t NOT IN \
564 existing_hrns_by_types %s " %( existing_hrns_by_types))
567 logger.debug("SLABDRIVER \tGetPeer\t \INNN type %s hrn %s " \
568 %(record.type,record.hrn))
569 existing_hrns_by_types[record.type].append(record.hrn)
572 logger.debug("SLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
573 %( existing_hrns_by_types))
578 records_list.append(existing_records[(peer_filter,'authority')])
580 for hrn in existing_hrns_by_types['authority']:
581 records_list.append(existing_records[(hrn,'authority')])
583 logger.debug("SLABDRIVER \tGetPeer \trecords_list %s " \
589 return_records = records_list
590 if not peer_filter and not return_fields_list:
594 logger.debug("SLABDRIVER \tGetPeer return_records %s " \
596 return return_records
599 #TODO : Handling OR request in make_ldap_filters_from_records
600 #instead of the for loop
601 #over the records' list
602 def GetPersons(self, person_filter=None, return_fields_list=None):
604 person_filter should be a list of dictionnaries when not set to None.
605 Returns a list of users whose accounts are enabled found in ldap.
608 logger.debug("SLABDRIVER \tGetPersons person_filter %s" \
611 if person_filter and isinstance(person_filter, list):
612 #If we are looking for a list of users (list of dict records)
613 #Usually the list contains only one user record
614 for searched_attributes in person_filter:
616 #Get only enabled user accounts in senslab LDAP :
617 #add a filter for make_ldap_filters_from_record
618 person = self.ldap.LdapFindUser(searched_attributes, \
619 is_user_enabled=True)
620 person_list.append(person)
623 #Get only enabled user accounts in senslab LDAP :
624 #add a filter for make_ldap_filters_from_record
625 person_list = self.ldap.LdapFindUser(is_user_enabled=True)
629 def GetTimezone(self):
630 server_timestamp, server_tz = self.oar.parser.\
631 SendRequest("GET_timezone")
632 return server_timestamp, server_tz
635 def DeleteJobs(self, job_id, slice_hrn):
636 if not job_id or job_id is -1:
638 username = slice_hrn.split(".")[-1].rstrip("_slice")
640 reqdict['method'] = "delete"
641 reqdict['strval'] = str(job_id)
643 self.db.delete_job(slice_hrn, job_id)
644 answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id', \
646 logger.debug("SLABDRIVER \tDeleteJobs jobid %s \r\n answer %s username %s" \
647 %(job_id,answer, username))
652 ##TODO : Unused GetJobsId ? SA 05/07/12
653 #def GetJobsId(self, job_id, username = None ):
655 #Details about a specific job.
656 #Includes details about submission time, jot type, state, events,
657 #owner, assigned ressources, walltime etc...
661 #node_list_k = 'assigned_network_address'
662 ##Get job info from OAR
663 #job_info = self.oar.parser.SendRequest(req, job_id, username)
665 #logger.debug("SLABDRIVER \t GetJobsId %s " %(job_info))
667 #if job_info['state'] == 'Terminated':
668 #logger.debug("SLABDRIVER \t GetJobsId job %s TERMINATED"\
671 #if job_info['state'] == 'Error':
672 #logger.debug("SLABDRIVER \t GetJobsId ERROR message %s "\
677 #logger.error("SLABDRIVER \tGetJobsId KeyError")
680 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
682 ##Replaces the previous entry
683 ##"assigned_network_address" / "reserved_resources"
685 #job_info.update({'node_ids':parsed_job_info[node_list_k]})
686 #del job_info[node_list_k]
687 #logger.debug(" \r\nSLABDRIVER \t GetJobsId job_info %s " %(job_info))
691 def GetJobsResources(self, job_id, username = None):
692 #job_resources=['reserved_resources', 'assigned_resources',\
693 #'job_id', 'job_uri', 'assigned_nodes',\
695 #assigned_res = ['resource_id', 'resource_uri']
696 #assigned_n = ['node', 'node_uri']
698 req = "GET_jobs_id_resources"
699 node_list_k = 'reserved_resources'
701 #Get job resources list from OAR
702 node_id_list = self.oar.parser.SendRequest(req, job_id, username)
703 logger.debug("SLABDRIVER \t GetJobsResources %s " %(node_id_list))
706 self.__get_hostnames_from_oar_node_ids(node_id_list)
708 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
710 #Replaces the previous entry "assigned_network_address" /
711 #"reserved_resources"
713 job_info = {'node_ids': hostname_list}
718 def get_info_on_reserved_nodes(self, job_info, node_list_name):
719 #Get the list of the testbed nodes records and make a
720 #dictionnary keyed on the hostname out of it
721 node_list_dict = self.GetNodes()
722 #node_hostname_list = []
723 node_hostname_list = [node['hostname'] for node in node_list_dict]
724 #for node in node_list_dict:
725 #node_hostname_list.append(node['hostname'])
726 node_dict = dict(zip(node_hostname_list, node_list_dict))
728 reserved_node_hostname_list = []
729 for index in range(len(job_info[node_list_name])):
730 #job_info[node_list_name][k] =
731 reserved_node_hostname_list[index] = \
732 node_dict[job_info[node_list_name][index]]['hostname']
734 logger.debug("SLABDRIVER \t get_info_on_reserved_nodes \
735 reserved_node_hostname_list %s" \
736 %(reserved_node_hostname_list))
738 logger.error("SLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
740 return reserved_node_hostname_list
742 def GetNodesCurrentlyInUse(self):
743 """Returns a list of all the nodes already involved in an oar job"""
744 return self.oar.parser.SendRequest("GET_running_jobs")
746 def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
747 full_nodes_dict_list = self.GetNodes()
748 #Put the full node list into a dictionary keyed by oar node id
749 oar_id_node_dict = {}
750 for node in full_nodes_dict_list:
751 oar_id_node_dict[node['oar_id']] = node
753 logger.debug("SLABDRIVER \t __get_hostnames_from_oar_node_ids\
754 oar_id_node_dict %s" %(oar_id_node_dict))
756 hostname_dict_list = []
757 for resource_id in resource_id_list:
758 #Because jobs requested "asap" do not have defined resources
759 if resource_id is not "Undefined":
760 hostname_dict_list.append({'hostname' : \
761 oar_id_node_dict[resource_id]['hostname'],
762 'site_id' : oar_id_node_dict[resource_id]['site']})
764 #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
765 return hostname_dict_list
767 def GetReservedNodes(self):
768 #Get the nodes in use and the reserved nodes
769 reservation_dict_list = \
770 self.oar.parser.SendRequest("GET_reserved_nodes")
773 for resa in reservation_dict_list:
774 logger.debug ("GetReservedNodes resa %s"%(resa))
775 #dict list of hostnames and their site
776 resa['reserved_nodes'] = \
777 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
779 #del resa['resource_ids']
780 return reservation_dict_list
782 def GetNodes(self, node_filter_dict = None, return_fields_list = None):
784 node_filter_dict : dictionnary of lists
787 node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
788 node_dict_list = node_dict_by_id.values()
790 #No filtering needed return the list directly
791 if not (node_filter_dict or return_fields_list):
792 return node_dict_list
794 return_node_list = []
796 for filter_key in node_filter_dict:
798 #Filter the node_dict_list by each value contained in the
799 #list node_filter_dict[filter_key]
800 for value in node_filter_dict[filter_key]:
801 for node in node_dict_list:
802 if node[filter_key] == value:
803 if return_fields_list :
805 for k in return_fields_list:
807 return_node_list.append(tmp)
809 return_node_list.append(node)
811 logger.log_exc("GetNodes KeyError")
815 return return_node_list
818 def GetSites(self, site_filter_name_list = None, return_fields_list = None):
819 site_dict = self.oar.parser.SendRequest("GET_sites")
820 #site_dict : dict where the key is the sit ename
821 return_site_list = []
822 if not ( site_filter_name_list or return_fields_list):
823 return_site_list = site_dict.values()
824 return return_site_list
826 for site_filter_name in site_filter_name_list:
827 if site_filter_name in site_dict:
828 if return_fields_list:
829 for field in return_fields_list:
832 tmp[field] = site_dict[site_filter_name][field]
834 logger.error("GetSites KeyError %s "%(field))
836 return_site_list.append(tmp)
838 return_site_list.append( site_dict[site_filter_name])
841 return return_site_list
842 #warning return_fields_list paramr emoved (Not used)
843 def GetSlices(self, slice_filter = None, slice_filter_type = None):
844 #def GetSlices(self, slice_filter = None, slice_filter_type = None, \
845 #return_fields_list = None):
846 """ Get the slice records from the slab db.
847 Returns a slice ditc if slice_filter and slice_filter_type
849 Returns a list of slice dictionnaries if there are no filters
854 return_slice_list = []
857 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
859 if slice_filter_type in authorized_filter_types_list:
860 #Get list of slices based on the slice hrn
861 if slice_filter_type == 'slice_hrn':
863 login = slice_filter.split(".")[1].split("_")[0]
865 #DO NOT USE RegSlice - reg_researchers to get the hrn of the user
866 #otherwise will mess up the RegRecord in Resolve, don't know
869 #Only one entry for one user = one slice in slice_senslab table
870 slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).first()
872 #Get slice based on user id
873 if slice_filter_type == 'record_id_user':
874 slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).first()
879 #slicerec_dictlist = []
880 slicerec_dict = slicerec.dump_sqlalchemyobj_to_dict()
882 login = slicerec_dict['slice_hrn'].split(".")[1].split("_")[0]
884 #for record in slicerec:
885 #slicerec_dictlist.append(record.dump_sqlalchemyobj_to_dict())
887 #login = slicerec_dictlist[0]['slice_hrn'].split(".")[1].split("_")[0]
889 #One slice can have multiple jobs
890 sqljob_list = slab_dbsession.query(JobSenslab).filter_by( slice_hrn=slicerec_dict['slice_hrn']).all()
892 for job in sqljob_list:
893 job_list.append(job.dump_sqlalchemyobj_to_dict())
895 logger.debug("\r\n SLABDRIVER \tGetSlices login %s \
897 %(login, slicerec_dict))
899 #Several jobs for one slice
900 slicerec_dict['oar_job_id'] = []
901 for job in job_list :
902 #if slicerec_dict['oar_job_id'] is not -1:
903 #Check with OAR the status of the job if a job id is in
906 rslt = self.GetJobsResources(job['oar_job_id'], \
908 logger.debug("SLABDRIVER.PY \tGetSlices rslt fromn GetJobsResources %s"\
911 slicerec_dict['oar_job_id'].append(job['oar_job_id'])
912 slicerec_dict.update(rslt)
913 slicerec_dict.update({'hrn':\
914 str(slicerec_dict['slice_hrn'])})
915 #If GetJobsResources is empty, this means the job is
916 #now in the 'Terminated' state
917 #Update the slice record
919 self.db.delete_job(slice_filter, job['oar_job_id'])
921 update({'hrn':str(slicerec_dict['slice_hrn'])})
924 slicerec_dict['node_ids'] = job['node_list']
928 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slicerec_dict %s"\
931 return [slicerec_dict]
935 slice_list = slab_dbsession.query(SliceSenslab).all()
936 sqljob_list = slab_dbsession.query(JobSenslab).all()
939 for job in sqljob_list:
940 job_list.append(job.dump_sqlalchemyobj_to_dict())
942 return_slice_list = []
943 for record in slice_list:
944 return_slice_list.append(record.dump_sqlalchemyobj_to_dict())
946 for slicerec_dict in return_slice_list:
947 slicerec_dict['oar_job_id'] = []
949 if slicerec_dict['slice_hrn'] in job:
950 slicerec_dict['oar_job_id'].append(job['oar_job_id'])
952 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slices %s \
953 slice_filter %s " %(return_slice_list, slice_filter))
955 #if return_fields_list:
956 #return_slice_list = parse_filter(sliceslist, \
957 #slice_filter,'slice', return_fields_list)
959 return return_slice_list
965 def testbed_name (self): return self.hrn
967 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
968 def aggregate_version (self):
969 version_manager = VersionManager()
970 ad_rspec_versions = []
971 request_rspec_versions = []
972 for rspec_version in version_manager.versions:
973 if rspec_version.content_type in ['*', 'ad']:
974 ad_rspec_versions.append(rspec_version.to_dict())
975 if rspec_version.content_type in ['*', 'request']:
976 request_rspec_versions.append(rspec_version.to_dict())
978 'testbed':self.testbed_name(),
979 'geni_request_rspec_versions': request_rspec_versions,
980 'geni_ad_rspec_versions': ad_rspec_versions,
989 # Convert SFA fields to PLC fields for use when registering up updating
990 # registry record in the PLC database
992 # @param type type of record (user, slice, ...)
993 # @param hrn human readable name
994 # @param sfa_fields dictionary of SFA fields
995 # @param slab_fields dictionary of PLC fields (output)
997 def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
999 def convert_ints(tmpdict, int_fields):
1000 for field in int_fields:
1001 if field in tmpdict:
1002 tmpdict[field] = int(tmpdict[field])
1005 #for field in record:
1006 # slab_record[field] = record[field]
1008 if sfa_type == "slice":
1009 #instantion used in get_slivers ?
1010 if not "instantiation" in slab_record:
1011 slab_record["instantiation"] = "senslab-instantiated"
1012 #slab_record["hrn"] = hrn_to_pl_slicename(hrn)
1013 #Unused hrn_to_pl_slicename because Slab's hrn already in the appropriate form SA 23/07/12
1014 slab_record["hrn"] = hrn
1015 logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
1016 slab_record %s " %(slab_record['hrn']))
1018 slab_record["url"] = record["url"]
1019 if "description" in record:
1020 slab_record["description"] = record["description"]
1021 if "expires" in record:
1022 slab_record["expires"] = int(record["expires"])
1024 #nodes added by OAR only and then imported to SFA
1025 #elif type == "node":
1026 #if not "hostname" in slab_record:
1027 #if not "hostname" in record:
1028 #raise MissingSfaInfo("hostname")
1029 #slab_record["hostname"] = record["hostname"]
1030 #if not "model" in slab_record:
1031 #slab_record["model"] = "geni"
1034 #elif type == "authority":
1035 #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
1037 #if not "name" in slab_record:
1038 #slab_record["name"] = hrn
1040 #if not "abbreviated_name" in slab_record:
1041 #slab_record["abbreviated_name"] = hrn
1043 #if not "enabled" in slab_record:
1044 #slab_record["enabled"] = True
1046 #if not "is_public" in slab_record:
1047 #slab_record["is_public"] = True
1054 def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
1055 """ Transforms unix timestamp into valid OAR date format """
1057 #Used in case of a scheduled experiment (not immediate)
1058 #To run an XP immediately, don't specify date and time in RSpec
1059 #They will be set to None.
1060 if xp_utc_timestamp:
1061 #transform the xp_utc_timestamp into server readable time
1062 xp_server_readable_date = datetime.fromtimestamp(int(\
1063 xp_utc_timestamp)).strftime(self.time_format)
1065 return xp_server_readable_date
1073 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
1074 lease_start_time, lease_duration, slice_user=None):
1076 lease_dict['lease_start_time'] = lease_start_time
1077 lease_dict['lease_duration'] = lease_duration
1078 lease_dict['added_nodes'] = added_nodes
1079 lease_dict['slice_name'] = slice_name
1080 lease_dict['slice_user'] = slice_user
1081 lease_dict['grain'] = self.GetLeaseGranularity()
1082 lease_dict['time_format'] = self.time_format
1084 def __create_job_structure_request_for_OAR(lease_dict):
1085 """ Creates the structure needed for a correct POST on OAR.
1086 Makes the timestamp transformation into the appropriate format.
1087 Sends the POST request to create the job with the resources in
1098 reqdict['workdir'] = '/tmp'
1099 reqdict['resource'] = "{network_address in ("
1101 for node in lease_dict['added_nodes']:
1102 logger.debug("\r\n \r\n OARrestapi \t __create_job_structure_request_for_OAR \
1105 # Get the ID of the node
1107 reqdict['resource'] += "'" + nodeid + "', "
1108 nodeid_list.append(nodeid)
1110 custom_length = len(reqdict['resource'])- 2
1111 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
1112 ")}/nodes=" + str(len(nodeid_list))
1114 def __process_walltime(duration):
1115 """ Calculates the walltime in seconds from the duration in H:M:S
1116 specified in the RSpec.
1120 # Fixing the walltime by adding a few delays.
1121 # First put the walltime in seconds oarAdditionalDelay = 20;
1122 # additional delay for /bin/sleep command to
1123 # take in account prologue and epilogue scripts execution
1124 # int walltimeAdditionalDelay = 120; additional delay
1125 desired_walltime = duration
1126 total_walltime = desired_walltime + 140#+2 min 20
1127 sleep_walltime = desired_walltime + 20 #+20 sec
1129 #Put the walltime back in str form
1130 #First get the hours
1131 walltime.append(str(total_walltime / 3600))
1132 total_walltime = total_walltime - 3600 * int(walltime[0])
1133 #Get the remaining minutes
1134 walltime.append(str(total_walltime / 60))
1135 total_walltime = total_walltime - 60 * int(walltime[1])
1137 walltime.append(str(total_walltime))
1140 logger.log_exc(" __process_walltime duration null")
1142 return walltime, sleep_walltime
1145 walltime, sleep_walltime = \
1146 __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1149 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1150 ":" + str(walltime[1]) + ":" + str(walltime[2])
1151 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1153 #In case of a scheduled experiment (not immediate)
1154 #To run an XP immediately, don't specify date and time in RSpec
1155 #They will be set to None.
1156 if lease_dict['lease_start_time'] is not '0':
1157 #Readable time accepted by OAR
1158 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1159 strftime(lease_dict['time_format'])
1160 reqdict['reservation'] = start_time
1161 #If there is not start time, Immediate XP. No need to add special
1165 reqdict['type'] = "deploy"
1166 reqdict['directory'] = ""
1167 reqdict['name'] = "SFA_" + lease_dict['slice_user']
1172 #Create the request for OAR
1173 reqdict = __create_job_structure_request_for_OAR(lease_dict)
1174 # first step : start the OAR job and update the job
1175 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1178 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1179 reqdict, slice_user)
1180 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s " %(answer))
1182 jobid = answer['id']
1184 logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1185 Impossible to create job %s " %(answer))
1189 def __configure_experiment(jobid, added_nodes):
1190 # second step : configure the experiment
1191 # we need to store the nodes in a yaml (well...) file like this :
1192 # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1193 job_file = open('/tmp/sfa/'+ str(jobid) + '.json', 'w')
1195 job_file.write(str(added_nodes[0].strip('node')))
1196 for node in added_nodes[1:len(added_nodes)] :
1197 job_file.write(', '+ node.strip('node'))
1202 def __launch_senslab_experiment(jobid):
1203 # third step : call the senslab-experiment wrapper
1204 #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar
1205 # "+str(jobid)+" "+slice_user
1206 javacmdline = "/usr/bin/java"
1208 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1209 #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", \
1210 #str(jobid), slice_user])
1211 output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1212 slice_user],stdout=subprocess.PIPE).communicate()[0]
1214 logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1221 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1222 added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1223 self.db.add_job( slice_name, jobid, added_nodes)
1225 __configure_experiment(jobid, added_nodes)
1226 __launch_senslab_experiment(jobid)
1230 def AddLeases(self, hostname_list, slice_record, lease_start_time, lease_duration):
1231 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s \
1232 slice_record %s lease_start_time %s lease_duration %s "\
1233 %( hostname_list, slice_record , lease_start_time, \
1236 tmp = slice_record['PI'][0].split(".")
1237 username = tmp[(len(tmp)-1)]
1238 self.LaunchExperimentOnOAR(hostname_list, slice_record['name'], lease_start_time, lease_duration, username)
1239 start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1240 logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1245 #Delete the jobs and updates the job id in the senslab table
1247 #Does not clear the node list
1248 def DeleteSliceFromNodes(self, slice_record):
1249 # Get user information
1251 self.DeleteJobs(slice_record['oar_job_id'], slice_record['hrn'])
1256 def GetLeaseGranularity(self):
1257 """ Returns the granularity of Senslab testbed.
1258 Defined in seconds. """
1263 def GetLeases(self, lease_filter_dict=None, return_fields_list=None):
1264 unfiltered_reservation_list = self.GetReservedNodes()
1266 ##Synchronize slice_table of sfa senslab db
1267 #self.synchronize_oar_and_slice_table(unfiltered_reservation_list)
1269 reservation_list = []
1270 #Find the slice associated with this user senslab ldap uid
1271 logger.debug(" SLABDRIVER.PY \tGetLeases ")
1272 #Create user dict first to avoir looking several times for
1273 #the same user in LDAP SA 27/07/12
1275 for resa in unfiltered_reservation_list:
1276 logger.debug("SLABDRIVER \tGetLeases USER %s"\
1278 if resa['user'] not in resa_user_dict:
1279 logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1280 ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1281 ldap_info = ldap_info[0][1]
1282 user = dbsession.query(RegUser).filter_by(email = \
1283 ldap_info['mail'][0]).first()
1284 #Separated in case user not in database : record_id not defined SA 17/07//12
1285 query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1286 if query_slice_info:
1287 slice_info = query_slice_info.first()
1291 resa_user_dict[resa['user']] = {}
1292 resa_user_dict[resa['user']]['ldap_info'] = user
1293 resa_user_dict[resa['user']]['slice_info'] = slice_info
1295 logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1297 for resa in unfiltered_reservation_list:
1299 #ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1300 #ldap_info = ldap_info[0][1]
1302 #user = dbsession.query(RegUser).filter_by(email = \
1303 #ldap_info['mail'][0]).first()
1304 ##Separated in case user not in database : record_id not defined SA 17/07//12
1305 #query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1306 #if query_slice_info:
1307 #slice_info = query_slice_info.first()
1309 resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info'].slice_hrn
1310 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1312 #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1313 resa['component_id_list'] = []
1314 #Transform the hostnames into urns (component ids)
1315 for node in resa['reserved_nodes']:
1316 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1317 #self.root_auth, node['hostname']))
1318 slab_xrn = slab_xrn_object(self.root_auth, node['hostname'])
1319 resa['component_id_list'].append(slab_xrn.urn)
1321 #Filter the reservation list if necessary
1322 #Returns all the leases associated with a given slice
1323 if lease_filter_dict:
1324 logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1325 %(lease_filter_dict))
1326 for resa in unfiltered_reservation_list:
1327 if lease_filter_dict['name'] == resa['slice_hrn']:
1328 reservation_list.append(resa)
1330 reservation_list = unfiltered_reservation_list
1332 logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1333 %(reservation_list))
1334 return reservation_list
1336 def augment_records_with_testbed_info (self, sfa_records):
1337 return self.fill_record_info (sfa_records)
1339 def fill_record_info(self, record_list):
1341 Given a SFA record, fill in the senslab specific and SFA specific
1342 fields in the record.
1345 logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1346 if not isinstance(record_list, list):
1347 record_list = [record_list]
1350 for record in record_list:
1351 #If the record is a SFA slice record, then add information
1352 #about the user of this slice. This kind of
1353 #information is in the Senslab's DB.
1354 if str(record['type']) == 'slice':
1355 #Get slab slice record.
1356 recslice_list = self.GetSlices(slice_filter = \
1357 str(record['hrn']),\
1358 slice_filter_type = 'slice_hrn')
1360 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1361 recslice_list[0]['record_id_user']).first()
1362 logger.debug("SLABDRIVER \tfill_record_info TYPE SLICE RECUSER %s " %(recuser))
1363 record.update({'PI':[recuser.hrn],
1364 'researcher': [recuser.hrn],
1365 'name':record['hrn'],
1366 'oar_job_id':[rec['oar_job_id'] for rec in recslice_list],
1368 'person_ids':[recslice_list[0]['record_id_user']],
1369 'geni_urn':'', #For client_helper.py compatibility
1370 'keys':'', #For client_helper.py compatibility
1371 'key_ids':''}) #For client_helper.py compatibility
1373 #for rec in recslice_list:
1374 #record['oar_job_id'].append(rec['oar_job_id'])
1375 logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1376 recslice_list %s \r\n \t RECORD %s \r\n \r\n" %(recslice_list,record))
1377 if str(record['type']) == 'user':
1378 #The record is a SFA user record.
1379 #Get the information about his slice from Senslab's DB
1380 #and add it to the user record.
1381 recslice_list = self.GetSlices(\
1382 slice_filter = record['record_id'],\
1383 slice_filter_type = 'record_id_user')
1385 logger.debug( "SLABDRIVER.PY \t fill_record_info TYPE USER \
1386 recslice_list %s \r\n \t RECORD %s \r\n" %(recslice_list , record))
1387 #Append slice record in records list,
1388 #therefore fetches user and slice info again(one more loop)
1389 #Will update PIs and researcher for the slice
1390 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1391 recslice_list[0]['record_id_user']).first()
1392 logger.debug( "SLABDRIVER.PY \t fill_record_info USER \
1393 recuser %s \r\n \r\n" %(recuser))
1395 recslice = recslice_list[0]
1396 recslice.update({'PI':[recuser.hrn],
1397 'researcher': [recuser.hrn],
1398 'name':record['hrn'],
1400 'oar_job_id': [rec['oar_job_id'] for rec in recslice_list],
1401 'person_ids':[recslice_list[0]['record_id_user']]})
1402 recslice.update({'type':'slice', \
1403 'hrn':recslice_list[0]['slice_hrn']})
1404 #for rec in recslice_list:
1405 #recslice['oar_job_id'].append(rec['oar_job_id'])
1407 #GetPersons takes [] as filters
1408 #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1409 user_slab = self.GetPersons([record])
1412 record.update(user_slab[0])
1413 #For client_helper.py compatibility
1414 record.update( { 'geni_urn':'',
1417 record_list.append(recslice)
1419 logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1420 INFO TO USER records %s" %(record_list))
1421 logger.debug("SLABDRIVER.PY \tfill_record_info END \
1422 #record %s \r\n \r\n " %(record))
1424 except TypeError, error:
1425 logger.log_exc("SLABDRIVER \t fill_record_info EXCEPTION %s"\
1427 #logger.debug("SLABDRIVER.PY \t fill_record_info ENDENDEND ")
1431 #self.fill_record_slab_info(records)
1437 #TODO Update membership? update_membership_list SA 05/07/12
1438 #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1440 ## get a list of the HRNs tht are members of the old and new records
1442 #oldList = oldRecord.get(listName, [])
1445 #newList = record.get(listName, [])
1447 ## if the lists are the same, then we don't have to update anything
1448 #if (oldList == newList):
1451 ## build a list of the new person ids, by looking up each person to get
1455 #records = table.find({'type': 'user', 'hrn': newList})
1456 #for rec in records:
1457 #newIdList.append(rec['pointer'])
1459 ## build a list of the old person ids from the person_ids field
1461 #oldIdList = oldRecord.get("person_ids", [])
1462 #containerId = oldRecord.get_pointer()
1464 ## if oldRecord==None, then we are doing a Register, instead of an
1467 #containerId = record.get_pointer()
1469 ## add people who are in the new list, but not the oldList
1470 #for personId in newIdList:
1471 #if not (personId in oldIdList):
1472 #addFunc(self.plauth, personId, containerId)
1474 ## remove people who are in the old list, but not the new list
1475 #for personId in oldIdList:
1476 #if not (personId in newIdList):
1477 #delFunc(self.plauth, personId, containerId)
1479 #def update_membership(self, oldRecord, record):
1481 #if record.type == "slice":
1482 #self.update_membership_list(oldRecord, record, 'researcher',
1483 #self.users.AddPersonToSlice,
1484 #self.users.DeletePersonFromSlice)
1485 #elif record.type == "authority":
1490 # I don't think you plan on running a component manager at this point
1491 # let me clean up the mess of ComponentAPI that is deprecated anyways
1494 #TODO FUNCTIONS SECTION 04/07/2012 SA
1496 #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1498 def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1499 """ This method is a hopefully temporary hack to let the sfa correctly
1500 detach the objects it creates from a remote peer object. This is
1501 needed so that the sfa federation link can work in parallel with
1502 RefreshPeer, as RefreshPeer depends on remote objects being correctly
1505 auth : struct, API authentication structure
1506 AuthMethod : string, Authentication method to use
1507 object_type : string, Object type, among 'site','person','slice',
1509 object_id : int, object_id
1510 shortname : string, peer shortname
1514 logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1518 #TODO Is BindObjectToPeer still necessary ? Currently does nothing
1520 def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1521 remote_object_id=None):
1522 """This method is a hopefully temporary hack to let the sfa correctly
1523 attach the objects it creates to a remote peer object. This is needed
1524 so that the sfa federation link can work in parallel with RefreshPeer,
1525 as RefreshPeer depends on remote objects being correctly marked.
1527 shortname : string, peer shortname
1528 remote_object_id : int, remote object_id, set to 0 if unknown
1532 logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1535 #TODO UpdateSlice 04/07/2012 SA
1536 #Funciton should delete and create another job since oin senslab slice=job
1537 def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1538 """Updates the parameters of an existing slice with the values in
1540 Users may only update slices of which they are members.
1541 PIs may update any of the slices at their sites, or any slices of
1542 which they are members. Admins may update any slice.
1543 Only PIs and admins may update max_nodes. Slices cannot be renewed
1544 (by updating the expires parameter) more than 8 weeks into the future.
1545 Returns 1 if successful, faults otherwise.
1549 logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1552 #TODO UpdatePerson 04/07/2012 SA
1553 def UpdatePerson(self, auth, person_id_or_email, person_fields=None):
1554 """Updates a person. Only the fields specified in person_fields
1555 are updated, all other fields are left untouched.
1556 Users and techs can only update themselves. PIs can only update
1557 themselves and other non-PIs at their sites.
1558 Returns 1 if successful, faults otherwise.
1562 logger.warning("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1565 #TODO GetKeys 04/07/2012 SA
1566 def GetKeys(self, auth, key_filter=None, return_fields=None):
1567 """Returns an array of structs containing details about keys.
1568 If key_filter is specified and is an array of key identifiers,
1569 or a struct of key attributes, only keys matching the filter
1570 will be returned. If return_fields is specified, only the
1571 specified details will be returned.
1573 Admin may query all keys. Non-admins may only query their own keys.
1577 logger.warning("SLABDRIVER GetKeys EMPTY - DO NOTHING \r\n ")
1580 #TODO DeleteKey 04/07/2012 SA
1581 def DeleteKey(self, auth, key_id):
1583 Non-admins may only delete their own keys.
1584 Returns 1 if successful, faults otherwise.
1588 logger.warning("SLABDRIVER DeleteKey EMPTY - DO NOTHING \r\n ")
1592 #TODO : Check rights to delete person
1593 def DeletePerson(self, auth, person_record):
1594 """ Disable an existing account in senslab LDAP.
1595 Users and techs can only delete themselves. PIs can only
1596 delete themselves and other non-PIs at their sites.
1597 ins can delete anyone.
1598 Returns 1 if successful, faults otherwise.
1602 #Disable user account in senslab LDAP
1603 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1604 logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1607 #TODO Check DeleteSlice, check rights 05/07/2012 SA
1608 def DeleteSlice(self, auth, slice_record):
1609 """ Deletes the specified slice.
1610 Senslab : Kill the job associated with the slice if there is one
1611 using DeleteSliceFromNodes.
1612 Updates the slice record in slab db to remove the slice nodes.
1614 Users may only delete slices of which they are members. PIs may
1615 delete any of the slices at their sites, or any slices of which
1616 they are members. Admins may delete any slice.
1617 Returns 1 if successful, faults otherwise.
1621 self.DeleteSliceFromNodes(slice_record)
1622 logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1625 #TODO AddPerson 04/07/2012 SA
1626 def AddPerson(self, auth, person_fields=None):
1627 """Adds a new account. Any fields specified in person_fields are used,
1628 otherwise defaults are used.
1629 Accounts are disabled by default. To enable an account,
1631 Returns the new person_id (> 0) if successful, faults otherwise.
1635 logger.warning("SLABDRIVER AddPerson EMPTY - DO NOTHING \r\n ")
1638 #TODO AddPersonToSite 04/07/2012 SA
1639 def AddPersonToSite (self, auth, person_id_or_email, \
1640 site_id_or_login_base=None):
1641 """ Adds the specified person to the specified site. If the person is
1642 already a member of the site, no errors are returned. Does not change
1643 the person's primary site.
1644 Returns 1 if successful, faults otherwise.
1648 logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1651 #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1652 def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1653 """Grants the specified role to the person.
1654 PIs can only grant the tech and user roles to users and techs at their
1655 sites. Admins can grant any role to any user.
1656 Returns 1 if successful, faults otherwise.
1660 logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1663 #TODO AddPersonKey 04/07/2012 SA
1664 def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1665 """Adds a new key to the specified account.
1666 Non-admins can only modify their own keys.
1667 Returns the new key_id (> 0) if successful, faults otherwise.
1671 logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1674 def DeleteLeases(self, leases_id_list, slice_hrn ):
1675 for job_id in leases_id_list:
1676 self.DeleteJobs(job_id, slice_hrn)
1678 logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \r\n " %(leases_id_list, slice_hrn))