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')
72 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
74 top_level_status = 'unknown'
75 nodes_in_slice = sl['node_ids']
76 recuser = dbsession.query(RegRecord).filter_by(record_id = \
77 sl['record_id_user']).first()
78 sl.update({'user':recuser.hrn})
79 if len(nodes_in_slice) is 0:
80 raise SliverDoesNotExist("No slivers allocated ")
82 top_level_status = 'ready'
84 logger.debug("Slabdriver - sliver_status Sliver status urn %s hrn %s sl\
85 %s \r\n " %(slice_urn, slice_hrn, sl))
87 if sl['oar_job_id'] is not -1:
88 #A job is running on Senslab for this slice
89 # report about the local nodes that are in the slice only
91 nodes_all = self.GetNodes({'hostname':nodes_in_slice},
92 ['node_id', 'hostname','site','boot_state'])
93 nodeall_byhostname = dict([(n['hostname'], n) for n in nodes_all])
97 result['geni_urn'] = slice_urn
98 result['pl_login'] = sl['user'] #For compatibility
101 timestamp = float(sl['startTime']) + float(sl['walltime'])
102 result['pl_expires'] = strftime(self.time_format, \
103 gmtime(float(timestamp)))
104 #result['slab_expires'] = strftime(self.time_format,\
105 #gmtime(float(timestamp)))
108 for node in nodeall_byhostname:
110 #res['slab_hostname'] = node['hostname']
111 #res['slab_boot_state'] = node['boot_state']
113 res['pl_hostname'] = nodeall_byhostname[node]['hostname']
114 res['pl_boot_state'] = nodeall_byhostname[node]['boot_state']
115 res['pl_last_contact'] = strftime(self.time_format, \
116 gmtime(float(timestamp)))
117 sliver_id = urn_to_sliver_id(slice_urn, sl['record_id_slice'], \
118 nodeall_byhostname[node]['node_id'])
119 res['geni_urn'] = sliver_id
120 if nodeall_byhostname[node]['boot_state'] == 'Alive':
122 res['geni_status'] = 'ready'
124 res['geni_status'] = 'failed'
125 top_level_status = 'failed'
127 res['geni_error'] = ''
129 resources.append(res)
131 result['geni_status'] = top_level_status
132 result['geni_resources'] = resources
133 logger.debug("SLABDRIVER \tsliver_statusresources %s res %s "\
138 def synchronize_oar_and_slice_table(self, slice_hrn = None):
140 oar_leases_list = self.GetReservedNodes()
142 logger.debug("SLABDRIVER \tsynchronize_oar_and_slice_table \r\n \r\n : oar_leases_list %s\r\n" %( oar_leases_list))
143 #Get list of slices/leases . multiple entry per user depending on number of jobs
144 #At this point we don't have the slice_hrn so that's why
145 #we are calling Getslices, which holds a field with slice_hrn
148 sfa_slices_list = self.GetSlices(slice_filter = slice_hrn, slice_filter_type = 'slice_hrn')
149 self.synchronize_oar_and_slice_table_for_slice_hrn(slice_hrn, oar_leases_list, sfa_slices_list)
151 sfa_slices_list = self.GetSlices()
153 sfa_slices_dict_by_slice_hrn = {}
154 for sfa_slice in sfa_slices_list:
155 if sfa_slice['slice_hrn'] not in sfa_slices_dict_by_slice_hrn:
156 sfa_slices_dict_by_slice_hrn[sfa_slice['slice_hrn']] = []
157 sfa_slices_dict_by_slice_hrn[sfa_slice['slice_hrn']].append(sfa_slice)
159 sfa_slices_dict_by_slice_hrn[sfa_slice['slice_hrn']].append(sfa_slice)
161 for slice_hrn in sfa_slices_dict_by_slice_hrn:
162 list_slices_sfa = sfa_slices_dict_by_slice_hrn[slice_hrn]
163 if slice_hrn =='senslab2.avakian_slice':
164 logger.debug("SLABDRIVER \tsynchronize_oar_and_slice_table slice_hrn %s list_slices_sfa %s\r\n \r\n" %( slice_hrn,list_slices_sfa))
165 self.synchronize_oar_and_slice_table_for_slice_hrn(slice_hrn, oar_leases_list, list_slices_sfa)
170 def synchronize_oar_and_slice_table_for_slice_hrn(self,slice_hrn, oar_leases_list, sfa_slices_list):
172 #Get list of slices/leases . multiple entry per user depending on number of jobs
173 #sfa_slices_list = self.GetSlices(slice_filter = slice_hrn, slice_filter_type = 'slice_hrn')
176 login = slice_hrn.split(".")[1].split("_")[0]
178 #Create dictionnaries based on the tuple user login/ job id
179 #for the leases list and the slices list
181 for sl in sfa_slices_list:
182 if sl['oar_job_id'] != [] :
183 for oar_jobid in sl['oar_job_id']:
184 if (login, oar_jobid) not in sfa_slices_dict:
185 sfa_slices_dict[(login,oar_jobid)] = sl
187 for lease in oar_leases_list:
188 if (lease['user'], lease['lease_id']) not in oar_leases_dict:
189 oar_leases_dict[(lease['user'], lease['lease_id'])] = lease
191 #Find missing entries in the sfa slices list dict by comparing
192 #the keys in both dictionnaries
193 #Add the missing entries in the slice sneslab table
195 for lease in oar_leases_dict :
196 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))
197 if lease not in sfa_slices_dict and login == lease[0]:
199 #if lease in GetReservedNodes not in GetSlices update the db
200 #First get the list of nodes hostnames for this job
201 oar_reserved_nodes_listdict = oar_leases_dict[lease]['reserved_nodes']
202 oar_reserved_nodes_list = []
203 for node_dict in oar_reserved_nodes_listdict:
204 oar_reserved_nodes_list.append(node_dict['hostname'])
205 #And update the db with slice hrn, job id and node list
206 self.db.add_job(slice_hrn, lease[1], oar_reserved_nodes_list)
208 for lease in sfa_slices_dict:
209 #Job is now terminated or in Error, either way ot is not going to run again
210 #Remove it from the db
211 if lease not in oar_leases_dict:
212 self.db.delete_job( slice_hrn, lease[1])
216 def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, \
218 aggregate = SlabAggregate(self)
220 slices = SlabSlices(self)
221 peer = slices.get_peer(slice_hrn)
222 sfa_peer = slices.get_sfa_peer(slice_hrn)
225 if not isinstance(creds, list):
229 slice_record = users[0].get('slice_record', {})
232 rspec = RSpec(rspec_string)
233 logger.debug("SLABDRIVER.PY \tcreate_sliver \trspec.version %s " \
236 self.synchronize_oar_and_slice_table(slice_hrn)
237 # ensure site record exists?
238 # ensure slice record exists
239 sfa_slice = slices.verify_slice(slice_hrn, slice_record, peer, \
240 sfa_peer, options=options)
241 requested_attributes = rspec.version.get_slice_attributes()
243 logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice))
245 # ensure person records exists
246 persons = slices.verify_persons(slice_hrn, sfa_slice, users, peer, \
247 sfa_peer, options=options)
251 # add/remove slice from nodes
253 requested_slivers = [node.get('component_name') \
254 for node in rspec.version.get_nodes_with_slivers()]
255 l = [ node for node in rspec.version.get_nodes_with_slivers() ]
256 logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
257 requested_slivers %s listnodes %s" %(requested_slivers,l))
259 nodes = slices.verify_slice_nodes(sfa_slice, requested_slivers, peer)
262 requested_lease_list = []
264 for lease in rspec.version.get_leases():
265 single_requested_lease = {}
266 logger.debug("SLABDRIVER.PY \tcreate_sliver lease %s " %(lease))
267 if not lease.get('lease_id'):
268 single_requested_lease['hostname'] = \
269 slab_xrn_to_hostname(lease.get('component_id').strip())
270 single_requested_lease['start_time'] = lease.get('start_time')
271 single_requested_lease['duration'] = lease.get('duration')
273 kept_leases.append(int(lease['lease_id']))
274 if single_requested_lease.get('hostname'):
275 requested_lease_list.append(single_requested_lease)
277 #dCreate dict of leases by start_time, regrouping nodes reserved at the same
278 #time, for the same amount of time = one job on OAR
279 requested_job_dict = {}
280 for lease in requested_lease_list:
282 #In case it is an asap experiment start_time is empty
283 if lease['start_time'] == '':
284 lease['start_time'] = '0'
286 if lease['start_time'] not in requested_job_dict:
287 if isinstance(lease['hostname'], str):
288 lease['hostname'] = [lease['hostname']]
290 requested_job_dict[lease['start_time']] = lease
293 job_lease = requested_job_dict[lease['start_time']]
294 if lease['duration'] == job_lease['duration'] :
295 job_lease['hostname'].append(lease['hostname'])
300 logger.debug("SLABDRIVER.PY \tcreate_sliver requested_job_dict %s " %(requested_job_dict))
302 leases = slices.verify_slice_leases(sfa_slice, \
303 requested_job_dict, kept_leases, peer)
305 return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
308 def delete_sliver (self, slice_urn, slice_hrn, creds, options):
310 sfa_slice = self.GetSlices(slice_filter = slice_hrn, \
311 slice_filter_type = 'slice_hrn')
312 logger.debug("SLABDRIVER.PY delete_sliver slice %s" %(sfa_slice))
316 slices = SlabSlices(self)
317 # determine if this is a peer slice
319 peer = slices.get_peer(slice_hrn)
320 logger.debug("SLABDRIVER.PY delete_sliver peer %s" %(peer))
323 self.UnBindObjectFromPeer('slice', \
324 sfa_slice['record_id_slice'], peer)
325 self.DeleteSliceFromNodes(sfa_slice)
328 self.BindObjectToPeer('slice', sfa_slice['record_id_slice'], \
329 peer, sfa_slice['peer_slice_id'])
333 def AddSlice(self, slice_record):
334 slab_slice = SliceSenslab( slice_hrn = slice_record['slice_hrn'], \
335 record_id_slice= slice_record['record_id_slice'] , \
336 record_id_user= slice_record['record_id_user'], \
337 peer_authority = slice_record['peer_authority'])
338 logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s slab_slice %s" \
339 %(slice_record,slab_slice))
340 slab_dbsession.add(slab_slice)
341 slab_dbsession.commit()
344 # first 2 args are None in case of resource discovery
345 def list_resources (self, slice_urn, slice_hrn, creds, options):
346 #cached_requested = options.get('cached', True)
348 version_manager = VersionManager()
349 # get the rspec's return format from options
351 version_manager.get_version(options.get('geni_rspec_version'))
352 version_string = "rspec_%s" % (rspec_version)
354 #panos adding the info option to the caching key (can be improved)
355 if options.get('info'):
356 version_string = version_string + "_" + \
357 options.get('info', 'default')
359 # look in cache first
360 #if cached_requested and self.cache and not slice_hrn:
361 #rspec = self.cache.get(version_string)
363 #logger.debug("SlabDriver.ListResources: \
364 #returning cached advertisement")
367 #panos: passing user-defined options
368 aggregate = SlabAggregate(self)
369 origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
370 options.update({'origin_hrn':origin_hrn})
371 rspec = aggregate.get_rspec(slice_xrn=slice_urn, \
372 version=rspec_version, options=options)
375 #if self.cache and not slice_hrn:
376 #logger.debug("Slab.ListResources: stores advertisement in cache")
377 #self.cache.add(version_string, rspec)
382 def list_slices (self, creds, options):
383 # look in cache first
385 #slices = self.cache.get('slices')
387 #logger.debug("PlDriver.list_slices returns from cache")
392 slices = self.GetSlices()
393 logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices))
394 slice_hrns = [slab_slice['slice_hrn'] for slab_slice in slices]
395 #slice_hrns = [slicename_to_hrn(self.hrn, slab_slice['slice_hrn']) \
396 #for slab_slice in slices]
397 slice_urns = [hrn_to_urn(slice_hrn, 'slice') \
398 for slice_hrn in slice_hrns]
402 #logger.debug ("SlabDriver.list_slices stores value in cache")
403 #self.cache.add('slices', slice_urns)
407 #No site or node register supported
408 def register (self, sfa_record, hrn, pub_key):
409 record_type = sfa_record['type']
410 slab_record = self.sfa_fields_to_slab_fields(record_type, hrn, \
414 if record_type == 'slice':
415 acceptable_fields = ['url', 'instantiation', 'name', 'description']
416 for key in slab_record.keys():
417 if key not in acceptable_fields:
419 logger.debug("SLABDRIVER.PY register")
420 slices = self.GetSlices(slice_filter =slab_record['hrn'], \
421 slice_filter_type = 'slice_hrn')
423 pointer = self.AddSlice(slab_record)
425 pointer = slices[0]['slice_id']
427 elif record_type == 'user':
428 persons = self.GetPersons([sfa_record])
429 #persons = self.GetPersons([sfa_record['hrn']])
431 pointer = self.AddPerson(dict(sfa_record))
434 pointer = persons[0]['person_id']
436 #Does this make sense to senslab ?
437 #if 'enabled' in sfa_record and sfa_record['enabled']:
438 #self.UpdatePerson(pointer, \
439 #{'enabled': sfa_record['enabled']})
441 #TODO register Change this AddPersonToSite stuff 05/07/2012 SA
442 # add this person to the site only if
443 # she is being added for the first
444 # time by sfa and doesnt already exist in plc
445 if not persons or not persons[0]['site_ids']:
446 login_base = get_leaf(sfa_record['authority'])
447 self.AddPersonToSite(pointer, login_base)
449 # What roles should this user have?
450 #TODO : DElete this AddRoleToPerson 04/07/2012 SA
451 #Function prototype is :
452 #AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email)
453 #what's the pointer doing here?
454 self.AddRoleToPerson('user', pointer)
457 self.AddPersonKey(pointer, {'key_type' : 'ssh', \
460 #No node adding outside OAR
464 #No site or node record update allowed
465 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
466 pointer = old_sfa_record['pointer']
467 old_sfa_record_type = old_sfa_record['type']
469 # new_key implemented for users only
470 if new_key and old_sfa_record_type not in [ 'user' ]:
471 raise UnknownSfaType(old_sfa_record_type)
473 #if (type == "authority"):
474 #self.shell.UpdateSite(pointer, new_sfa_record)
476 if old_sfa_record_type == "slice":
477 slab_record = self.sfa_fields_to_slab_fields(old_sfa_record_type, \
479 if 'name' in slab_record:
480 slab_record.pop('name')
481 #Prototype should be UpdateSlice(self,
482 #auth, slice_id_or_name, slice_fields)
483 #Senslab cannot update slice since slice = job
484 #so we must delete and create another job
485 self.UpdateSlice(pointer, slab_record)
487 elif old_sfa_record_type == "user":
489 all_fields = new_sfa_record
490 for key in all_fields.keys():
491 if key in ['first_name', 'last_name', 'title', 'email',
492 'password', 'phone', 'url', 'bio', 'accepted_aup',
494 update_fields[key] = all_fields[key]
495 self.UpdatePerson(pointer, update_fields)
498 # must check this key against the previous one if it exists
499 persons = self.GetPersons([pointer], ['key_ids'])
501 keys = person['key_ids']
502 keys = self.GetKeys(person['key_ids'])
504 # Delete all stale keys
507 if new_key != key['key']:
508 self.DeleteKey(key['key_id'])
512 self.AddPersonKey(pointer, {'key_type': 'ssh', \
519 def remove (self, sfa_record):
520 sfa_record_type = sfa_record['type']
521 hrn = sfa_record['hrn']
522 record_id = sfa_record['record_id']
523 if sfa_record_type == 'user':
525 #get user from senslab ldap
526 person = self.GetPersons(sfa_record)
527 #No registering at a given site in Senslab.
528 #Once registered to the LDAP, all senslab sites are
531 #Mark account as disabled in ldap
532 self.DeletePerson(sfa_record)
533 elif sfa_record_type == 'slice':
534 if self.GetSlices(slice_filter = hrn, \
535 slice_filter_type = 'slice_hrn'):
536 self.DeleteSlice(sfa_record_type)
538 #elif type == 'authority':
539 #if self.GetSites(pointer):
540 #self.DeleteSite(pointer)
546 #TODO clean GetPeers. 05/07/12SA
547 def GetPeers (self, auth = None, peer_filter=None, return_fields_list=None):
549 existing_records = {}
550 existing_hrns_by_types = {}
551 logger.debug("SLABDRIVER \tGetPeers auth = %s, peer_filter %s, \
552 return_field %s " %(auth , peer_filter, return_fields_list))
553 all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
554 for record in all_records:
555 existing_records[(record.hrn, record.type)] = record
556 if record.type not in existing_hrns_by_types:
557 existing_hrns_by_types[record.type] = [record.hrn]
558 logger.debug("SLABDRIVER \tGetPeer\t NOT IN \
559 existing_hrns_by_types %s " %( existing_hrns_by_types))
562 logger.debug("SLABDRIVER \tGetPeer\t \INNN type %s hrn %s " \
563 %(record.type,record.hrn))
564 existing_hrns_by_types[record.type].append(record.hrn)
567 logger.debug("SLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
568 %( existing_hrns_by_types))
573 records_list.append(existing_records[(peer_filter,'authority')])
575 for hrn in existing_hrns_by_types['authority']:
576 records_list.append(existing_records[(hrn,'authority')])
578 logger.debug("SLABDRIVER \tGetPeer \trecords_list %s " \
584 return_records = records_list
585 if not peer_filter and not return_fields_list:
589 logger.debug("SLABDRIVER \tGetPeer return_records %s " \
591 return return_records
594 #TODO : Handling OR request in make_ldap_filters_from_records
595 #instead of the for loop
596 #over the records' list
597 def GetPersons(self, person_filter=None, return_fields_list=None):
599 person_filter should be a list of dictionnaries when not set to None.
600 Returns a list of users whose accounts are enabled found in ldap.
603 logger.debug("SLABDRIVER \tGetPersons person_filter %s" \
606 if person_filter and isinstance(person_filter, list):
607 #If we are looking for a list of users (list of dict records)
608 #Usually the list contains only one user record
609 for searched_attributes in person_filter:
611 #Get only enabled user accounts in senslab LDAP :
612 #add a filter for make_ldap_filters_from_record
613 person = self.ldap.LdapFindUser(searched_attributes, \
614 is_user_enabled=True)
615 person_list.append(person)
618 #Get only enabled user accounts in senslab LDAP :
619 #add a filter for make_ldap_filters_from_record
620 person_list = self.ldap.LdapFindUser(is_user_enabled=True)
624 def GetTimezone(self):
625 server_timestamp, server_tz = self.oar.parser.\
626 SendRequest("GET_timezone")
627 return server_timestamp, server_tz
630 def DeleteJobs(self, job_id, slice_hrn):
631 if not job_id or job_id is -1:
633 username = slice_hrn.split(".")[-1].rstrip("_slice")
635 reqdict['method'] = "delete"
636 reqdict['strval'] = str(job_id)
638 self.db.delete_job(slice_hrn, job_id)
639 answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id', \
641 logger.debug("SLABDRIVER \tDeleteJobs jobid %s \r\n answer %s username %s" \
642 %(job_id,answer, username))
647 ##TODO : Unused GetJobsId ? SA 05/07/12
648 #def GetJobsId(self, job_id, username = None ):
650 #Details about a specific job.
651 #Includes details about submission time, jot type, state, events,
652 #owner, assigned ressources, walltime etc...
656 #node_list_k = 'assigned_network_address'
657 ##Get job info from OAR
658 #job_info = self.oar.parser.SendRequest(req, job_id, username)
660 #logger.debug("SLABDRIVER \t GetJobsId %s " %(job_info))
662 #if job_info['state'] == 'Terminated':
663 #logger.debug("SLABDRIVER \t GetJobsId job %s TERMINATED"\
666 #if job_info['state'] == 'Error':
667 #logger.debug("SLABDRIVER \t GetJobsId ERROR message %s "\
672 #logger.error("SLABDRIVER \tGetJobsId KeyError")
675 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
677 ##Replaces the previous entry
678 ##"assigned_network_address" / "reserved_resources"
680 #job_info.update({'node_ids':parsed_job_info[node_list_k]})
681 #del job_info[node_list_k]
682 #logger.debug(" \r\nSLABDRIVER \t GetJobsId job_info %s " %(job_info))
686 def GetJobsResources(self, job_id, username = None):
687 #job_resources=['reserved_resources', 'assigned_resources',\
688 #'job_id', 'job_uri', 'assigned_nodes',\
690 #assigned_res = ['resource_id', 'resource_uri']
691 #assigned_n = ['node', 'node_uri']
693 req = "GET_jobs_id_resources"
694 node_list_k = 'reserved_resources'
696 #Get job resources list from OAR
697 node_id_list = self.oar.parser.SendRequest(req, job_id, username)
698 logger.debug("SLABDRIVER \t GetJobsResources %s " %(node_id_list))
701 self.__get_hostnames_from_oar_node_ids(node_id_list)
703 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
705 #Replaces the previous entry "assigned_network_address" /
706 #"reserved_resources"
708 job_info = {'node_ids': hostname_list}
713 def get_info_on_reserved_nodes(self, job_info, node_list_name):
714 #Get the list of the testbed nodes records and make a
715 #dictionnary keyed on the hostname out of it
716 node_list_dict = self.GetNodes()
717 #node_hostname_list = []
718 node_hostname_list = [node['hostname'] for node in node_list_dict]
719 #for node in node_list_dict:
720 #node_hostname_list.append(node['hostname'])
721 node_dict = dict(zip(node_hostname_list, node_list_dict))
723 reserved_node_hostname_list = []
724 for index in range(len(job_info[node_list_name])):
725 #job_info[node_list_name][k] =
726 reserved_node_hostname_list[index] = \
727 node_dict[job_info[node_list_name][index]]['hostname']
729 logger.debug("SLABDRIVER \t get_info_on_reserved_nodes \
730 reserved_node_hostname_list %s" \
731 %(reserved_node_hostname_list))
733 logger.error("SLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
735 return reserved_node_hostname_list
737 def GetNodesCurrentlyInUse(self):
738 """Returns a list of all the nodes already involved in an oar job"""
739 return self.oar.parser.SendRequest("GET_running_jobs")
741 def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
742 full_nodes_dict_list = self.GetNodes()
743 #Put the full node list into a dictionary keyed by oar node id
744 oar_id_node_dict = {}
745 for node in full_nodes_dict_list:
746 oar_id_node_dict[node['oar_id']] = node
748 logger.debug("SLABDRIVER \t __get_hostnames_from_oar_node_ids\
749 oar_id_node_dict %s" %(oar_id_node_dict))
751 hostname_dict_list = []
752 for resource_id in resource_id_list:
753 #Because jobs requested "asap" do not have defined resources
754 if resource_id is not "Undefined":
755 hostname_dict_list.append({'hostname' : \
756 oar_id_node_dict[resource_id]['hostname'],
757 'site_id' : oar_id_node_dict[resource_id]['site']})
759 #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
760 return hostname_dict_list
762 def GetReservedNodes(self):
763 #Get the nodes in use and the reserved nodes
764 reservation_dict_list = \
765 self.oar.parser.SendRequest("GET_reserved_nodes")
768 for resa in reservation_dict_list:
769 logger.debug ("GetReservedNodes resa %s"%(resa))
770 #dict list of hostnames and their site
771 resa['reserved_nodes'] = \
772 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
774 #del resa['resource_ids']
775 return reservation_dict_list
777 def GetNodes(self, node_filter_dict = None, return_fields_list = None):
779 node_filter_dict : dictionnary of lists
782 node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
783 node_dict_list = node_dict_by_id.values()
785 #No filtering needed return the list directly
786 if not (node_filter_dict or return_fields_list):
787 return node_dict_list
789 return_node_list = []
791 for filter_key in node_filter_dict:
793 #Filter the node_dict_list by each value contained in the
794 #list node_filter_dict[filter_key]
795 for value in node_filter_dict[filter_key]:
796 for node in node_dict_list:
797 if node[filter_key] == value:
798 if return_fields_list :
800 for k in return_fields_list:
802 return_node_list.append(tmp)
804 return_node_list.append(node)
806 logger.log_exc("GetNodes KeyError")
810 return return_node_list
813 def GetSites(self, site_filter_name_list = None, return_fields_list = None):
814 site_dict = self.oar.parser.SendRequest("GET_sites")
815 #site_dict : dict where the key is the sit ename
816 return_site_list = []
817 if not ( site_filter_name_list or return_fields_list):
818 return_site_list = site_dict.values()
819 return return_site_list
821 for site_filter_name in site_filter_name_list:
822 if site_filter_name in site_dict:
823 if return_fields_list:
824 for field in return_fields_list:
827 tmp[field] = site_dict[site_filter_name][field]
829 logger.error("GetSites KeyError %s "%(field))
831 return_site_list.append(tmp)
833 return_site_list.append( site_dict[site_filter_name])
836 return return_site_list
837 #warning return_fields_list paramr emoved (Not used)
838 def GetSlices(self, slice_filter = None, slice_filter_type = None):
839 #def GetSlices(self, slice_filter = None, slice_filter_type = None, \
840 #return_fields_list = None):
841 """ Get the slice records from the slab db.
842 Returns a slice ditc if slice_filter and slice_filter_type
844 Returns a list of slice dictionnaries if there are no filters
849 return_slice_list = []
852 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
854 if slice_filter_type in authorized_filter_types_list:
855 #Get list of slices based on the slice hrn
856 if slice_filter_type == 'slice_hrn':
858 login = slice_filter.split(".")[1].split("_")[0]
860 #DO NOT USE RegSlice - reg_researchers to get the hrn of the user
861 #otherwise will mess up the RegRecord in Resolve, don't know
864 #Only one entry for one user = one slice in slice_senslab table
865 slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).first()
867 #Get slice based on user id
868 if slice_filter_type == 'record_id_user':
869 slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).first()
874 #slicerec_dictlist = []
875 slicerec_dict = slicerec.dump_sqlalchemyobj_to_dict()
877 login = slicerec_dict['slice_hrn'].split(".")[1].split("_")[0]
879 #for record in slicerec:
880 #slicerec_dictlist.append(record.dump_sqlalchemyobj_to_dict())
882 #login = slicerec_dictlist[0]['slice_hrn'].split(".")[1].split("_")[0]
884 #One slice can have multiple jobs
885 sqljob_list = slab_dbsession.query(JobSenslab).filter_by( slice_hrn=slicerec_dict['slice_hrn']).all()
887 for job in sqljob_list:
888 job_list.append(job.dump_sqlalchemyobj_to_dict())
890 logger.debug("\r\n SLABDRIVER \tGetSlices login %s \
892 %(login, slicerec_dict))
894 #Several jobs for one slice
895 slicerec_dict['oar_job_id'] = []
896 for job in job_list :
897 #if slicerec_dict['oar_job_id'] is not -1:
898 #Check with OAR the status of the job if a job id is in
901 rslt = self.GetJobsResources(job['oar_job_id'], \
903 logger.debug("SLABDRIVER.PY \tGetSlices rslt fromn GetJobsResources %s"\
906 slicerec_dict['oar_job_id'].append(job['oar_job_id'])
907 slicerec_dict.update(rslt)
908 slicerec_dict.update({'hrn':\
909 str(slicerec_dict['slice_hrn'])})
910 #If GetJobsResources is empty, this means the job is
911 #now in the 'Terminated' state
912 #Update the slice record
914 self.db.delete_job(slice_filter, job['oar_job_id'])
916 update({'hrn':str(slicerec_dict['slice_hrn'])})
919 slicerec_dict['node_ids'] = job['node_list']
923 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slicerec_dict %s"\
926 return [slicerec_dict]
930 slice_list = slab_dbsession.query(SliceSenslab).all()
931 sqljob_list = slab_dbsession.query(JobSenslab).all()
934 for job in sqljob_list:
935 job_list.append(job.dump_sqlalchemyobj_to_dict())
937 return_slice_list = []
938 for record in slice_list:
939 return_slice_list.append(record.dump_sqlalchemyobj_to_dict())
941 for slicerec_dict in return_slice_list:
942 slicerec_dict['oar_job_id'] = []
944 if slicerec_dict['slice_hrn'] in job:
945 slicerec_dict['oar_job_id'].append(job['oar_job_id'])
947 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slices %s \
948 slice_filter %s " %(return_slice_list, slice_filter))
950 #if return_fields_list:
951 #return_slice_list = parse_filter(sliceslist, \
952 #slice_filter,'slice', return_fields_list)
954 return return_slice_list
960 def testbed_name (self): return self.hrn
962 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
963 def aggregate_version (self):
964 version_manager = VersionManager()
965 ad_rspec_versions = []
966 request_rspec_versions = []
967 for rspec_version in version_manager.versions:
968 if rspec_version.content_type in ['*', 'ad']:
969 ad_rspec_versions.append(rspec_version.to_dict())
970 if rspec_version.content_type in ['*', 'request']:
971 request_rspec_versions.append(rspec_version.to_dict())
973 'testbed':self.testbed_name(),
974 'geni_request_rspec_versions': request_rspec_versions,
975 'geni_ad_rspec_versions': ad_rspec_versions,
984 # Convert SFA fields to PLC fields for use when registering up updating
985 # registry record in the PLC database
987 # @param type type of record (user, slice, ...)
988 # @param hrn human readable name
989 # @param sfa_fields dictionary of SFA fields
990 # @param slab_fields dictionary of PLC fields (output)
992 def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
994 def convert_ints(tmpdict, int_fields):
995 for field in int_fields:
997 tmpdict[field] = int(tmpdict[field])
1000 #for field in record:
1001 # slab_record[field] = record[field]
1003 if sfa_type == "slice":
1004 #instantion used in get_slivers ?
1005 if not "instantiation" in slab_record:
1006 slab_record["instantiation"] = "senslab-instantiated"
1007 #slab_record["hrn"] = hrn_to_pl_slicename(hrn)
1008 #Unused hrn_to_pl_slicename because Slab's hrn already in the appropriate form SA 23/07/12
1009 slab_record["hrn"] = hrn
1010 logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
1011 slab_record %s " %(slab_record['hrn']))
1013 slab_record["url"] = record["url"]
1014 if "description" in record:
1015 slab_record["description"] = record["description"]
1016 if "expires" in record:
1017 slab_record["expires"] = int(record["expires"])
1019 #nodes added by OAR only and then imported to SFA
1020 #elif type == "node":
1021 #if not "hostname" in slab_record:
1022 #if not "hostname" in record:
1023 #raise MissingSfaInfo("hostname")
1024 #slab_record["hostname"] = record["hostname"]
1025 #if not "model" in slab_record:
1026 #slab_record["model"] = "geni"
1029 #elif type == "authority":
1030 #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
1032 #if not "name" in slab_record:
1033 #slab_record["name"] = hrn
1035 #if not "abbreviated_name" in slab_record:
1036 #slab_record["abbreviated_name"] = hrn
1038 #if not "enabled" in slab_record:
1039 #slab_record["enabled"] = True
1041 #if not "is_public" in slab_record:
1042 #slab_record["is_public"] = True
1049 def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
1050 """ Transforms unix timestamp into valid OAR date format """
1052 #Used in case of a scheduled experiment (not immediate)
1053 #To run an XP immediately, don't specify date and time in RSpec
1054 #They will be set to None.
1055 if xp_utc_timestamp:
1056 #transform the xp_utc_timestamp into server readable time
1057 xp_server_readable_date = datetime.fromtimestamp(int(\
1058 xp_utc_timestamp)).strftime(self.time_format)
1060 return xp_server_readable_date
1068 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
1069 lease_start_time, lease_duration, slice_user=None):
1071 lease_dict['lease_start_time'] = lease_start_time
1072 lease_dict['lease_duration'] = lease_duration
1073 lease_dict['added_nodes'] = added_nodes
1074 lease_dict['slice_name'] = slice_name
1075 lease_dict['slice_user'] = slice_user
1076 lease_dict['grain'] = self.GetLeaseGranularity()
1077 lease_dict['time_format'] = self.time_format
1079 def __create_job_structure_request_for_OAR(lease_dict):
1080 """ Creates the structure needed for a correct POST on OAR.
1081 Makes the timestamp transformation into the appropriate format.
1082 Sends the POST request to create the job with the resources in
1093 reqdict['workdir'] = '/tmp'
1094 reqdict['resource'] = "{network_address in ("
1096 for node in lease_dict['added_nodes']:
1097 logger.debug("\r\n \r\n OARrestapi \t __create_job_structure_request_for_OAR \
1100 # Get the ID of the node
1102 reqdict['resource'] += "'" + nodeid + "', "
1103 nodeid_list.append(nodeid)
1105 custom_length = len(reqdict['resource'])- 2
1106 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
1107 ")}/nodes=" + str(len(nodeid_list))
1109 def __process_walltime(duration):
1110 """ Calculates the walltime in seconds from the duration in H:M:S
1111 specified in the RSpec.
1115 # Fixing the walltime by adding a few delays.
1116 # First put the walltime in seconds oarAdditionalDelay = 20;
1117 # additional delay for /bin/sleep command to
1118 # take in account prologue and epilogue scripts execution
1119 # int walltimeAdditionalDelay = 120; additional delay
1120 desired_walltime = duration
1121 total_walltime = desired_walltime + 140#+2 min 20
1122 sleep_walltime = desired_walltime + 20 #+20 sec
1124 #Put the walltime back in str form
1125 #First get the hours
1126 walltime.append(str(total_walltime / 3600))
1127 total_walltime = total_walltime - 3600 * int(walltime[0])
1128 #Get the remaining minutes
1129 walltime.append(str(total_walltime / 60))
1130 total_walltime = total_walltime - 60 * int(walltime[1])
1132 walltime.append(str(total_walltime))
1135 logger.log_exc(" __process_walltime duration null")
1137 return walltime, sleep_walltime
1140 walltime, sleep_walltime = \
1141 __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1144 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1145 ":" + str(walltime[1]) + ":" + str(walltime[2])
1146 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1148 #In case of a scheduled experiment (not immediate)
1149 #To run an XP immediately, don't specify date and time in RSpec
1150 #They will be set to None.
1151 if lease_dict['lease_start_time'] is not '0':
1152 #Readable time accepted by OAR
1153 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1154 strftime(lease_dict['time_format'])
1155 reqdict['reservation'] = start_time
1156 #If there is not start time, Immediate XP. No need to add special
1160 reqdict['type'] = "deploy"
1161 reqdict['directory'] = ""
1162 reqdict['name'] = "SFA_" + lease_dict['slice_user']
1167 #Create the request for OAR
1168 reqdict = __create_job_structure_request_for_OAR(lease_dict)
1169 # first step : start the OAR job and update the job
1170 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1173 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1174 reqdict, slice_user)
1175 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s " %(answer))
1177 jobid = answer['id']
1179 logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1180 Impossible to create job %s " %(answer))
1184 def __configure_experiment(jobid, added_nodes):
1185 # second step : configure the experiment
1186 # we need to store the nodes in a yaml (well...) file like this :
1187 # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1188 job_file = open('/tmp/sfa/'+ str(jobid) + '.json', 'w')
1190 job_file.write(str(added_nodes[0].strip('node')))
1191 for node in added_nodes[1:len(added_nodes)] :
1192 job_file.write(', '+ node.strip('node'))
1197 def __launch_senslab_experiment(jobid):
1198 # third step : call the senslab-experiment wrapper
1199 #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar
1200 # "+str(jobid)+" "+slice_user
1201 javacmdline = "/usr/bin/java"
1203 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1204 #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", \
1205 #str(jobid), slice_user])
1206 output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1207 slice_user],stdout=subprocess.PIPE).communicate()[0]
1209 logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1216 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1217 added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1218 self.db.add_job( slice_name, jobid, added_nodes)
1220 __configure_experiment(jobid, added_nodes)
1221 __launch_senslab_experiment(jobid)
1225 def AddLeases(self, hostname_list, slice_record, lease_start_time, lease_duration):
1226 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s \
1227 slice_record %s lease_start_time %s lease_duration %s "\
1228 %( hostname_list, slice_record , lease_start_time, \
1231 tmp = slice_record['PI'][0].split(".")
1232 username = tmp[(len(tmp)-1)]
1233 self.LaunchExperimentOnOAR(hostname_list, slice_record['name'], lease_start_time, lease_duration, username)
1234 start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1235 logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1240 #Delete the jobs and updates the job id in the senslab table
1242 #Does not clear the node list
1243 def DeleteSliceFromNodes(self, slice_record):
1244 # Get user information
1246 self.DeleteJobs(slice_record['oar_job_id'], slice_record['hrn'])
1251 def GetLeaseGranularity(self):
1252 """ Returns the granularity of Senslab testbed.
1253 Defined in seconds. """
1258 def GetLeases(self, lease_filter_dict=None, return_fields_list=None):
1259 unfiltered_reservation_list = self.GetReservedNodes()
1261 ##Synchronize slice_table of sfa senslab db
1262 #self.synchronize_oar_and_slice_table(unfiltered_reservation_list)
1264 reservation_list = []
1265 #Find the slice associated with this user senslab ldap uid
1266 logger.debug(" SLABDRIVER.PY \tGetLeases ")
1267 #Create user dict first to avoir looking several times for
1268 #the same user in LDAP SA 27/07/12
1270 for resa in unfiltered_reservation_list:
1271 logger.debug("SLABDRIVER \tGetLeases USER %s"\
1273 if resa['user'] not in resa_user_dict:
1274 logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1275 ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1276 ldap_info = ldap_info[0][1]
1277 user = dbsession.query(RegUser).filter_by(email = \
1278 ldap_info['mail'][0]).first()
1279 #Separated in case user not in database : record_id not defined SA 17/07//12
1280 query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1281 if query_slice_info:
1282 slice_info = query_slice_info.first()
1286 resa_user_dict[resa['user']] = {}
1287 resa_user_dict[resa['user']]['ldap_info'] = user
1288 resa_user_dict[resa['user']]['slice_info'] = slice_info
1290 logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1292 for resa in unfiltered_reservation_list:
1294 #ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1295 #ldap_info = ldap_info[0][1]
1297 #user = dbsession.query(RegUser).filter_by(email = \
1298 #ldap_info['mail'][0]).first()
1299 ##Separated in case user not in database : record_id not defined SA 17/07//12
1300 #query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1301 #if query_slice_info:
1302 #slice_info = query_slice_info.first()
1304 resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info'].slice_hrn
1305 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1307 #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1308 resa['component_id_list'] = []
1309 #Transform the hostnames into urns (component ids)
1310 for node in resa['reserved_nodes']:
1311 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1312 #self.root_auth, node['hostname']))
1313 slab_xrn = slab_xrn_object(self.root_auth, node['hostname'])
1314 resa['component_id_list'].append(slab_xrn.urn)
1316 #Filter the reservation list if necessary
1317 #Returns all the leases associated with a given slice
1318 if lease_filter_dict:
1319 logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1320 %(lease_filter_dict))
1321 for resa in unfiltered_reservation_list:
1322 if lease_filter_dict['name'] == resa['slice_hrn']:
1323 reservation_list.append(resa)
1325 reservation_list = unfiltered_reservation_list
1327 logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1328 %(reservation_list))
1329 return reservation_list
1331 def augment_records_with_testbed_info (self, sfa_records):
1332 return self.fill_record_info (sfa_records)
1334 def fill_record_info(self, record_list):
1336 Given a SFA record, fill in the senslab specific and SFA specific
1337 fields in the record.
1340 logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1341 if not isinstance(record_list, list):
1342 record_list = [record_list]
1345 for record in record_list:
1346 #If the record is a SFA slice record, then add information
1347 #about the user of this slice. This kind of
1348 #information is in the Senslab's DB.
1349 if str(record['type']) == 'slice':
1350 #Get slab slice record.
1351 recslice_list = self.GetSlices(slice_filter = \
1352 str(record['hrn']),\
1353 slice_filter_type = 'slice_hrn')
1355 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1356 recslice_list[0]['record_id_user']).first()
1357 logger.debug("SLABDRIVER \tfill_record_info TYPE SLICE RECUSER %s " %(recuser))
1358 record.update({'PI':[recuser.hrn],
1359 'researcher': [recuser.hrn],
1360 'name':record['hrn'],
1361 'oar_job_id':[rec['oar_job_id'] for rec in recslice_list],
1363 'person_ids':[recslice_list[0]['record_id_user']],
1364 'geni_urn':'', #For client_helper.py compatibility
1365 'keys':'', #For client_helper.py compatibility
1366 'key_ids':''}) #For client_helper.py compatibility
1368 #for rec in recslice_list:
1369 #record['oar_job_id'].append(rec['oar_job_id'])
1370 logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1371 recslice_list %s \r\n \t RECORD %s \r\n \r\n" %(recslice_list,record))
1372 if str(record['type']) == 'user':
1373 #The record is a SFA user record.
1374 #Get the information about his slice from Senslab's DB
1375 #and add it to the user record.
1376 recslice_list = self.GetSlices(\
1377 slice_filter = record['record_id'],\
1378 slice_filter_type = 'record_id_user')
1380 logger.debug( "SLABDRIVER.PY \t fill_record_info TYPE USER \
1381 recslice_list %s \r\n \t RECORD %s \r\n" %(recslice_list , record))
1382 #Append slice record in records list,
1383 #therefore fetches user and slice info again(one more loop)
1384 #Will update PIs and researcher for the slice
1385 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1386 recslice_list[0]['record_id_user']).first()
1387 logger.debug( "SLABDRIVER.PY \t fill_record_info USER \
1388 recuser %s \r\n \r\n" %(recuser))
1390 recslice = recslice_list[0]
1391 recslice.update({'PI':[recuser.hrn],
1392 'researcher': [recuser.hrn],
1393 'name':record['hrn'],
1395 'oar_job_id': [rec['oar_job_id'] for rec in recslice_list],
1396 'person_ids':[recslice_list[0]['record_id_user']]})
1397 recslice.update({'type':'slice', \
1398 'hrn':recslice_list[0]['slice_hrn']})
1399 #for rec in recslice_list:
1400 #recslice['oar_job_id'].append(rec['oar_job_id'])
1402 #GetPersons takes [] as filters
1403 #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1404 user_slab = self.GetPersons([record])
1407 record.update(user_slab[0])
1408 #For client_helper.py compatibility
1409 record.update( { 'geni_urn':'',
1412 record_list.append(recslice)
1414 logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1415 INFO TO USER records %s" %(record_list))
1416 logger.debug("SLABDRIVER.PY \tfill_record_info END \
1417 #record %s \r\n \r\n " %(record))
1419 except TypeError, error:
1420 logger.log_exc("SLABDRIVER \t fill_record_info EXCEPTION %s"\
1422 #logger.debug("SLABDRIVER.PY \t fill_record_info ENDENDEND ")
1426 #self.fill_record_slab_info(records)
1432 #TODO Update membership? update_membership_list SA 05/07/12
1433 #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1435 ## get a list of the HRNs tht are members of the old and new records
1437 #oldList = oldRecord.get(listName, [])
1440 #newList = record.get(listName, [])
1442 ## if the lists are the same, then we don't have to update anything
1443 #if (oldList == newList):
1446 ## build a list of the new person ids, by looking up each person to get
1450 #records = table.find({'type': 'user', 'hrn': newList})
1451 #for rec in records:
1452 #newIdList.append(rec['pointer'])
1454 ## build a list of the old person ids from the person_ids field
1456 #oldIdList = oldRecord.get("person_ids", [])
1457 #containerId = oldRecord.get_pointer()
1459 ## if oldRecord==None, then we are doing a Register, instead of an
1462 #containerId = record.get_pointer()
1464 ## add people who are in the new list, but not the oldList
1465 #for personId in newIdList:
1466 #if not (personId in oldIdList):
1467 #addFunc(self.plauth, personId, containerId)
1469 ## remove people who are in the old list, but not the new list
1470 #for personId in oldIdList:
1471 #if not (personId in newIdList):
1472 #delFunc(self.plauth, personId, containerId)
1474 #def update_membership(self, oldRecord, record):
1476 #if record.type == "slice":
1477 #self.update_membership_list(oldRecord, record, 'researcher',
1478 #self.users.AddPersonToSlice,
1479 #self.users.DeletePersonFromSlice)
1480 #elif record.type == "authority":
1485 # I don't think you plan on running a component manager at this point
1486 # let me clean up the mess of ComponentAPI that is deprecated anyways
1489 #TODO FUNCTIONS SECTION 04/07/2012 SA
1491 #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1493 def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1494 """ This method is a hopefully temporary hack to let the sfa correctly
1495 detach the objects it creates from a remote peer object. This is
1496 needed so that the sfa federation link can work in parallel with
1497 RefreshPeer, as RefreshPeer depends on remote objects being correctly
1500 auth : struct, API authentication structure
1501 AuthMethod : string, Authentication method to use
1502 object_type : string, Object type, among 'site','person','slice',
1504 object_id : int, object_id
1505 shortname : string, peer shortname
1509 logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1513 #TODO Is BindObjectToPeer still necessary ? Currently does nothing
1515 def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1516 remote_object_id=None):
1517 """This method is a hopefully temporary hack to let the sfa correctly
1518 attach the objects it creates to a remote peer object. This is needed
1519 so that the sfa federation link can work in parallel with RefreshPeer,
1520 as RefreshPeer depends on remote objects being correctly marked.
1522 shortname : string, peer shortname
1523 remote_object_id : int, remote object_id, set to 0 if unknown
1527 logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1530 #TODO UpdateSlice 04/07/2012 SA
1531 #Funciton should delete and create another job since oin senslab slice=job
1532 def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1533 """Updates the parameters of an existing slice with the values in
1535 Users may only update slices of which they are members.
1536 PIs may update any of the slices at their sites, or any slices of
1537 which they are members. Admins may update any slice.
1538 Only PIs and admins may update max_nodes. Slices cannot be renewed
1539 (by updating the expires parameter) more than 8 weeks into the future.
1540 Returns 1 if successful, faults otherwise.
1544 logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1547 #TODO UpdatePerson 04/07/2012 SA
1548 def UpdatePerson(self, auth, person_id_or_email, person_fields=None):
1549 """Updates a person. Only the fields specified in person_fields
1550 are updated, all other fields are left untouched.
1551 Users and techs can only update themselves. PIs can only update
1552 themselves and other non-PIs at their sites.
1553 Returns 1 if successful, faults otherwise.
1557 logger.warning("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1560 #TODO GetKeys 04/07/2012 SA
1561 def GetKeys(self, auth, key_filter=None, return_fields=None):
1562 """Returns an array of structs containing details about keys.
1563 If key_filter is specified and is an array of key identifiers,
1564 or a struct of key attributes, only keys matching the filter
1565 will be returned. If return_fields is specified, only the
1566 specified details will be returned.
1568 Admin may query all keys. Non-admins may only query their own keys.
1572 logger.warning("SLABDRIVER GetKeys EMPTY - DO NOTHING \r\n ")
1575 #TODO DeleteKey 04/07/2012 SA
1576 def DeleteKey(self, auth, key_id):
1578 Non-admins may only delete their own keys.
1579 Returns 1 if successful, faults otherwise.
1583 logger.warning("SLABDRIVER DeleteKey EMPTY - DO NOTHING \r\n ")
1587 #TODO : Check rights to delete person
1588 def DeletePerson(self, auth, person_record):
1589 """ Disable an existing account in senslab LDAP.
1590 Users and techs can only delete themselves. PIs can only
1591 delete themselves and other non-PIs at their sites.
1592 ins can delete anyone.
1593 Returns 1 if successful, faults otherwise.
1597 #Disable user account in senslab LDAP
1598 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1599 logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1602 #TODO Check DeleteSlice, check rights 05/07/2012 SA
1603 def DeleteSlice(self, auth, slice_record):
1604 """ Deletes the specified slice.
1605 Senslab : Kill the job associated with the slice if there is one
1606 using DeleteSliceFromNodes.
1607 Updates the slice record in slab db to remove the slice nodes.
1609 Users may only delete slices of which they are members. PIs may
1610 delete any of the slices at their sites, or any slices of which
1611 they are members. Admins may delete any slice.
1612 Returns 1 if successful, faults otherwise.
1616 self.DeleteSliceFromNodes(slice_record)
1617 logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1620 #TODO AddPerson 04/07/2012 SA
1621 def AddPerson(self, auth, person_fields=None):
1622 """Adds a new account. Any fields specified in person_fields are used,
1623 otherwise defaults are used.
1624 Accounts are disabled by default. To enable an account,
1626 Returns the new person_id (> 0) if successful, faults otherwise.
1630 logger.warning("SLABDRIVER AddPerson EMPTY - DO NOTHING \r\n ")
1633 #TODO AddPersonToSite 04/07/2012 SA
1634 def AddPersonToSite (self, auth, person_id_or_email, \
1635 site_id_or_login_base=None):
1636 """ Adds the specified person to the specified site. If the person is
1637 already a member of the site, no errors are returned. Does not change
1638 the person's primary site.
1639 Returns 1 if successful, faults otherwise.
1643 logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1646 #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1647 def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1648 """Grants the specified role to the person.
1649 PIs can only grant the tech and user roles to users and techs at their
1650 sites. Admins can grant any role to any user.
1651 Returns 1 if successful, faults otherwise.
1655 logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1658 #TODO AddPersonKey 04/07/2012 SA
1659 def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1660 """Adds a new key to the specified account.
1661 Non-admins can only modify their own keys.
1662 Returns the new key_id (> 0) if successful, faults otherwise.
1666 logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1669 def DeleteLeases(self, leases_id_list, slice_hrn ):
1670 for job_id in leases_id_list:
1671 self.DeleteJobs(job_id, slice_hrn)
1673 logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \r\n " %(leases_id_list, slice_hrn))