4 from datetime import datetime
6 from sfa.util.faults import SliverDoesNotExist, UnknownSfaType
7 from sfa.util.sfalogging import logger
8 from sfa.storage.alchemy import dbsession
9 from sfa.storage.model import RegRecord, RegUser, RegSlice
10 from sqlalchemy.orm import joinedload
13 from sfa.managers.driver import Driver
14 from sfa.rspecs.version_manager import VersionManager
15 from sfa.rspecs.rspec import RSpec
17 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority
20 ## thierry: everything that is API-related (i.e. handling incoming requests)
22 # SlabDriver should be really only about talking to the senslab testbed
25 from sfa.senslab.OARrestapi import OARrestapi
26 from sfa.senslab.LDAPapi import LDAPapi
28 from sfa.senslab.slabpostgres import SlabDB, slab_dbsession, SenslabXP
31 from sfa.senslab.slabaggregate import SlabAggregate, slab_xrn_to_hostname, \
33 from sfa.senslab.slabslices import SlabSlices
38 # this inheritance scheme is so that the driver object can receive
39 # GetNodes or GetSites sorts of calls directly
40 # and thus minimize the differences in the managers with the pl version
44 class SlabDriver(Driver):
45 """ Senslab Driver class inherited from Driver generic class.
47 Contains methods compliant with the SFA standard and the testbed
48 infrastructure (calls to LDAP and OAR).
50 def __init__(self, config):
51 Driver.__init__ (self, config)
53 self.hrn = config.SFA_INTERFACE_HRN
54 self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
55 self.oar = OARrestapi()
57 self.time_format = "%Y-%m-%d %H:%M:%S"
58 self.db = SlabDB(config, debug = False)
62 def sliver_status(self, slice_urn, slice_hrn):
63 """Receive a status request for slice named urn/hrn
64 urn:publicid:IDN+senslab+nturro_slice hrn senslab.nturro_slice
65 shall return a structure as described in
66 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
67 NT : not sure if we should implement this or not, but used by sface.
71 #First get the slice with the slice hrn
72 slice_list = self.GetSlices(slice_filter = slice_hrn, \
73 slice_filter_type = 'slice_hrn')
75 if len(slice_list) is 0:
76 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
78 #Slice has the same slice hrn for each slice in the slice/lease list
79 #So fetch the info on the user once
80 one_slice = slice_list[0]
81 #recuser = dbsession.query(RegRecord).filter_by(record_id = \
82 #one_slice['record_id_user']).first()
84 #Make a list of all the nodes hostnames in use for this slice
86 for single_slice in slice_list:
87 for node in single_slice['node_ids']:
88 slice_nodes_list.append(node['hostname'])
90 #Get all the corresponding nodes details
91 nodes_all = self.GetNodes({'hostname':slice_nodes_list},
92 ['node_id', 'hostname','site','boot_state'])
93 nodeall_byhostname = dict([(one_node['hostname'], one_node) \
94 for one_node in nodes_all])
98 for single_slice in slice_list:
101 top_level_status = 'empty'
104 ['geni_urn','pl_login','geni_status','geni_resources'], None)
105 result['pl_login'] = one_slice['reg_researchers']['hrn']
106 logger.debug("Slabdriver - sliver_status Sliver status \
107 urn %s hrn %s single_slice %s \r\n " \
108 %(slice_urn, slice_hrn, single_slice))
110 nodes_in_slice = single_slice['node_ids']
113 result['geni_status'] = top_level_status
114 result['geni_resources'] = []
117 top_level_status = 'ready'
119 #A job is running on Senslab for this slice
120 # report about the local nodes that are in the slice only
122 result['geni_urn'] = slice_urn
126 #timestamp = float(sl['startTime']) + float(sl['walltime'])
127 #result['pl_expires'] = strftime(self.time_format, \
128 #gmtime(float(timestamp)))
129 #result['slab_expires'] = strftime(self.time_format,\
130 #gmtime(float(timestamp)))
133 for node in single_slice['node_ids']:
135 #res['slab_hostname'] = node['hostname']
136 #res['slab_boot_state'] = node['boot_state']
138 res['pl_hostname'] = node['hostname']
139 res['pl_boot_state'] = \
140 nodeall_byhostname[node['hostname']]['boot_state']
141 #res['pl_last_contact'] = strftime(self.time_format, \
142 #gmtime(float(timestamp)))
143 sliver_id = Xrn(slice_urn, type='slice', \
144 id=nodeall_byhostname[node['hostname']]['node_id'], \
145 authority=self.hrn).urn
147 res['geni_urn'] = sliver_id
148 node_name = node['hostname']
149 if nodeall_byhostname[node_name]['boot_state'] == 'Alive':
151 res['geni_status'] = 'ready'
153 res['geni_status'] = 'failed'
154 top_level_status = 'failed'
156 res['geni_error'] = ''
158 resources.append(res)
160 result['geni_status'] = top_level_status
161 result['geni_resources'] = resources
162 logger.debug("SLABDRIVER \tsliver_statusresources %s res %s "\
166 def get_user(self, hrn):
167 return dbsession.query(RegRecord).filter_by(hrn = hrn).first()
170 def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, \
172 aggregate = SlabAggregate(self)
174 slices = SlabSlices(self)
175 peer = slices.get_peer(slice_hrn)
176 sfa_peer = slices.get_sfa_peer(slice_hrn)
179 if not isinstance(creds, list):
183 slice_record = users[0].get('slice_record', {})
184 logger.debug("SLABDRIVER.PY \t ===============create_sliver \t\
185 creds %s \r\n \r\n users %s" \
187 slice_record['user'] = {'keys':users[0]['keys'], \
188 'email':users[0]['email'], \
189 'hrn':slice_record['reg-researchers'][0]}
191 rspec = RSpec(rspec_string)
192 logger.debug("SLABDRIVER.PY \t create_sliver \trspec.version \
193 %s slice_record %s users %s" \
194 %(rspec.version,slice_record, users))
197 # ensure site record exists?
198 # ensure slice record exists
199 #Removed options to verify_slice SA 14/08/12
200 sfa_slice = slices.verify_slice(slice_hrn, slice_record, peer, \
203 # ensure person records exists
204 #verify_persons returns added persons but since the return value
206 slices.verify_persons(slice_hrn, sfa_slice, users, peer, \
207 sfa_peer, options=options)
208 #requested_attributes returned by rspec.version.get_slice_attributes()
209 #unused, removed SA 13/08/12
210 rspec.version.get_slice_attributes()
212 logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice))
214 # add/remove slice from nodes
216 requested_slivers = [node.get('component_id') \
217 for node in rspec.version.get_nodes_with_slivers()\
218 if node.get('authority_id') is self.root_auth]
219 l = [ node for node in rspec.version.get_nodes_with_slivers() ]
220 logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
221 requested_slivers %s listnodes %s" \
222 %(requested_slivers,l))
223 #verify_slice_nodes returns nodes, but unused here. Removed SA 13/08/12.
224 #slices.verify_slice_nodes(sfa_slice, requested_slivers, peer)
227 requested_lease_list = []
229 logger.debug("SLABDRIVER.PY \tcreate_sliver AVANTLEASE " )
230 rspec_requested_leases = rspec.version.get_leases()
231 for lease in rspec.version.get_leases():
232 single_requested_lease = {}
233 logger.debug("SLABDRIVER.PY \tcreate_sliver lease %s " %(lease))
235 if not lease.get('lease_id'):
236 if get_authority(lease['component_id']) == self.root_auth:
237 single_requested_lease['hostname'] = \
238 slab_xrn_to_hostname(\
239 lease.get('component_id').strip())
240 single_requested_lease['start_time'] = \
241 lease.get('start_time')
242 single_requested_lease['duration'] = lease.get('duration')
244 requested_lease_list.append(single_requested_lease)
246 logger.debug("SLABDRIVER.PY \tcreate_sliver APRESLEASE" )
247 #Create dict of leases by start_time, regrouping nodes reserved
249 #time, for the same amount of time = one job on OAR
250 requested_job_dict = {}
251 for lease in requested_lease_list:
253 #In case it is an asap experiment start_time is empty
254 if lease['start_time'] == '':
255 lease['start_time'] = '0'
257 if lease['start_time'] not in requested_job_dict:
258 if isinstance(lease['hostname'], str):
259 lease['hostname'] = [lease['hostname']]
261 requested_job_dict[lease['start_time']] = lease
264 job_lease = requested_job_dict[lease['start_time']]
265 if lease['duration'] == job_lease['duration'] :
266 job_lease['hostname'].append(lease['hostname'])
271 logger.debug("SLABDRIVER.PY \tcreate_sliver requested_job_dict %s "\
272 %(requested_job_dict))
273 #verify_slice_leases returns the leases , but the return value is unused
274 #here. Removed SA 13/08/12
275 slices.verify_slice_leases(sfa_slice, \
276 requested_job_dict, peer)
278 return aggregate.get_rspec(slice_xrn=slice_urn, login=sfa_slice['login'],version=rspec.version)
281 def delete_sliver (self, slice_urn, slice_hrn, creds, options):
283 sfa_slice_list = self.GetSlices(slice_filter = slice_hrn, \
284 slice_filter_type = 'slice_hrn')
286 if not sfa_slice_list:
289 #Delete all in the slice
290 for sfa_slice in sfa_slice_list:
293 logger.debug("SLABDRIVER.PY delete_sliver slice %s" %(sfa_slice))
294 slices = SlabSlices(self)
295 # determine if this is a peer slice
297 peer = slices.get_peer(slice_hrn)
298 #TODO delete_sliver SA : UnBindObjectFromPeer should be
299 #used when there is another
300 #senslab testbed, which is not the case 14/08/12 .
302 logger.debug("SLABDRIVER.PY delete_sliver peer %s" %(peer))
305 self.UnBindObjectFromPeer('slice', \
306 sfa_slice['record_id_slice'], \
308 self.DeleteSliceFromNodes(sfa_slice)
311 self.BindObjectToPeer('slice', \
312 sfa_slice['record_id_slice'], \
313 peer, sfa_slice['peer_slice_id'])
317 def AddSlice(self, slice_record, user_record):
318 """Add slice to the sfa tables and senslab table only if the user
319 already exists in senslab database(user already registered in LDAP).
320 There is no way to separate adding the slice to the tesbed
321 and then importing it from the testbed to SFA because of
322 senslab's architecture. Therefore, sfa tables are updated here.
325 sfa_record = RegSlice(hrn=slice_record['slice_hrn'],
326 gid=slice_record['gid'],
327 pointer=slice_record['slice_id'],
328 authority=slice_record['authority'])
330 logger.debug("SLABDRIVER.PY AddSlice sfa_record %s user_record %s" \
331 %(sfa_record, user_record))
332 sfa_record.just_created()
333 dbsession.add(sfa_record)
335 #Update the reg-researcher dependance table
336 sfa_record.reg_researchers = [user_record]
339 #Update the senslab table with the new slice
340 #slab_slice = SenslabXP( slice_hrn = slice_record['slice_hrn'], \
341 #record_id_slice = sfa_record.record_id , \
342 #record_id_user = slice_record['record_id_user'], \
343 #peer_authority = slice_record['peer_authority'])
345 #logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s \
346 #slab_slice %s sfa_record %s" \
347 #%(slice_record,slab_slice, sfa_record))
348 #slab_dbsession.add(slab_slice)
349 #slab_dbsession.commit()
352 # first 2 args are None in case of resource discovery
353 def list_resources (self, slice_urn, slice_hrn, creds, options):
354 #cached_requested = options.get('cached', True)
356 version_manager = VersionManager()
357 # get the rspec's return format from options
359 version_manager.get_version(options.get('geni_rspec_version'))
360 version_string = "rspec_%s" % (rspec_version)
362 #panos adding the info option to the caching key (can be improved)
363 if options.get('info'):
364 version_string = version_string + "_" + \
365 options.get('info', 'default')
367 # Adding the list_leases option to the caching key
368 if options.get('list_leases'):
369 version_string = version_string + "_"+options.get('list_leases', 'default')
371 # Adding geni_available to caching key
372 if options.get('geni_available'):
373 version_string = version_string + "_" + str(options.get('geni_available'))
375 # look in cache first
376 #if cached_requested and self.cache and not slice_hrn:
377 #rspec = self.cache.get(version_string)
379 #logger.debug("SlabDriver.ListResources: \
380 #returning cached advertisement")
383 #panos: passing user-defined options
384 aggregate = SlabAggregate(self)
385 #origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
386 #options.update({'origin_hrn':origin_hrn})
387 rspec = aggregate.get_rspec(slice_xrn=slice_urn, \
388 version=rspec_version, options=options)
391 #if self.cache and not slice_hrn:
392 #logger.debug("Slab.ListResources: stores advertisement in cache")
393 #self.cache.add(version_string, rspec)
398 def list_slices (self, creds, options):
399 # look in cache first
401 #slices = self.cache.get('slices')
403 #logger.debug("PlDriver.list_slices returns from cache")
408 slices = self.GetSlices()
409 logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices))
410 slice_hrns = [slab_slice['hrn'] for slab_slice in slices]
412 slice_urns = [hrn_to_urn(slice_hrn, 'slice') \
413 for slice_hrn in slice_hrns]
417 #logger.debug ("SlabDriver.list_slices stores value in cache")
418 #self.cache.add('slices', slice_urns)
423 def register (self, sfa_record, hrn, pub_key):
425 Adding new user, slice, node or site should not be handled
429 Adding users = LDAP Senslab
430 Adding slice = Import from LDAP users
436 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
437 """No site or node record update allowed in Senslab."""
439 pointer = old_sfa_record['pointer']
440 old_sfa_record_type = old_sfa_record['type']
442 # new_key implemented for users only
443 if new_key and old_sfa_record_type not in [ 'user' ]:
444 raise UnknownSfaType(old_sfa_record_type)
446 #if (type == "authority"):
447 #self.shell.UpdateSite(pointer, new_sfa_record)
449 if old_sfa_record_type == "slice":
450 slab_record = self.sfa_fields_to_slab_fields(old_sfa_record_type, \
452 if 'name' in slab_record:
453 slab_record.pop('name')
454 #Prototype should be UpdateSlice(self,
455 #auth, slice_id_or_name, slice_fields)
456 #Senslab cannot update slice since slice = job
457 #so we must delete and create another job
458 self.UpdateSlice(pointer, slab_record)
460 elif old_sfa_record_type == "user":
462 all_fields = new_sfa_record
463 for key in all_fields.keys():
464 if key in ['first_name', 'last_name', 'title', 'email',
465 'password', 'phone', 'url', 'bio', 'accepted_aup',
467 update_fields[key] = all_fields[key]
468 self.UpdatePerson(pointer, update_fields)
471 # must check this key against the previous one if it exists
472 persons = self.GetPersons([pointer], ['key_ids'])
474 keys = person['key_ids']
475 keys = self.GetKeys(person['key_ids'])
477 # Delete all stale keys
480 if new_key != key['key']:
481 self.DeleteKey(key['key_id'])
485 self.AddPersonKey(pointer, {'key_type': 'ssh', \
492 def remove (self, sfa_record):
493 sfa_record_type = sfa_record['type']
494 hrn = sfa_record['hrn']
495 if sfa_record_type == 'user':
497 #get user from senslab ldap
498 person = self.GetPersons(sfa_record)
499 #No registering at a given site in Senslab.
500 #Once registered to the LDAP, all senslab sites are
503 #Mark account as disabled in ldap
504 self.DeletePerson(sfa_record)
505 elif sfa_record_type == 'slice':
506 if self.GetSlices(slice_filter = hrn, \
507 slice_filter_type = 'slice_hrn'):
508 self.DeleteSlice(sfa_record)
510 #elif type == 'authority':
511 #if self.GetSites(pointer):
512 #self.DeleteSite(pointer)
518 #TODO clean GetPeers. 05/07/12SA
519 def GetPeers (self, auth = None, peer_filter=None, return_fields_list=None):
521 existing_records = {}
522 existing_hrns_by_types = {}
523 logger.debug("SLABDRIVER \tGetPeers auth = %s, peer_filter %s, \
524 return_field %s " %(auth , peer_filter, return_fields_list))
525 all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
527 for record in all_records:
528 existing_records[(record.hrn, record.type)] = record
529 if record.type not in existing_hrns_by_types:
530 existing_hrns_by_types[record.type] = [record.hrn]
532 existing_hrns_by_types[record.type].append(record.hrn)
535 logger.debug("SLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
536 %( existing_hrns_by_types))
541 records_list.append(existing_records[(peer_filter,'authority')])
543 for hrn in existing_hrns_by_types['authority']:
544 records_list.append(existing_records[(hrn,'authority')])
546 logger.debug("SLABDRIVER \tGetPeer \trecords_list %s " \
552 return_records = records_list
553 if not peer_filter and not return_fields_list:
557 logger.debug("SLABDRIVER \tGetPeer return_records %s " \
559 return return_records
562 #TODO : Handling OR request in make_ldap_filters_from_records
563 #instead of the for loop
564 #over the records' list
565 def GetPersons(self, person_filter=None):
567 person_filter should be a list of dictionnaries when not set to None.
568 Returns a list of users whose accounts are enabled found in ldap.
571 logger.debug("SLABDRIVER \tGetPersons person_filter %s" \
574 if person_filter and isinstance(person_filter, list):
575 #If we are looking for a list of users (list of dict records)
576 #Usually the list contains only one user record
577 for searched_attributes in person_filter:
579 #Get only enabled user accounts in senslab LDAP :
580 #add a filter for make_ldap_filters_from_record
581 person = self.ldap.LdapFindUser(searched_attributes, \
582 is_user_enabled=True)
583 #If a person was found, append it to the list
585 person_list.append(person)
587 #If the list is empty, return None
588 if len(person_list) is 0:
592 #Get only enabled user accounts in senslab LDAP :
593 #add a filter for make_ldap_filters_from_record
594 person_list = self.ldap.LdapFindUser(is_user_enabled=True)
598 def GetTimezone(self):
599 """ Get the OAR servier time and timezone.
600 Unused SA 16/11/12"""
601 server_timestamp, server_tz = self.oar.parser.\
602 SendRequest("GET_timezone")
603 return server_timestamp, server_tz
606 def DeleteJobs(self, job_id, slice_hrn):
607 if not job_id or job_id is -1:
609 username = slice_hrn.split(".")[-1].rstrip("_slice")
611 reqdict['method'] = "delete"
612 reqdict['strval'] = str(job_id)
615 answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id', \
617 logger.debug("SLABDRIVER \tDeleteJobs jobid %s \r\n answer %s \
618 username %s" %(job_id,answer, username))
623 ##TODO : Unused GetJobsId ? SA 05/07/12
624 #def GetJobsId(self, job_id, username = None ):
626 #Details about a specific job.
627 #Includes details about submission time, jot type, state, events,
628 #owner, assigned ressources, walltime etc...
632 #node_list_k = 'assigned_network_address'
633 ##Get job info from OAR
634 #job_info = self.oar.parser.SendRequest(req, job_id, username)
636 #logger.debug("SLABDRIVER \t GetJobsId %s " %(job_info))
638 #if job_info['state'] == 'Terminated':
639 #logger.debug("SLABDRIVER \t GetJobsId job %s TERMINATED"\
642 #if job_info['state'] == 'Error':
643 #logger.debug("SLABDRIVER \t GetJobsId ERROR message %s "\
648 #logger.error("SLABDRIVER \tGetJobsId KeyError")
651 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
653 ##Replaces the previous entry
654 ##"assigned_network_address" / "reserved_resources"
656 #job_info.update({'node_ids':parsed_job_info[node_list_k]})
657 #del job_info[node_list_k]
658 #logger.debug(" \r\nSLABDRIVER \t GetJobsId job_info %s " %(job_info))
662 def GetJobsResources(self, job_id, username = None):
663 #job_resources=['reserved_resources', 'assigned_resources',\
664 #'job_id', 'job_uri', 'assigned_nodes',\
666 #assigned_res = ['resource_id', 'resource_uri']
667 #assigned_n = ['node', 'node_uri']
669 req = "GET_jobs_id_resources"
672 #Get job resources list from OAR
673 node_id_list = self.oar.parser.SendRequest(req, job_id, username)
674 logger.debug("SLABDRIVER \t GetJobsResources %s " %(node_id_list))
677 self.__get_hostnames_from_oar_node_ids(node_id_list)
680 #Replaces the previous entry "assigned_network_address" /
681 #"reserved_resources"
683 job_info = {'node_ids': hostname_list}
688 def get_info_on_reserved_nodes(self, job_info, node_list_name):
689 #Get the list of the testbed nodes records and make a
690 #dictionnary keyed on the hostname out of it
691 node_list_dict = self.GetNodes()
692 #node_hostname_list = []
693 node_hostname_list = [node['hostname'] for node in node_list_dict]
694 #for node in node_list_dict:
695 #node_hostname_list.append(node['hostname'])
696 node_dict = dict(zip(node_hostname_list, node_list_dict))
698 reserved_node_hostname_list = []
699 for index in range(len(job_info[node_list_name])):
700 #job_info[node_list_name][k] =
701 reserved_node_hostname_list[index] = \
702 node_dict[job_info[node_list_name][index]]['hostname']
704 logger.debug("SLABDRIVER \t get_info_on_reserved_nodes \
705 reserved_node_hostname_list %s" \
706 %(reserved_node_hostname_list))
708 logger.error("SLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
710 return reserved_node_hostname_list
712 def GetNodesCurrentlyInUse(self):
713 """Returns a list of all the nodes already involved in an oar job"""
714 return self.oar.parser.SendRequest("GET_running_jobs")
716 def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
717 full_nodes_dict_list = self.GetNodes()
718 #Put the full node list into a dictionary keyed by oar node id
719 oar_id_node_dict = {}
720 for node in full_nodes_dict_list:
721 oar_id_node_dict[node['oar_id']] = node
723 #logger.debug("SLABDRIVER \t __get_hostnames_from_oar_node_ids\
724 #oar_id_node_dict %s" %(oar_id_node_dict))
726 hostname_dict_list = []
727 for resource_id in resource_id_list:
728 #Because jobs requested "asap" do not have defined resources
729 if resource_id is not "Undefined":
730 hostname_dict_list.append(\
731 oar_id_node_dict[resource_id]['hostname'])
733 #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
734 return hostname_dict_list
736 def GetReservedNodes(self,username = None):
737 #Get the nodes in use and the reserved nodes
738 reservation_dict_list = \
739 self.oar.parser.SendRequest("GET_reserved_nodes", \
743 for resa in reservation_dict_list:
744 logger.debug ("GetReservedNodes resa %s"%(resa))
745 #dict list of hostnames and their site
746 resa['reserved_nodes'] = \
747 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
749 #del resa['resource_ids']
750 return reservation_dict_list
752 def GetNodes(self, node_filter_dict = None, return_fields_list = None):
754 node_filter_dict : dictionnary of lists
757 node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
758 node_dict_list = node_dict_by_id.values()
759 logger.debug (" SLABDRIVER GetNodes node_filter_dict %s \
760 return_fields_list %s "%(node_filter_dict, return_fields_list))
761 #No filtering needed return the list directly
762 if not (node_filter_dict or return_fields_list):
763 return node_dict_list
765 return_node_list = []
767 for filter_key in node_filter_dict:
769 #Filter the node_dict_list by each value contained in the
770 #list node_filter_dict[filter_key]
771 for value in node_filter_dict[filter_key]:
772 for node in node_dict_list:
773 if node[filter_key] == value:
774 if return_fields_list :
776 for k in return_fields_list:
778 return_node_list.append(tmp)
780 return_node_list.append(node)
782 logger.log_exc("GetNodes KeyError")
786 return return_node_list
789 def GetSites(self, site_filter_name_list = None, return_fields_list = None):
790 site_dict = self.oar.parser.SendRequest("GET_sites")
791 #site_dict : dict where the key is the sit ename
792 return_site_list = []
793 if not ( site_filter_name_list or return_fields_list):
794 return_site_list = site_dict.values()
795 return return_site_list
797 for site_filter_name in site_filter_name_list:
798 if site_filter_name in site_dict:
799 if return_fields_list:
800 for field in return_fields_list:
803 tmp[field] = site_dict[site_filter_name][field]
805 logger.error("GetSites KeyError %s "%(field))
807 return_site_list.append(tmp)
809 return_site_list.append( site_dict[site_filter_name])
812 return return_site_list
815 def _sql_get_slice_info( self, slice_filter ):
816 #DO NOT USE RegSlice - reg_researchers to get the hrn
817 #of the user otherwise will mess up the RegRecord in
818 #Resolve, don't know why - SA 08/08/2012
820 #Only one entry for one user = one slice in slab_xp table
821 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
822 raw_slicerec = dbsession.query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn = slice_filter).first()
823 #raw_slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
826 #raw_slicerec.reg_researchers
827 raw_slicerec = raw_slicerec.__dict__
828 logger.debug(" SLABDRIVER \t get_slice_info slice_filter %s raw_slicerec %s"%(slice_filter,raw_slicerec))
829 slicerec = raw_slicerec
830 #only one researcher per slice so take the first one
831 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
832 #del slicerec['reg_researchers']['_sa_instance_state']
839 def _sql_get_slice_info_from_user( self, slice_filter ):
840 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
841 raw_slicerec = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id = slice_filter).first()
842 #raw_slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
843 #Put it in correct order
844 user_needed_fields = ['peer_authority', 'hrn', 'last_updated', 'classtype', 'authority', 'gid', 'record_id', 'date_created', 'type', 'email', 'pointer']
845 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated', 'classtype', 'authority', 'gid', 'record_id', 'date_created', 'type', 'pointer']
847 #raw_slicerec.reg_slices_as_researcher
848 raw_slicerec = raw_slicerec.__dict__
850 slicerec = dict([(k,raw_slicerec['reg_slices_as_researcher'][0].__dict__[k]) for k in slice_needed_fields])
851 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k]) for k in user_needed_fields])
852 #TODO Handle multiple slices for one user SA 10/12/12
853 #for now only take the first slice record associated to the rec user
854 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
855 #del raw_slicerec['reg_slices_as_researcher']
856 #slicerec['reg_researchers'] = raw_slicerec
857 ##del slicerec['_sa_instance_state']
864 def _get_slice_records(self, slice_filter = None, \
865 slice_filter_type = None):
869 #Get list of slices based on the slice hrn
870 if slice_filter_type == 'slice_hrn':
872 #if get_authority(slice_filter) == self.root_auth:
873 #login = slice_filter.split(".")[1].split("_")[0]
875 slicerec = self._sql_get_slice_info(slice_filter)
881 #Get slice based on user id
882 if slice_filter_type == 'record_id_user':
884 slicerec = self._sql_get_slice_info_from_user(slice_filter)
887 fixed_slicerec_dict = slicerec
888 #At this point if the there is no login it means
889 #record_id_user filter has been used for filtering
891 ##If theslice record is from senslab
892 #if fixed_slicerec_dict['peer_authority'] is None:
893 #login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
894 #return login, fixed_slicerec_dict
895 return fixed_slicerec_dict
897 def GetSlices(self, slice_filter = None, slice_filter_type = None, login=None):
898 """ Get the slice records from the slab db.
899 Returns a slice ditc if slice_filter and slice_filter_type
901 Returns a list of slice dictionnaries if there are no filters
906 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
907 return_slicerec_dictlist = []
909 #First try to get information on the slice based on the filter provided
910 if slice_filter_type in authorized_filter_types_list:
911 fixed_slicerec_dict = \
912 self._get_slice_records(slice_filter, slice_filter_type)
913 #login, fixed_slicerec_dict = \
914 #self._get_slice_records(slice_filter, slice_filter_type)
915 logger.debug(" SLABDRIVER \tGetSlices login %s \
916 slice record %s slice_filter %s slice_filter_type %s "\
917 %(login, fixed_slicerec_dict,slice_filter, slice_filter_type))
920 #Now we have the slice record fixed_slicerec_dict, get the
921 #jobs associated to this slice
922 #leases_list = self.GetReservedNodes(username = login)
923 leases_list = self.GetLeases(login = login)
924 #If no job is running or no job scheduled
925 #return only the slice record
926 if leases_list == [] and fixed_slicerec_dict:
927 return_slicerec_dictlist.append(fixed_slicerec_dict)
929 #If several jobs for one slice , put the slice record into
930 # each lease information dict
931 for lease in leases_list :
934 reserved_list = lease['reserved_nodes']
936 slicerec_dict['oar_job_id']= lease['lease_id']
937 slicerec_dict.update({'list_node_ids':{'hostname':reserved_list}})
938 slicerec_dict.update({'node_ids':lease['reserved_nodes']})
940 #Update lease dict with the slice record
941 if fixed_slicerec_dict:
942 fixed_slicerec_dict['oar_job_id'] = []
943 fixed_slicerec_dict['oar_job_id'].append(slicerec_dict['oar_job_id'])
944 slicerec_dict.update(fixed_slicerec_dict)
945 #slicerec_dict.update({'hrn':\
946 #str(fixed_slicerec_dict['slice_hrn'])})
949 return_slicerec_dictlist.append(slicerec_dict)
950 logger.debug("SLABDRIVER.PY \tGetSlices \
951 slicerec_dict %s return_slicerec_dictlist %s \
952 lease['reserved_nodes'] \
953 %s" %(slicerec_dict, return_slicerec_dictlist, \
954 lease['reserved_nodes'] ))
956 logger.debug("SLABDRIVER.PY \tGetSlices RETURN \
957 return_slicerec_dictlist %s" \
958 %(return_slicerec_dictlist))
960 return return_slicerec_dictlist
964 #Get all slices from the senslab sfa database ,
965 #put them in dict format
966 #query_slice_list = dbsession.query(RegRecord).all()
967 query_slice_list = dbsession.query(RegSlice).options(joinedload('reg_researchers')).all()
968 #query_slice_list = dbsession.query(RegRecord).filter_by(type='slice').all()
969 #query_slice_list = slab_dbsession.query(SenslabXP).all()
970 return_slicerec_dictlist = []
971 for record in query_slice_list:
972 tmp = record.__dict__
973 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
974 #del tmp['reg_researchers']['_sa_instance_state']
975 return_slicerec_dictlist.append(tmp)
976 #return_slicerec_dictlist.append(record.__dict__)
978 #Get all the jobs reserved nodes
979 leases_list = self.GetReservedNodes()
982 for fixed_slicerec_dict in return_slicerec_dictlist:
984 #Check if the slice belongs to a senslab user
985 if fixed_slicerec_dict['peer_authority'] is None:
986 owner = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
989 for lease in leases_list:
990 if owner == lease['user']:
991 slicerec_dict['oar_job_id'] = lease['lease_id']
993 #for reserved_node in lease['reserved_nodes']:
994 logger.debug("SLABDRIVER.PY \tGetSlices lease %s "\
997 reserved_list = lease['reserved_nodes']
999 slicerec_dict.update({'node_ids':lease['reserved_nodes']})
1000 slicerec_dict.update({'list_node_ids':{'hostname':reserved_list}})
1001 slicerec_dict.update(fixed_slicerec_dict)
1002 #slicerec_dict.update({'hrn':\
1003 #str(fixed_slicerec_dict['slice_hrn'])})
1004 #return_slicerec_dictlist.append(slicerec_dict)
1005 fixed_slicerec_dict.update(slicerec_dict)
1007 logger.debug("SLABDRIVER.PY \tGetSlices RETURN \
1008 return_slicerec_dictlist %s \slice_filter %s " \
1009 %(return_slicerec_dictlist, slice_filter))
1011 return return_slicerec_dictlist
1014 def testbed_name (self): return self.hrn
1016 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1017 def aggregate_version (self):
1018 version_manager = VersionManager()
1019 ad_rspec_versions = []
1020 request_rspec_versions = []
1021 for rspec_version in version_manager.versions:
1022 if rspec_version.content_type in ['*', 'ad']:
1023 ad_rspec_versions.append(rspec_version.to_dict())
1024 if rspec_version.content_type in ['*', 'request']:
1025 request_rspec_versions.append(rspec_version.to_dict())
1027 'testbed':self.testbed_name(),
1028 'geni_request_rspec_versions': request_rspec_versions,
1029 'geni_ad_rspec_versions': ad_rspec_versions,
1035 # Convert SFA fields to PLC fields for use when registering up updating
1036 # registry record in the PLC database
1038 # @param type type of record (user, slice, ...)
1039 # @param hrn human readable name
1040 # @param sfa_fields dictionary of SFA fields
1041 # @param slab_fields dictionary of PLC fields (output)
1043 def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
1047 #for field in record:
1048 # slab_record[field] = record[field]
1050 if sfa_type == "slice":
1051 #instantion used in get_slivers ?
1052 if not "instantiation" in slab_record:
1053 slab_record["instantiation"] = "senslab-instantiated"
1054 #slab_record["hrn"] = hrn_to_pl_slicename(hrn)
1055 #Unused hrn_to_pl_slicename because Slab's hrn already
1056 #in the appropriate form SA 23/07/12
1057 slab_record["hrn"] = hrn
1058 logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
1059 slab_record %s " %(slab_record['hrn']))
1061 slab_record["url"] = record["url"]
1062 if "description" in record:
1063 slab_record["description"] = record["description"]
1064 if "expires" in record:
1065 slab_record["expires"] = int(record["expires"])
1067 #nodes added by OAR only and then imported to SFA
1068 #elif type == "node":
1069 #if not "hostname" in slab_record:
1070 #if not "hostname" in record:
1071 #raise MissingSfaInfo("hostname")
1072 #slab_record["hostname"] = record["hostname"]
1073 #if not "model" in slab_record:
1074 #slab_record["model"] = "geni"
1077 #elif type == "authority":
1078 #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
1080 #if not "name" in slab_record:
1081 #slab_record["name"] = hrn
1083 #if not "abbreviated_name" in slab_record:
1084 #slab_record["abbreviated_name"] = hrn
1086 #if not "enabled" in slab_record:
1087 #slab_record["enabled"] = True
1089 #if not "is_public" in slab_record:
1090 #slab_record["is_public"] = True
1097 def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
1098 """ Transforms unix timestamp into valid OAR date format """
1100 #Used in case of a scheduled experiment (not immediate)
1101 #To run an XP immediately, don't specify date and time in RSpec
1102 #They will be set to None.
1103 if xp_utc_timestamp:
1104 #transform the xp_utc_timestamp into server readable time
1105 xp_server_readable_date = datetime.fromtimestamp(int(\
1106 xp_utc_timestamp)).strftime(self.time_format)
1108 return xp_server_readable_date
1116 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
1117 lease_start_time, lease_duration, slice_user=None):
1119 lease_dict['lease_start_time'] = lease_start_time
1120 lease_dict['lease_duration'] = lease_duration
1121 lease_dict['added_nodes'] = added_nodes
1122 lease_dict['slice_name'] = slice_name
1123 lease_dict['slice_user'] = slice_user
1124 lease_dict['grain'] = self.GetLeaseGranularity()
1125 lease_dict['time_format'] = self.time_format
1128 def __create_job_structure_request_for_OAR(lease_dict):
1129 """ Creates the structure needed for a correct POST on OAR.
1130 Makes the timestamp transformation into the appropriate format.
1131 Sends the POST request to create the job with the resources in
1140 reqdict['workdir'] = '/tmp'
1141 reqdict['resource'] = "{network_address in ("
1143 for node in lease_dict['added_nodes']:
1144 logger.debug("\r\n \r\n OARrestapi \t \
1145 __create_job_structure_request_for_OAR node %s" %(node))
1147 # Get the ID of the node
1149 reqdict['resource'] += "'" + nodeid + "', "
1150 nodeid_list.append(nodeid)
1152 custom_length = len(reqdict['resource'])- 2
1153 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
1154 ")}/nodes=" + str(len(nodeid_list))
1156 def __process_walltime(duration):
1157 """ Calculates the walltime in seconds from the duration in H:M:S
1158 specified in the RSpec.
1162 # Fixing the walltime by adding a few delays.
1163 # First put the walltime in seconds oarAdditionalDelay = 20;
1164 # additional delay for /bin/sleep command to
1165 # take in account prologue and epilogue scripts execution
1166 # int walltimeAdditionalDelay = 240; additional delay
1167 desired_walltime = duration
1168 total_walltime = desired_walltime + 240 #+4 min Update SA 23/10/12
1169 sleep_walltime = desired_walltime # 0 sec added Update SA 23/10/12
1171 #Put the walltime back in str form
1172 #First get the hours
1173 walltime.append(str(total_walltime / 3600))
1174 total_walltime = total_walltime - 3600 * int(walltime[0])
1175 #Get the remaining minutes
1176 walltime.append(str(total_walltime / 60))
1177 total_walltime = total_walltime - 60 * int(walltime[1])
1179 walltime.append(str(total_walltime))
1182 logger.log_exc(" __process_walltime duration null")
1184 return walltime, sleep_walltime
1187 walltime, sleep_walltime = \
1188 __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1191 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1192 ":" + str(walltime[1]) + ":" + str(walltime[2])
1193 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1195 #In case of a scheduled experiment (not immediate)
1196 #To run an XP immediately, don't specify date and time in RSpec
1197 #They will be set to None.
1198 if lease_dict['lease_start_time'] is not '0':
1199 #Readable time accepted by OAR
1200 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1201 strftime(lease_dict['time_format'])
1202 reqdict['reservation'] = start_time
1203 #If there is not start time, Immediate XP. No need to add special
1207 reqdict['type'] = "deploy"
1208 reqdict['directory'] = ""
1209 reqdict['name'] = "SFA_" + lease_dict['slice_user']
1213 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR slice_user %s\
1214 \r\n " %(slice_user))
1215 #Create the request for OAR
1216 reqdict = __create_job_structure_request_for_OAR(lease_dict)
1217 # first step : start the OAR job and update the job
1218 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1221 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1222 reqdict, slice_user)
1223 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s " %(answer))
1225 jobid = answer['id']
1227 logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1228 Impossible to create job %s " %(answer))
1232 def __configure_experiment(jobid, added_nodes):
1233 # second step : configure the experiment
1234 # we need to store the nodes in a yaml (well...) file like this :
1235 # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1236 tmp_dir = '/tmp/sfa/'
1237 if not os.path.exists(tmp_dir):
1238 os.makedirs(tmp_dir)
1239 job_file = open(tmp_dir + str(jobid) + '.json', 'w')
1241 job_file.write(str(added_nodes[0].strip('node')))
1242 for node in added_nodes[1:len(added_nodes)] :
1243 job_file.write(', '+ node.strip('node'))
1248 def __launch_senslab_experiment(jobid):
1249 # third step : call the senslab-experiment wrapper
1250 #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar
1251 # "+str(jobid)+" "+slice_user
1252 javacmdline = "/usr/bin/java"
1254 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1256 output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1257 slice_user],stdout=subprocess.PIPE).communicate()[0]
1259 logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1266 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1267 added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1270 __configure_experiment(jobid, added_nodes)
1271 __launch_senslab_experiment(jobid)
1276 def AddLeases(self, hostname_list, slice_record, \
1277 lease_start_time, lease_duration):
1278 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s \
1279 slice_record %s lease_start_time %s lease_duration %s "\
1280 %( hostname_list, slice_record , lease_start_time, \
1283 #tmp = slice_record['reg-researchers'][0].split(".")
1284 username = slice_record['login']
1285 #username = tmp[(len(tmp)-1)]
1286 job_id = self.LaunchExperimentOnOAR(hostname_list, slice_record['hrn'], \
1287 lease_start_time, lease_duration, username)
1288 start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1289 end_time = lease_start_time + lease_duration
1291 import logging, logging.handlers
1292 from sfa.util.sfalogging import _SfaLogger
1293 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases TURN ON LOGGING SQL %s %s %s "%(slice_record['hrn'], job_id, end_time))
1294 sql_logger = _SfaLogger(loggername = 'sqlalchemy.engine', level=logging.DEBUG)
1295 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases %s %s %s " %(type(slice_record['hrn']), type(job_id), type(end_time)))
1296 slab_ex_row = SenslabXP(slice_hrn = slice_record['hrn'], job_id = job_id,end_time= end_time)
1297 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases slab_ex_row %s" %(slab_ex_row))
1298 slab_dbsession.add(slab_ex_row)
1299 slab_dbsession.commit()
1301 logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1306 #Delete the jobs from job_senslab table
1307 def DeleteSliceFromNodes(self, slice_record):
1308 for job_id in slice_record['oar_job_id']:
1309 self.DeleteJobs(job_id, slice_record['hrn'])
1313 def GetLeaseGranularity(self):
1314 """ Returns the granularity of Senslab testbed.
1315 OAR returns seconds for experiments duration.
1316 Defined in seconds. """
1321 def update_jobs_in_slabdb(self, job_oar_list, jobs_psql):
1322 #Get all the entries in slab_xp table
1325 jobs_psql = set(jobs_psql)
1326 kept_jobs = set(job_oar_list).intersection(jobs_psql)
1327 logger.debug ( "\r\n \t\tt update_jobs_in_slabdb jobs_psql %s \r\n \t job_oar_list %s \
1328 kept_jobs %s " %(jobs_psql,job_oar_list,kept_jobs))
1329 deleted_jobs = set(jobs_psql).difference(kept_jobs)
1330 deleted_jobs = list(deleted_jobs)
1331 if len(deleted_jobs) > 0:
1332 slab_dbsession.query(SenslabXP).filter(SenslabXP.job_id.in_(deleted_jobs)).delete(synchronize_session='fetch')
1333 slab_dbsession.commit()
1339 def GetLeases(self, lease_filter_dict=None, login=None):
1342 unfiltered_reservation_list = self.GetReservedNodes(login)
1344 reservation_list = []
1345 #Find the slice associated with this user senslab ldap uid
1346 logger.debug(" SLABDRIVER.PY \tGetLeases login %s unfiltered_reservation_list %s " %(login ,unfiltered_reservation_list))
1347 #Create user dict first to avoid looking several times for
1348 #the same user in LDAP SA 27/07/12
1352 jobs_psql_query = slab_dbsession.query(SenslabXP).all()
1353 jobs_psql_dict = [ (row.job_id, row.__dict__ )for row in jobs_psql_query ]
1354 jobs_psql_dict = dict(jobs_psql_dict)
1355 logger.debug("SLABDRIVER \tGetLeases jobs_psql_dict %s"\
1357 jobs_psql_id_list = [ row.job_id for row in jobs_psql_query ]
1361 for resa in unfiltered_reservation_list:
1362 logger.debug("SLABDRIVER \tGetLeases USER %s"\
1364 #Cosntruct list of jobs (runing, waiting..) in oar
1365 job_oar_list.append(resa['lease_id'])
1366 #If there is information on the job in SLAB DB (slice used and job id)
1367 if resa['lease_id'] in jobs_psql_dict:
1368 job_info = jobs_psql_dict[resa['lease_id']]
1369 logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1371 resa['slice_hrn'] = job_info['slice_hrn']
1372 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1374 #Assume it is a senslab slice:
1376 resa['slice_id'] = hrn_to_urn(self.root_auth+'.'+ resa['user'] +"_slice" , 'slice')
1377 #if resa['user'] not in resa_user_dict:
1378 #logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1379 #ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1381 #ldap_info = ldap_info[0][1]
1382 ##Get the backref :relationship table reg-researchers
1383 #user = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(email = \
1384 #ldap_info['mail'][0])
1386 #user = user.first()
1387 #user = user.__dict__
1388 #slice_info = user['reg_slices_as_researcher'][0].__dict__
1389 ##Separated in case user not in database :
1390 ##record_id not defined SA 17/07//12
1392 ##query_slice_info = slab_dbsession.query(SenslabXP).filter_by(record_id_user = user.record_id)
1393 ##if query_slice_info:
1394 ##slice_info = query_slice_info.first()
1398 #resa_user_dict[resa['user']] = {}
1399 #resa_user_dict[resa['user']]['ldap_info'] = user
1400 #resa_user_dict[resa['user']]['slice_info'] = slice_info
1402 #resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info']['hrn']
1403 #resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1406 resa['component_id_list'] = []
1407 resa['hrn'] = Xrn(resa['slice_id']).get_hrn()
1408 #Transform the hostnames into urns (component ids)
1409 for node in resa['reserved_nodes']:
1410 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1411 #self.root_auth, node['hostname']))
1412 slab_xrn = slab_xrn_object(self.root_auth, node)
1413 resa['component_id_list'].append(slab_xrn.urn)
1415 if lease_filter_dict:
1416 logger.debug("SLABDRIVER \tGetLeases resa_ %s \r\n leasefilter %s"\
1417 %(resa,lease_filter_dict))
1419 if lease_filter_dict['name'] == resa['hrn']:
1420 reservation_list.append(resa)
1422 if lease_filter_dict is None:
1423 reservation_list = unfiltered_reservation_list
1425 #del unfiltered_reservation_list[unfiltered_reservation_list.index(resa)]
1428 self.update_jobs_in_slabdb(job_oar_list, jobs_psql_id_list)
1430 #for resa in unfiltered_reservation_list:
1434 #if resa['user'] in resa_user_dict:
1435 #resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info']['hrn']
1436 #resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1438 ##resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1439 #resa['component_id_list'] = []
1440 ##Transform the hostnames into urns (component ids)
1441 #for node in resa['reserved_nodes']:
1442 ##resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1443 ##self.root_auth, node['hostname']))
1444 #slab_xrn = slab_xrn_object(self.root_auth, node)
1445 #resa['component_id_list'].append(slab_xrn.urn)
1447 ##Filter the reservation list if necessary
1448 ##Returns all the leases associated with a given slice
1449 #if lease_filter_dict:
1450 #logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1451 #%(lease_filter_dict))
1452 #for resa in unfiltered_reservation_list:
1453 #if lease_filter_dict['name'] == resa['slice_hrn']:
1454 #reservation_list.append(resa)
1456 #reservation_list = unfiltered_reservation_list
1458 logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1459 %(reservation_list))
1460 return reservation_list
1462 def augment_records_with_testbed_info (self, sfa_records):
1463 return self.fill_record_info (sfa_records)
1465 def fill_record_info(self, record_list):
1467 Given a SFA record, fill in the senslab specific and SFA specific
1468 fields in the record.
1471 logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1472 if not isinstance(record_list, list):
1473 record_list = [record_list]
1476 for record in record_list:
1477 #If the record is a SFA slice record, then add information
1478 #about the user of this slice. This kind of
1479 #information is in the Senslab's DB.
1480 if str(record['type']) == 'slice':
1481 if 'reg_researchers' in record and isinstance(record['reg_researchers'],list) :
1482 record['reg_researchers'] = record['reg_researchers'][0].__dict__
1483 record.update({'PI':[record['reg_researchers']['hrn']],
1484 'researcher': [record['reg_researchers']['hrn']],
1485 'name':record['hrn'],
1488 'person_ids':[record['reg_researchers']['record_id']],
1489 'geni_urn':'', #For client_helper.py compatibility
1490 'keys':'', #For client_helper.py compatibility
1491 'key_ids':''}) #For client_helper.py compatibility
1494 #Get slab slice record.
1495 recslice_list = self.GetSlices(slice_filter = \
1496 str(record['hrn']),\
1497 slice_filter_type = 'slice_hrn')
1499 #recuser = recslice_list[0]['reg_researchers']
1500 ##recuser = dbsession.query(RegRecord).filter_by(record_id = \
1501 ##recslice_list[0]['record_id_user']).first()
1503 #record.update({'PI':[recuser['hrn']],
1504 #'researcher': [recuser['hrn']],
1505 #'name':record['hrn'],
1508 #'person_ids':[recslice_list[0]['reg_researchers']['record_id']],
1509 #'geni_urn':'', #For client_helper.py compatibility
1510 #'keys':'', #For client_helper.py compatibility
1511 #'key_ids':''}) #For client_helper.py compatibility
1512 logger.debug("SLABDRIVER \tfill_record_info TYPE SLICE RECUSER record['hrn'] %s ecord['oar_job_id'] %s " %(record['hrn'],record['oar_job_id']))
1514 for rec in recslice_list:
1515 logger.debug("SLABDRIVER\r\n \t \t fill_record_info oar_job_id %s " %(rec['oar_job_id']))
1516 #record['oar_job_id'].append(rec['oar_job_id'])
1517 #del record['_sa_instance_state']
1518 del record['reg_researchers']
1519 record['node_ids'] = [ self.root_auth + hostname for hostname in rec['node_ids']]
1523 logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1524 recslice_list %s \r\n \t RECORD %s \r\n \r\n" %(recslice_list,record))
1525 if str(record['type']) == 'user':
1526 #The record is a SFA user record.
1527 #Get the information about his slice from Senslab's DB
1528 #and add it to the user record.
1529 recslice_list = self.GetSlices(\
1530 slice_filter = record['record_id'],\
1531 slice_filter_type = 'record_id_user')
1533 logger.debug( "SLABDRIVER.PY \t fill_record_info TYPE USER \
1534 recslice_list %s \r\n \t RECORD %s \r\n" %(recslice_list , record))
1535 #Append slice record in records list,
1536 #therefore fetches user and slice info again(one more loop)
1537 #Will update PIs and researcher for the slice
1538 #recuser = dbsession.query(RegRecord).filter_by(record_id = \
1539 #recslice_list[0]['record_id_user']).first()
1540 recuser = recslice_list[0]['reg_researchers']
1541 logger.debug( "SLABDRIVER.PY \t fill_record_info USER \
1542 recuser %s \r\n \r\n" %(recuser))
1544 recslice = recslice_list[0]
1545 recslice.update({'PI':[recuser['hrn']],
1546 'researcher': [recuser['hrn']],
1547 'name':record['hrn'],
1550 'person_ids':[recuser['record_id']]})
1552 for rec in recslice_list:
1553 recslice['oar_job_id'].append(rec['oar_job_id'])
1557 recslice.update({'type':'slice', \
1558 'hrn':recslice_list[0]['hrn']})
1561 #GetPersons takes [] as filters
1562 #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1563 user_slab = self.GetPersons([record])
1566 record.update(user_slab[0])
1567 #For client_helper.py compatibility
1568 record.update( { 'geni_urn':'',
1571 record_list.append(recslice)
1573 logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1574 INFO TO USER records %s" %(record_list))
1576 logger.debug("SLABDRIVER.PY \tfill_record_info END \
1577 record %s \r\n \r\n " %(record))
1579 except TypeError, error:
1580 logger.log_exc("SLABDRIVER \t fill_record_info EXCEPTION %s"\
1582 #logger.debug("SLABDRIVER.PY \t fill_record_info ENDENDEND ")
1586 #self.fill_record_slab_info(records)
1592 #TODO Update membership? update_membership_list SA 05/07/12
1593 #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1595 ## get a list of the HRNs tht are members of the old and new records
1597 #oldList = oldRecord.get(listName, [])
1600 #newList = record.get(listName, [])
1602 ## if the lists are the same, then we don't have to update anything
1603 #if (oldList == newList):
1606 ## build a list of the new person ids, by looking up each person to get
1610 #records = table.find({'type': 'user', 'hrn': newList})
1611 #for rec in records:
1612 #newIdList.append(rec['pointer'])
1614 ## build a list of the old person ids from the person_ids field
1616 #oldIdList = oldRecord.get("person_ids", [])
1617 #containerId = oldRecord.get_pointer()
1619 ## if oldRecord==None, then we are doing a Register, instead of an
1622 #containerId = record.get_pointer()
1624 ## add people who are in the new list, but not the oldList
1625 #for personId in newIdList:
1626 #if not (personId in oldIdList):
1627 #addFunc(self.plauth, personId, containerId)
1629 ## remove people who are in the old list, but not the new list
1630 #for personId in oldIdList:
1631 #if not (personId in newIdList):
1632 #delFunc(self.plauth, personId, containerId)
1634 #def update_membership(self, oldRecord, record):
1636 #if record.type == "slice":
1637 #self.update_membership_list(oldRecord, record, 'researcher',
1638 #self.users.AddPersonToSlice,
1639 #self.users.DeletePersonFromSlice)
1640 #elif record.type == "authority":
1645 # I don't think you plan on running a component manager at this point
1646 # let me clean up the mess of ComponentAPI that is deprecated anyways
1649 #TODO FUNCTIONS SECTION 04/07/2012 SA
1651 #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1653 def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1654 """ This method is a hopefully temporary hack to let the sfa correctly
1655 detach the objects it creates from a remote peer object. This is
1656 needed so that the sfa federation link can work in parallel with
1657 RefreshPeer, as RefreshPeer depends on remote objects being correctly
1660 auth : struct, API authentication structure
1661 AuthMethod : string, Authentication method to use
1662 object_type : string, Object type, among 'site','person','slice',
1664 object_id : int, object_id
1665 shortname : string, peer shortname
1669 logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1673 #TODO Is BindObjectToPeer still necessary ? Currently does nothing
1675 def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1676 remote_object_id=None):
1677 """This method is a hopefully temporary hack to let the sfa correctly
1678 attach the objects it creates to a remote peer object. This is needed
1679 so that the sfa federation link can work in parallel with RefreshPeer,
1680 as RefreshPeer depends on remote objects being correctly marked.
1682 shortname : string, peer shortname
1683 remote_object_id : int, remote object_id, set to 0 if unknown
1687 logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1690 #TODO UpdateSlice 04/07/2012 SA
1691 #Funciton should delete and create another job since oin senslab slice=job
1692 def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1693 """Updates the parameters of an existing slice with the values in
1695 Users may only update slices of which they are members.
1696 PIs may update any of the slices at their sites, or any slices of
1697 which they are members. Admins may update any slice.
1698 Only PIs and admins may update max_nodes. Slices cannot be renewed
1699 (by updating the expires parameter) more than 8 weeks into the future.
1700 Returns 1 if successful, faults otherwise.
1704 logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1707 #TODO UpdatePerson 04/07/2012 SA
1708 def UpdatePerson(self, slab_hrn, federated_hrn, person_fields=None):
1709 """Updates a person. Only the fields specified in person_fields
1710 are updated, all other fields are left untouched.
1711 Users and techs can only update themselves. PIs can only update
1712 themselves and other non-PIs at their sites.
1713 Returns 1 if successful, faults otherwise.
1717 #new_row = FederatedToSenslab(slab_hrn, federated_hrn)
1718 #slab_dbsession.add(new_row)
1719 #slab_dbsession.commit()
1721 logger.debug("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1724 #TODO GetKeys 04/07/2012 SA
1725 def GetKeys(self, auth, key_filter=None, return_fields=None):
1726 """Returns an array of structs containing details about keys.
1727 If key_filter is specified and is an array of key identifiers,
1728 or a struct of key attributes, only keys matching the filter
1729 will be returned. If return_fields is specified, only the
1730 specified details will be returned.
1732 Admin may query all keys. Non-admins may only query their own keys.
1736 logger.warning("SLABDRIVER GetKeys EMPTY - DO NOTHING \r\n ")
1739 #TODO DeleteKey 04/07/2012 SA
1740 def DeleteKey(self, auth, key_id):
1742 Non-admins may only delete their own keys.
1743 Returns 1 if successful, faults otherwise.
1747 logger.warning("SLABDRIVER DeleteKey EMPTY - DO NOTHING \r\n ")
1751 #TODO : Check rights to delete person
1752 def DeletePerson(self, auth, person_record):
1753 """ Disable an existing account in senslab LDAP.
1754 Users and techs can only delete themselves. PIs can only
1755 delete themselves and other non-PIs at their sites.
1756 ins can delete anyone.
1757 Returns 1 if successful, faults otherwise.
1761 #Disable user account in senslab LDAP
1762 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1763 logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1766 #TODO Check DeleteSlice, check rights 05/07/2012 SA
1767 def DeleteSlice(self, auth, slice_record):
1768 """ Deletes the specified slice.
1769 Senslab : Kill the job associated with the slice if there is one
1770 using DeleteSliceFromNodes.
1771 Updates the slice record in slab db to remove the slice nodes.
1773 Users may only delete slices of which they are members. PIs may
1774 delete any of the slices at their sites, or any slices of which
1775 they are members. Admins may delete any slice.
1776 Returns 1 if successful, faults otherwise.
1780 self.DeleteSliceFromNodes(slice_record)
1781 logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1784 def __add_person_to_db(self, user_dict):
1786 check_if_exists = dbsession.query(RegUser).filter_by(email = user_dict['email']).first()
1787 #user doesn't exists
1788 if not check_if_exists:
1789 logger.debug("__add_person_to_db \t Adding %s \r\n \r\n \
1790 _________________________________________________________________________\
1791 " %(user_dict['hrn']))
1792 user_record = RegUser(hrn =user_dict['hrn'] , pointer= '-1', authority=get_authority(hrn), \
1793 email= user_dict['email'], gid = None)
1794 user_record.reg_keys = [RegKey(user_dict['pkey'])]
1795 user_record.just_created()
1796 dbsession.add (user_record)
1800 #TODO AddPerson 04/07/2012 SA
1801 #def AddPerson(self, auth, person_fields=None):
1802 def AddPerson(self, record):#TODO fixing 28/08//2012 SA
1803 """Adds a new account. Any fields specified in records are used,
1804 otherwise defaults are used.
1805 Accounts are disabled by default. To enable an account,
1807 Returns the new person_id (> 0) if successful, faults otherwise.
1811 ret = self.ldap.LdapAddUser(record)
1812 logger.debug("SLABDRIVER AddPerson return code %s \r\n "%(ret))
1813 self.__add_person_to_db(record)
1816 #TODO AddPersonToSite 04/07/2012 SA
1817 def AddPersonToSite (self, auth, person_id_or_email, \
1818 site_id_or_login_base=None):
1819 """ Adds the specified person to the specified site. If the person is
1820 already a member of the site, no errors are returned. Does not change
1821 the person's primary site.
1822 Returns 1 if successful, faults otherwise.
1826 logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1829 #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1830 def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1831 """Grants the specified role to the person.
1832 PIs can only grant the tech and user roles to users and techs at their
1833 sites. Admins can grant any role to any user.
1834 Returns 1 if successful, faults otherwise.
1838 logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1841 #TODO AddPersonKey 04/07/2012 SA
1842 def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1843 """Adds a new key to the specified account.
1844 Non-admins can only modify their own keys.
1845 Returns the new key_id (> 0) if successful, faults otherwise.
1849 logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1852 def DeleteLeases(self, leases_id_list, slice_hrn ):
1853 logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \
1854 \r\n " %(leases_id_list, slice_hrn))
1855 for job_id in leases_id_list:
1856 self.DeleteJobs(job_id, slice_hrn)