4 from datetime import datetime
6 from sfa.util.faults import SliverDoesNotExist, UnknownSfaType
7 from sfa.util.sfalogging import logger
9 from sfa.storage.alchemy import dbsession
10 from sfa.storage.model import RegRecord, RegUser, RegSlice
11 from sqlalchemy.orm import joinedload
12 from sfa.trust.credential import Credential
15 from sfa.managers.driver import Driver
16 from sfa.rspecs.version_manager import VersionManager
17 from sfa.rspecs.rspec import RSpec
19 from sfa.util.xrn import Xrn, hrn_to_urn, get_authority
22 ## thierry: everything that is API-related (i.e. handling incoming requests)
24 # SlabDriver should be really only about talking to the senslab testbed
27 from sfa.senslab.OARrestapi import OARrestapi
28 from sfa.senslab.LDAPapi import LDAPapi
30 from sfa.senslab.slabpostgres import SlabDB, slab_dbsession, SenslabXP
33 from sfa.senslab.slabaggregate import SlabAggregate, slab_xrn_to_hostname, \
35 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
46 class SlabDriver(Driver):
47 """ Senslab Driver class inherited from Driver generic class.
49 Contains methods compliant with the SFA standard and the testbed
50 infrastructure (calls to LDAP and OAR).
52 def __init__(self, config):
53 Driver.__init__ (self, config)
55 self.hrn = config.SFA_INTERFACE_HRN
56 self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
57 self.oar = OARrestapi()
59 self.time_format = "%Y-%m-%d %H:%M:%S"
60 self.db = SlabDB(config, debug = True)
64 def sliver_status(self, slice_urn, slice_hrn):
65 """Receive a status request for slice named urn/hrn
66 urn:publicid:IDN+senslab+nturro_slice hrn senslab.nturro_slice
67 shall return a structure as described in
68 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
69 NT : not sure if we should implement this or not, but used by sface.
73 #First get the slice with the slice hrn
74 slice_list = self.GetSlices(slice_filter = slice_hrn, \
75 slice_filter_type = 'slice_hrn')
77 if len(slice_list) is 0:
78 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
80 #Slice has the same slice hrn for each slice in the slice/lease list
81 #So fetch the info on the user once
82 one_slice = slice_list[0]
83 #recuser = dbsession.query(RegRecord).filter_by(record_id = \
84 #one_slice['record_id_user']).first()
86 #Make a list of all the nodes hostnames in use for this slice
88 for single_slice in slice_list:
89 for node in single_slice['node_ids']:
90 slice_nodes_list.append(node['hostname'])
92 #Get all the corresponding nodes details
93 nodes_all = self.GetNodes({'hostname':slice_nodes_list},
94 ['node_id', 'hostname','site','boot_state'])
95 nodeall_byhostname = dict([(one_node['hostname'], one_node) \
96 for one_node in nodes_all])
100 for single_slice in slice_list:
103 top_level_status = 'empty'
106 ['geni_urn','pl_login','geni_status','geni_resources'], None)
107 result['pl_login'] = one_slice['reg_researchers']['hrn']
108 logger.debug("Slabdriver - sliver_status Sliver status \
109 urn %s hrn %s single_slice %s \r\n " \
110 %(slice_urn, slice_hrn, single_slice))
112 nodes_in_slice = single_slice['node_ids']
115 result['geni_status'] = top_level_status
116 result['geni_resources'] = []
119 top_level_status = 'ready'
121 #A job is running on Senslab for this slice
122 # report about the local nodes that are in the slice only
124 result['geni_urn'] = slice_urn
128 #timestamp = float(sl['startTime']) + float(sl['walltime'])
129 #result['pl_expires'] = strftime(self.time_format, \
130 #gmtime(float(timestamp)))
131 #result['slab_expires'] = strftime(self.time_format,\
132 #gmtime(float(timestamp)))
135 for node in single_slice['node_ids']:
137 #res['slab_hostname'] = node['hostname']
138 #res['slab_boot_state'] = node['boot_state']
140 res['pl_hostname'] = node['hostname']
141 res['pl_boot_state'] = \
142 nodeall_byhostname[node['hostname']]['boot_state']
143 #res['pl_last_contact'] = strftime(self.time_format, \
144 #gmtime(float(timestamp)))
145 sliver_id = Xrn(slice_urn, type='slice', \
146 id=nodeall_byhostname[node['hostname']]['node_id'], \
147 authority=self.hrn).urn
149 res['geni_urn'] = sliver_id
150 node_name = node['hostname']
151 if nodeall_byhostname[node_name]['boot_state'] == 'Alive':
153 res['geni_status'] = 'ready'
155 res['geni_status'] = 'failed'
156 top_level_status = 'failed'
158 res['geni_error'] = ''
160 resources.append(res)
162 result['geni_status'] = top_level_status
163 result['geni_resources'] = resources
164 logger.debug("SLABDRIVER \tsliver_statusresources %s res %s "\
168 def get_user(self, hrn):
169 return dbsession.query(RegRecord).filter_by(hrn = hrn).first()
172 def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, \
174 aggregate = SlabAggregate(self)
176 slices = SlabSlices(self)
177 peer = slices.get_peer(slice_hrn)
178 sfa_peer = slices.get_sfa_peer(slice_hrn)
181 if not isinstance(creds, list):
185 slice_record = users[0].get('slice_record', {})
186 logger.debug("SLABDRIVER.PY \t ===============create_sliver \t\
187 creds %s \r\n \r\n users %s" \
189 slice_record['user'] = {'keys':users[0]['keys'], \
190 'email':users[0]['email'], \
191 'hrn':slice_record['reg-researchers'][0]}
193 rspec = RSpec(rspec_string)
194 logger.debug("SLABDRIVER.PY \t create_sliver \trspec.version \
195 %s slice_record %s users %s" \
196 %(rspec.version,slice_record, users))
199 # ensure site record exists?
200 # ensure slice record exists
201 #Removed options to verify_slice SA 14/08/12
202 sfa_slice = slices.verify_slice(slice_hrn, slice_record, peer, \
205 # ensure person records exists
206 #verify_persons returns added persons but since the return value
208 slices.verify_persons(slice_hrn, sfa_slice, users, peer, \
209 sfa_peer, options=options)
210 #requested_attributes returned by rspec.version.get_slice_attributes()
211 #unused, removed SA 13/08/12
212 rspec.version.get_slice_attributes()
214 logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice))
216 # add/remove slice from nodes
218 requested_slivers = [node.get('component_id') \
219 for node in rspec.version.get_nodes_with_slivers()\
220 if node.get('authority_id') is self.root_auth]
221 l = [ node for node in rspec.version.get_nodes_with_slivers() ]
222 logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
223 requested_slivers %s listnodes %s" \
224 %(requested_slivers,l))
225 #verify_slice_nodes returns nodes, but unused here. Removed SA 13/08/12.
226 #slices.verify_slice_nodes(sfa_slice, requested_slivers, peer)
229 requested_lease_list = []
231 logger.debug("SLABDRIVER.PY \tcreate_sliver AVANTLEASE " )
232 rspec_requested_leases = rspec.version.get_leases()
233 for lease in rspec.version.get_leases():
234 single_requested_lease = {}
235 logger.debug("SLABDRIVER.PY \tcreate_sliver lease %s " %(lease))
237 if not lease.get('lease_id'):
238 if get_authority(lease['component_id']) == self.root_auth:
239 single_requested_lease['hostname'] = \
240 slab_xrn_to_hostname(\
241 lease.get('component_id').strip())
242 single_requested_lease['start_time'] = \
243 lease.get('start_time')
244 single_requested_lease['duration'] = lease.get('duration')
246 requested_lease_list.append(single_requested_lease)
248 logger.debug("SLABDRIVER.PY \tcreate_sliver APRESLEASE" )
249 #dCreate dict of leases by start_time, regrouping nodes reserved
251 #time, for the same amount of time = one job on OAR
252 requested_job_dict = {}
253 for lease in requested_lease_list:
255 #In case it is an asap experiment start_time is empty
256 if lease['start_time'] == '':
257 lease['start_time'] = '0'
259 if lease['start_time'] not in requested_job_dict:
260 if isinstance(lease['hostname'], str):
261 lease['hostname'] = [lease['hostname']]
263 requested_job_dict[lease['start_time']] = lease
266 job_lease = requested_job_dict[lease['start_time']]
267 if lease['duration'] == job_lease['duration'] :
268 job_lease['hostname'].append(lease['hostname'])
273 logger.debug("SLABDRIVER.PY \tcreate_sliver requested_job_dict %s "\
274 %(requested_job_dict))
275 #verify_slice_leases returns the leases , but the return value is unused
276 #here. Removed SA 13/08/12
277 slices.verify_slice_leases(sfa_slice, \
278 requested_job_dict, peer)
280 return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
283 def delete_sliver (self, slice_urn, slice_hrn, creds, options):
285 sfa_slice_list = self.GetSlices(slice_filter = slice_hrn, \
286 slice_filter_type = 'slice_hrn')
288 if not sfa_slice_list:
291 #Delete all in the slice
292 for sfa_slice in sfa_slice_list:
295 logger.debug("SLABDRIVER.PY delete_sliver slice %s" %(sfa_slice))
296 slices = SlabSlices(self)
297 # determine if this is a peer slice
299 peer = slices.get_peer(slice_hrn)
300 #TODO delete_sliver SA : UnBindObjectFromPeer should be
301 #used when there is another
302 #senslab testbed, which is not the case 14/08/12 .
304 logger.debug("SLABDRIVER.PY delete_sliver peer %s" %(peer))
307 self.UnBindObjectFromPeer('slice', \
308 sfa_slice['record_id_slice'], \
310 self.DeleteSliceFromNodes(sfa_slice)
313 self.BindObjectToPeer('slice', \
314 sfa_slice['record_id_slice'], \
315 peer, sfa_slice['peer_slice_id'])
319 def AddSlice(self, slice_record, user_record):
320 """Add slice to the sfa tables and senslab table only if the user
321 already exists in senslab database(user already registered in LDAP).
322 There is no way to separate adding the slice to the tesbed
323 and then importing it from the testbed to SFA because of
324 senslab's architecture. Therefore, sfa tables are updated here.
327 sfa_record = RegSlice(hrn=slice_record['slice_hrn'],
328 gid=slice_record['gid'],
329 pointer=slice_record['slice_id'],
330 authority=slice_record['authority'])
332 logger.debug("SLABDRIVER.PY AddSlice sfa_record %s user_record %s" \
333 %(sfa_record, user_record))
334 sfa_record.just_created()
335 dbsession.add(sfa_record)
337 #Update the reg-researcher dependance table
338 sfa_record.reg_researchers = [user_record]
341 #Update the senslab table with the new slice
342 #slab_slice = SenslabXP( slice_hrn = slice_record['slice_hrn'], \
343 #record_id_slice = sfa_record.record_id , \
344 #record_id_user = slice_record['record_id_user'], \
345 #peer_authority = slice_record['peer_authority'])
347 #logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s \
348 #slab_slice %s sfa_record %s" \
349 #%(slice_record,slab_slice, sfa_record))
350 #slab_dbsession.add(slab_slice)
351 #slab_dbsession.commit()
354 # first 2 args are None in case of resource discovery
355 def list_resources (self, slice_urn, slice_hrn, creds, options):
356 #cached_requested = options.get('cached', True)
358 version_manager = VersionManager()
359 # get the rspec's return format from options
361 version_manager.get_version(options.get('geni_rspec_version'))
362 version_string = "rspec_%s" % (rspec_version)
364 #panos adding the info option to the caching key (can be improved)
365 if options.get('info'):
366 version_string = version_string + "_" + \
367 options.get('info', 'default')
369 # Adding the list_leases option to the caching key
370 if options.get('list_leases'):
371 version_string = version_string + "_"+options.get('list_leases', 'default')
373 # Adding geni_available to caching key
374 if options.get('geni_available'):
375 version_string = version_string + "_" + str(options.get('geni_available'))
377 # look in cache first
378 #if cached_requested and self.cache and not slice_hrn:
379 #rspec = self.cache.get(version_string)
381 #logger.debug("SlabDriver.ListResources: \
382 #returning cached advertisement")
385 #panos: passing user-defined options
386 aggregate = SlabAggregate(self)
387 #origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
388 #options.update({'origin_hrn':origin_hrn})
389 rspec = aggregate.get_rspec(slice_xrn=slice_urn, \
390 version=rspec_version, options=options)
393 #if self.cache and not slice_hrn:
394 #logger.debug("Slab.ListResources: stores advertisement in cache")
395 #self.cache.add(version_string, rspec)
400 def list_slices (self, creds, options):
401 # look in cache first
403 #slices = self.cache.get('slices')
405 #logger.debug("PlDriver.list_slices returns from cache")
410 slices = self.GetSlices()
411 logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices))
412 slice_hrns = [slab_slice['hrn'] for slab_slice in slices]
414 slice_urns = [hrn_to_urn(slice_hrn, 'slice') \
415 for slice_hrn in slice_hrns]
419 #logger.debug ("SlabDriver.list_slices stores value in cache")
420 #self.cache.add('slices', slice_urns)
425 def register (self, sfa_record, hrn, pub_key):
427 Adding new user, slice, node or site should not be handled
431 Adding users = LDAP Senslab
432 Adding slice = Import from LDAP users
438 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
439 """No site or node record update allowed in Senslab."""
441 pointer = old_sfa_record['pointer']
442 old_sfa_record_type = old_sfa_record['type']
444 # new_key implemented for users only
445 if new_key and old_sfa_record_type not in [ 'user' ]:
446 raise UnknownSfaType(old_sfa_record_type)
448 #if (type == "authority"):
449 #self.shell.UpdateSite(pointer, new_sfa_record)
451 if old_sfa_record_type == "slice":
452 slab_record = self.sfa_fields_to_slab_fields(old_sfa_record_type, \
454 if 'name' in slab_record:
455 slab_record.pop('name')
456 #Prototype should be UpdateSlice(self,
457 #auth, slice_id_or_name, slice_fields)
458 #Senslab cannot update slice since slice = job
459 #so we must delete and create another job
460 self.UpdateSlice(pointer, slab_record)
462 elif old_sfa_record_type == "user":
464 all_fields = new_sfa_record
465 for key in all_fields.keys():
466 if key in ['first_name', 'last_name', 'title', 'email',
467 'password', 'phone', 'url', 'bio', 'accepted_aup',
469 update_fields[key] = all_fields[key]
470 self.UpdatePerson(pointer, update_fields)
473 # must check this key against the previous one if it exists
474 persons = self.GetPersons([pointer], ['key_ids'])
476 keys = person['key_ids']
477 keys = self.GetKeys(person['key_ids'])
479 # Delete all stale keys
482 if new_key != key['key']:
483 self.DeleteKey(key['key_id'])
487 self.AddPersonKey(pointer, {'key_type': 'ssh', \
494 def remove (self, sfa_record):
495 sfa_record_type = sfa_record['type']
496 hrn = sfa_record['hrn']
497 if sfa_record_type == 'user':
499 #get user from senslab ldap
500 person = self.GetPersons(sfa_record)
501 #No registering at a given site in Senslab.
502 #Once registered to the LDAP, all senslab sites are
505 #Mark account as disabled in ldap
506 self.DeletePerson(sfa_record)
507 elif sfa_record_type == 'slice':
508 if self.GetSlices(slice_filter = hrn, \
509 slice_filter_type = 'slice_hrn'):
510 self.DeleteSlice(sfa_record)
512 #elif type == 'authority':
513 #if self.GetSites(pointer):
514 #self.DeleteSite(pointer)
520 #TODO clean GetPeers. 05/07/12SA
521 def GetPeers (self, auth = None, peer_filter=None, return_fields_list=None):
523 existing_records = {}
524 existing_hrns_by_types = {}
525 logger.debug("SLABDRIVER \tGetPeers auth = %s, peer_filter %s, \
526 return_field %s " %(auth , peer_filter, return_fields_list))
527 all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
529 for record in all_records:
530 existing_records[(record.hrn, record.type)] = record
531 if record.type not in existing_hrns_by_types:
532 existing_hrns_by_types[record.type] = [record.hrn]
534 existing_hrns_by_types[record.type].append(record.hrn)
537 logger.debug("SLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
538 %( existing_hrns_by_types))
543 records_list.append(existing_records[(peer_filter,'authority')])
545 for hrn in existing_hrns_by_types['authority']:
546 records_list.append(existing_records[(hrn,'authority')])
548 logger.debug("SLABDRIVER \tGetPeer \trecords_list %s " \
554 return_records = records_list
555 if not peer_filter and not return_fields_list:
559 logger.debug("SLABDRIVER \tGetPeer return_records %s " \
561 return return_records
564 #TODO : Handling OR request in make_ldap_filters_from_records
565 #instead of the for loop
566 #over the records' list
567 def GetPersons(self, person_filter=None):
569 person_filter should be a list of dictionnaries when not set to None.
570 Returns a list of users whose accounts are enabled found in ldap.
573 logger.debug("SLABDRIVER \tGetPersons person_filter %s" \
576 if person_filter and isinstance(person_filter, list):
577 #If we are looking for a list of users (list of dict records)
578 #Usually the list contains only one user record
579 for searched_attributes in person_filter:
581 #Get only enabled user accounts in senslab LDAP :
582 #add a filter for make_ldap_filters_from_record
583 person = self.ldap.LdapFindUser(searched_attributes, \
584 is_user_enabled=True)
585 #If a person was found, append it to the list
587 person_list.append(person)
589 #If the list is empty, return None
590 if len(person_list) is 0:
594 #Get only enabled user accounts in senslab LDAP :
595 #add a filter for make_ldap_filters_from_record
596 person_list = self.ldap.LdapFindUser(is_user_enabled=True)
600 def GetTimezone(self):
601 """ Get the OAR servier time and timezone.
602 Unused SA 16/11/12"""
603 server_timestamp, server_tz = self.oar.parser.\
604 SendRequest("GET_timezone")
605 return server_timestamp, server_tz
608 def DeleteJobs(self, job_id, slice_hrn):
609 if not job_id or job_id is -1:
611 username = slice_hrn.split(".")[-1].rstrip("_slice")
613 reqdict['method'] = "delete"
614 reqdict['strval'] = str(job_id)
617 answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id', \
619 logger.debug("SLABDRIVER \tDeleteJobs jobid %s \r\n answer %s \
620 username %s" %(job_id,answer, username))
625 ##TODO : Unused GetJobsId ? SA 05/07/12
626 #def GetJobsId(self, job_id, username = None ):
628 #Details about a specific job.
629 #Includes details about submission time, jot type, state, events,
630 #owner, assigned ressources, walltime etc...
634 #node_list_k = 'assigned_network_address'
635 ##Get job info from OAR
636 #job_info = self.oar.parser.SendRequest(req, job_id, username)
638 #logger.debug("SLABDRIVER \t GetJobsId %s " %(job_info))
640 #if job_info['state'] == 'Terminated':
641 #logger.debug("SLABDRIVER \t GetJobsId job %s TERMINATED"\
644 #if job_info['state'] == 'Error':
645 #logger.debug("SLABDRIVER \t GetJobsId ERROR message %s "\
650 #logger.error("SLABDRIVER \tGetJobsId KeyError")
653 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
655 ##Replaces the previous entry
656 ##"assigned_network_address" / "reserved_resources"
658 #job_info.update({'node_ids':parsed_job_info[node_list_k]})
659 #del job_info[node_list_k]
660 #logger.debug(" \r\nSLABDRIVER \t GetJobsId job_info %s " %(job_info))
664 def GetJobsResources(self, job_id, username = None):
665 #job_resources=['reserved_resources', 'assigned_resources',\
666 #'job_id', 'job_uri', 'assigned_nodes',\
668 #assigned_res = ['resource_id', 'resource_uri']
669 #assigned_n = ['node', 'node_uri']
671 req = "GET_jobs_id_resources"
674 #Get job resources list from OAR
675 node_id_list = self.oar.parser.SendRequest(req, job_id, username)
676 logger.debug("SLABDRIVER \t GetJobsResources %s " %(node_id_list))
679 self.__get_hostnames_from_oar_node_ids(node_id_list)
682 #Replaces the previous entry "assigned_network_address" /
683 #"reserved_resources"
685 job_info = {'node_ids': hostname_list}
690 def get_info_on_reserved_nodes(self, job_info, node_list_name):
691 #Get the list of the testbed nodes records and make a
692 #dictionnary keyed on the hostname out of it
693 node_list_dict = self.GetNodes()
694 #node_hostname_list = []
695 node_hostname_list = [node['hostname'] for node in node_list_dict]
696 #for node in node_list_dict:
697 #node_hostname_list.append(node['hostname'])
698 node_dict = dict(zip(node_hostname_list, node_list_dict))
700 reserved_node_hostname_list = []
701 for index in range(len(job_info[node_list_name])):
702 #job_info[node_list_name][k] =
703 reserved_node_hostname_list[index] = \
704 node_dict[job_info[node_list_name][index]]['hostname']
706 logger.debug("SLABDRIVER \t get_info_on_reserved_nodes \
707 reserved_node_hostname_list %s" \
708 %(reserved_node_hostname_list))
710 logger.error("SLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
712 return reserved_node_hostname_list
714 def GetNodesCurrentlyInUse(self):
715 """Returns a list of all the nodes already involved in an oar job"""
716 return self.oar.parser.SendRequest("GET_running_jobs")
718 def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
719 full_nodes_dict_list = self.GetNodes()
720 #Put the full node list into a dictionary keyed by oar node id
721 oar_id_node_dict = {}
722 for node in full_nodes_dict_list:
723 oar_id_node_dict[node['oar_id']] = node
725 #logger.debug("SLABDRIVER \t __get_hostnames_from_oar_node_ids\
726 #oar_id_node_dict %s" %(oar_id_node_dict))
728 hostname_dict_list = []
729 for resource_id in resource_id_list:
730 #Because jobs requested "asap" do not have defined resources
731 if resource_id is not "Undefined":
732 hostname_dict_list.append(\
733 oar_id_node_dict[resource_id]['hostname'])
735 #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
736 return hostname_dict_list
738 def GetReservedNodes(self,username = None):
739 #Get the nodes in use and the reserved nodes
740 reservation_dict_list = \
741 self.oar.parser.SendRequest("GET_reserved_nodes", \
745 for resa in reservation_dict_list:
746 logger.debug ("GetReservedNodes resa %s"%(resa))
747 #dict list of hostnames and their site
748 resa['reserved_nodes'] = \
749 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
751 #del resa['resource_ids']
752 return reservation_dict_list
754 def GetNodes(self, node_filter_dict = None, return_fields_list = None):
756 node_filter_dict : dictionnary of lists
759 node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
760 node_dict_list = node_dict_by_id.values()
761 logger.debug (" SLABDRIVER GetNodes node_filter_dict %s \
762 return_fields_list %s "%(node_filter_dict, return_fields_list))
763 #No filtering needed return the list directly
764 if not (node_filter_dict or return_fields_list):
765 return node_dict_list
767 return_node_list = []
769 for filter_key in node_filter_dict:
771 #Filter the node_dict_list by each value contained in the
772 #list node_filter_dict[filter_key]
773 for value in node_filter_dict[filter_key]:
774 for node in node_dict_list:
775 if node[filter_key] == value:
776 if return_fields_list :
778 for k in return_fields_list:
780 return_node_list.append(tmp)
782 return_node_list.append(node)
784 logger.log_exc("GetNodes KeyError")
788 return return_node_list
791 def GetSites(self, site_filter_name_list = None, return_fields_list = None):
792 site_dict = self.oar.parser.SendRequest("GET_sites")
793 #site_dict : dict where the key is the sit ename
794 return_site_list = []
795 if not ( site_filter_name_list or return_fields_list):
796 return_site_list = site_dict.values()
797 return return_site_list
799 for site_filter_name in site_filter_name_list:
800 if site_filter_name in site_dict:
801 if return_fields_list:
802 for field in return_fields_list:
805 tmp[field] = site_dict[site_filter_name][field]
807 logger.error("GetSites KeyError %s "%(field))
809 return_site_list.append(tmp)
811 return_site_list.append( site_dict[site_filter_name])
814 return return_site_list
817 def _sql_get_slice_info( self, slice_filter ):
818 #DO NOT USE RegSlice - reg_researchers to get the hrn
819 #of the user otherwise will mess up the RegRecord in
820 #Resolve, don't know why - SA 08/08/2012
822 #Only one entry for one user = one slice in slab_xp table
823 #slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
824 raw_slicerec = dbsession.query(RegSlice).options(joinedload('reg_researchers')).filter_by(hrn = slice_filter).first()
825 #raw_slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first()
828 #raw_slicerec.reg_researchers
829 raw_slicerec = raw_slicerec.__dict__
830 logger.debug(" SLABDRIVER \t get_slice_info slice_filter %s raw_slicerec %s"%(slice_filter,raw_slicerec))
831 slicerec = raw_slicerec
832 #only one researcher per slice so take the first one
833 #slicerec['reg_researchers'] = raw_slicerec['reg_researchers']
834 #del slicerec['reg_researchers']['_sa_instance_state']
841 def _sql_get_slice_info_from_user( self, slice_filter ):
842 #slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
843 raw_slicerec = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(record_id = slice_filter).first()
844 #raw_slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first()
845 #Put it in correct order
846 user_needed_fields = ['peer_authority', 'hrn', 'last_updated', 'classtype', 'authority', 'gid', 'record_id', 'date_created', 'type', 'email', 'pointer']
847 slice_needed_fields = ['peer_authority', 'hrn', 'last_updated', 'classtype', 'authority', 'gid', 'record_id', 'date_created', 'type', 'pointer']
849 #raw_slicerec.reg_slices_as_researcher
850 raw_slicerec = raw_slicerec.__dict__
852 slicerec = dict([(k,raw_slicerec['reg_slices_as_researcher'][0].__dict__[k]) for k in slice_needed_fields])
853 slicerec['reg_researchers'] = dict([(k, raw_slicerec[k]) for k in user_needed_fields])
854 #TODO Handle multiple slices for one user SA 10/12/12
855 #for now only take the first slice record associated to the rec user
856 ##slicerec = raw_slicerec['reg_slices_as_researcher'][0].__dict__
857 #del raw_slicerec['reg_slices_as_researcher']
858 #slicerec['reg_researchers'] = raw_slicerec
859 ##del slicerec['_sa_instance_state']
866 def _get_slice_records(self, slice_filter = None, \
867 slice_filter_type = None):
870 #Get list of slices based on the slice hrn
871 if slice_filter_type == 'slice_hrn':
873 if get_authority(slice_filter) == self.root_auth:
874 login = slice_filter.split(".")[1].split("_")[0]
876 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
897 def GetSlices(self, slice_filter = None, slice_filter_type = 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:
912 login, fixed_slicerec_dict = \
913 self._get_slice_records(slice_filter, slice_filter_type)
914 logger.debug(" SLABDRIVER \tGetSlices login %s \
915 slice record %s slice_filter %s slice_filter_type %s "\
916 %(login, fixed_slicerec_dict,slice_filter, slice_filter_type))
919 #Now we have the slice record fixed_slicerec_dict, get the
920 #jobs associated to this slice
921 #leases_list = self.GetReservedNodes(username = login)
922 leases_list = self.GetLeases(login = login)
923 #If no job is running or no job scheduled
924 #return only the slice record
925 if leases_list == [] and fixed_slicerec_dict:
926 return_slicerec_dictlist.append(fixed_slicerec_dict)
928 #If several jobs for one slice , put the slice record into
929 # each lease information dict
930 for lease in leases_list :
933 reserved_list = lease['reserved_nodes']
935 slicerec_dict['oar_job_id']= lease['lease_id']
936 slicerec_dict.update({'list_node_ids':{'hostname':reserved_list}})
937 slicerec_dict.update({'node_ids':lease['reserved_nodes']})
939 #Update lease dict with the slice record
940 if fixed_slicerec_dict:
941 fixed_slicerec_dict['oar_job_id'] = []
942 fixed_slicerec_dict['oar_job_id'].append(slicerec_dict['oar_job_id'])
943 slicerec_dict.update(fixed_slicerec_dict)
944 #slicerec_dict.update({'hrn':\
945 #str(fixed_slicerec_dict['slice_hrn'])})
948 return_slicerec_dictlist.append(slicerec_dict)
949 logger.debug("SLABDRIVER.PY \tGetSlices \
950 slicerec_dict %s return_slicerec_dictlist %s \
951 lease['reserved_nodes'] \
952 %s" %(slicerec_dict, return_slicerec_dictlist, \
953 lease['reserved_nodes'] ))
955 logger.debug("SLABDRIVER.PY \tGetSlices RETURN \
956 return_slicerec_dictlist %s" \
957 %(return_slicerec_dictlist))
959 return return_slicerec_dictlist
963 #Get all slices from the senslab sfa database ,
964 #put them in dict format
965 #query_slice_list = dbsession.query(RegRecord).all()
966 query_slice_list = dbsession.query(RegSlice).options(joinedload('reg_researchers')).all()
967 #query_slice_list = dbsession.query(RegRecord).filter_by(type='slice').all()
968 #query_slice_list = slab_dbsession.query(SenslabXP).all()
969 return_slicerec_dictlist = []
970 for record in query_slice_list:
971 tmp = record.__dict__
972 tmp['reg_researchers'] = tmp['reg_researchers'][0].__dict__
973 #del tmp['reg_researchers']['_sa_instance_state']
974 return_slicerec_dictlist.append(tmp)
975 #return_slicerec_dictlist.append(record.__dict__)
977 #Get all the jobs reserved nodes
978 leases_list = self.GetReservedNodes()
981 for fixed_slicerec_dict in return_slicerec_dictlist:
983 #Check if the slice belongs to a senslab user
984 if fixed_slicerec_dict['peer_authority'] is None:
985 owner = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0]
988 for lease in leases_list:
989 if owner == lease['user']:
990 slicerec_dict['oar_job_id'] = lease['lease_id']
992 #for reserved_node in lease['reserved_nodes']:
993 logger.debug("SLABDRIVER.PY \tGetSlices lease %s "\
996 reserved_list = lease['reserved_nodes']
998 slicerec_dict.update({'node_ids':lease['reserved_nodes']})
999 slicerec_dict.update({'list_node_ids':{'hostname':reserved_list}})
1000 slicerec_dict.update(fixed_slicerec_dict)
1001 #slicerec_dict.update({'hrn':\
1002 #str(fixed_slicerec_dict['slice_hrn'])})
1003 #return_slicerec_dictlist.append(slicerec_dict)
1004 fixed_slicerec_dict.update(slicerec_dict)
1006 logger.debug("SLABDRIVER.PY \tGetSlices RETURN \
1007 return_slicerec_dictlist %s \slice_filter %s " \
1008 %(return_slicerec_dictlist, slice_filter))
1010 return return_slicerec_dictlist
1013 def testbed_name (self): return self.hrn
1015 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
1016 def aggregate_version (self):
1017 version_manager = VersionManager()
1018 ad_rspec_versions = []
1019 request_rspec_versions = []
1020 for rspec_version in version_manager.versions:
1021 if rspec_version.content_type in ['*', 'ad']:
1022 ad_rspec_versions.append(rspec_version.to_dict())
1023 if rspec_version.content_type in ['*', 'request']:
1024 request_rspec_versions.append(rspec_version.to_dict())
1026 'testbed':self.testbed_name(),
1027 'geni_request_rspec_versions': request_rspec_versions,
1028 'geni_ad_rspec_versions': ad_rspec_versions,
1034 # Convert SFA fields to PLC fields for use when registering up updating
1035 # registry record in the PLC database
1037 # @param type type of record (user, slice, ...)
1038 # @param hrn human readable name
1039 # @param sfa_fields dictionary of SFA fields
1040 # @param slab_fields dictionary of PLC fields (output)
1042 def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
1046 #for field in record:
1047 # slab_record[field] = record[field]
1049 if sfa_type == "slice":
1050 #instantion used in get_slivers ?
1051 if not "instantiation" in slab_record:
1052 slab_record["instantiation"] = "senslab-instantiated"
1053 #slab_record["hrn"] = hrn_to_pl_slicename(hrn)
1054 #Unused hrn_to_pl_slicename because Slab's hrn already
1055 #in the appropriate form SA 23/07/12
1056 slab_record["hrn"] = hrn
1057 logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
1058 slab_record %s " %(slab_record['hrn']))
1060 slab_record["url"] = record["url"]
1061 if "description" in record:
1062 slab_record["description"] = record["description"]
1063 if "expires" in record:
1064 slab_record["expires"] = int(record["expires"])
1066 #nodes added by OAR only and then imported to SFA
1067 #elif type == "node":
1068 #if not "hostname" in slab_record:
1069 #if not "hostname" in record:
1070 #raise MissingSfaInfo("hostname")
1071 #slab_record["hostname"] = record["hostname"]
1072 #if not "model" in slab_record:
1073 #slab_record["model"] = "geni"
1076 #elif type == "authority":
1077 #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
1079 #if not "name" in slab_record:
1080 #slab_record["name"] = hrn
1082 #if not "abbreviated_name" in slab_record:
1083 #slab_record["abbreviated_name"] = hrn
1085 #if not "enabled" in slab_record:
1086 #slab_record["enabled"] = True
1088 #if not "is_public" in slab_record:
1089 #slab_record["is_public"] = True
1096 def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
1097 """ Transforms unix timestamp into valid OAR date format """
1099 #Used in case of a scheduled experiment (not immediate)
1100 #To run an XP immediately, don't specify date and time in RSpec
1101 #They will be set to None.
1102 if xp_utc_timestamp:
1103 #transform the xp_utc_timestamp into server readable time
1104 xp_server_readable_date = datetime.fromtimestamp(int(\
1105 xp_utc_timestamp)).strftime(self.time_format)
1107 return xp_server_readable_date
1115 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
1116 lease_start_time, lease_duration, slice_user=None):
1118 lease_dict['lease_start_time'] = lease_start_time
1119 lease_dict['lease_duration'] = lease_duration
1120 lease_dict['added_nodes'] = added_nodes
1121 lease_dict['slice_name'] = slice_name
1122 lease_dict['slice_user'] = slice_user
1123 lease_dict['grain'] = self.GetLeaseGranularity()
1124 lease_dict['time_format'] = self.time_format
1127 def __create_job_structure_request_for_OAR(lease_dict):
1128 """ Creates the structure needed for a correct POST on OAR.
1129 Makes the timestamp transformation into the appropriate format.
1130 Sends the POST request to create the job with the resources in
1139 reqdict['workdir'] = '/tmp'
1140 reqdict['resource'] = "{network_address in ("
1142 for node in lease_dict['added_nodes']:
1143 logger.debug("\r\n \r\n OARrestapi \t \
1144 __create_job_structure_request_for_OAR node %s" %(node))
1146 # Get the ID of the node
1148 reqdict['resource'] += "'" + nodeid + "', "
1149 nodeid_list.append(nodeid)
1151 custom_length = len(reqdict['resource'])- 2
1152 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
1153 ")}/nodes=" + str(len(nodeid_list))
1155 def __process_walltime(duration):
1156 """ Calculates the walltime in seconds from the duration in H:M:S
1157 specified in the RSpec.
1161 # Fixing the walltime by adding a few delays.
1162 # First put the walltime in seconds oarAdditionalDelay = 20;
1163 # additional delay for /bin/sleep command to
1164 # take in account prologue and epilogue scripts execution
1165 # int walltimeAdditionalDelay = 240; additional delay
1166 desired_walltime = duration
1167 total_walltime = desired_walltime + 240 #+4 min Update SA 23/10/12
1168 sleep_walltime = desired_walltime # 0 sec added Update SA 23/10/12
1170 #Put the walltime back in str form
1171 #First get the hours
1172 walltime.append(str(total_walltime / 3600))
1173 total_walltime = total_walltime - 3600 * int(walltime[0])
1174 #Get the remaining minutes
1175 walltime.append(str(total_walltime / 60))
1176 total_walltime = total_walltime - 60 * int(walltime[1])
1178 walltime.append(str(total_walltime))
1181 logger.log_exc(" __process_walltime duration null")
1183 return walltime, sleep_walltime
1186 walltime, sleep_walltime = \
1187 __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1190 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1191 ":" + str(walltime[1]) + ":" + str(walltime[2])
1192 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1194 #In case of a scheduled experiment (not immediate)
1195 #To run an XP immediately, don't specify date and time in RSpec
1196 #They will be set to None.
1197 if lease_dict['lease_start_time'] is not '0':
1198 #Readable time accepted by OAR
1199 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1200 strftime(lease_dict['time_format'])
1201 reqdict['reservation'] = start_time
1202 #If there is not start time, Immediate XP. No need to add special
1206 reqdict['type'] = "deploy"
1207 reqdict['directory'] = ""
1208 reqdict['name'] = "SFA_" + lease_dict['slice_user']
1213 #Create the request for OAR
1214 reqdict = __create_job_structure_request_for_OAR(lease_dict)
1215 # first step : start the OAR job and update the job
1216 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1219 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1220 reqdict, slice_user)
1221 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s " %(answer))
1223 jobid = answer['id']
1225 logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1226 Impossible to create job %s " %(answer))
1230 def __configure_experiment(jobid, added_nodes):
1231 # second step : configure the experiment
1232 # we need to store the nodes in a yaml (well...) file like this :
1233 # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1234 tmp_dir = '/tmp/sfa/'
1235 if not os.path.exists(tmp_dir):
1236 os.makedirs(tmp_dir)
1237 job_file = open(tmp_dir + str(jobid) + '.json', 'w')
1239 job_file.write(str(added_nodes[0].strip('node')))
1240 for node in added_nodes[1:len(added_nodes)] :
1241 job_file.write(', '+ node.strip('node'))
1246 def __launch_senslab_experiment(jobid):
1247 # third step : call the senslab-experiment wrapper
1248 #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar
1249 # "+str(jobid)+" "+slice_user
1250 javacmdline = "/usr/bin/java"
1252 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1254 output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1255 slice_user],stdout=subprocess.PIPE).communicate()[0]
1257 logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1264 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1265 added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1268 __configure_experiment(jobid, added_nodes)
1269 __launch_senslab_experiment(jobid)
1274 def AddLeases(self, hostname_list, slice_record, \
1275 lease_start_time, lease_duration):
1276 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s \
1277 slice_record %s lease_start_time %s lease_duration %s "\
1278 %( hostname_list, slice_record , lease_start_time, \
1281 #tmp = slice_record['reg-researchers'][0].split(".")
1282 username = slice_record['user']['uid']
1283 #username = tmp[(len(tmp)-1)]
1284 job_id = self.LaunchExperimentOnOAR(hostname_list, slice_record['hrn'], \
1285 lease_start_time, lease_duration, username)
1286 start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1287 end_time = lease_start_time + lease_duration
1288 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases %s %s %s " %(type(slice_record['hrn']), type(job_id), type(end_time)))
1289 slab_ex_row = SenslabXP(slice_record['hrn'], job_id, end_time)
1290 logger.debug("SLABDRIVER \r\n \r\n \t slab_ex_row %s" %(slab_ex_row))
1291 slab_dbsession.add(slab_ex_row)
1292 slab_dbsession.commit()
1294 logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1299 #Delete the jobs from job_senslab table
1300 def DeleteSliceFromNodes(self, slice_record):
1301 for job_id in slice_record['oar_job_id']:
1302 self.DeleteJobs(job_id, slice_record['hrn'])
1306 def GetLeaseGranularity(self):
1307 """ Returns the granularity of Senslab testbed.
1308 OAR returns seconds for experiments duration.
1309 Defined in seconds. """
1314 def update_jobs_in_slabdb(self, job_oar_list, jobs_psql):
1315 #Get all the entries in slab_xp table
1318 jobs_psql = set(jobs_psql)
1319 kept_jobs = set(job_oar_list).intersection(jobs_psql)
1321 deleted_jobs = set(jobs_psql).difference(kept_jobs)
1322 deleted_jobs = list(deleted_jobs)
1323 if len(deleted_jobs) > 0:
1324 slab_dbsession.query(SenslabXP).filter(SenslabXP.job_id.in_(deleted_jobs)).delete(synchronize_session='fetch')
1325 slab_dbsession.commit()
1331 def GetLeases(self, lease_filter_dict=None, login=None):
1334 unfiltered_reservation_list = self.GetReservedNodes(login)
1336 reservation_list = []
1337 #Find the slice associated with this user senslab ldap uid
1338 logger.debug(" SLABDRIVER.PY \tGetLeases unfiltered_reservation_list %s " %(unfiltered_reservation_list))
1339 #Create user dict first to avoid looking several times for
1340 #the same user in LDAP SA 27/07/12
1344 jobs_psql_query = slab_dbsession.query(SenslabXP).all()
1345 jobs_psql_dict = [ (row.job_id, row.__dict__ )for row in jobs_psql_query ]
1346 jobs_psql_dict = dict(jobs_psql_dict)
1347 logger.debug("SLABDRIVER \tGetLeases jobs_psql_dict %s"\
1349 jobs_psql_id_list = [ row.job_id for row in jobs_psql_query ]
1353 for resa in unfiltered_reservation_list:
1354 logger.debug("SLABDRIVER \tGetLeases USER %s"\
1356 #Cosntruct list of jobs (runing, waiting..) in oar
1357 job_oar_list.append(resa['lease_id'])
1358 #If there is information on the job in SLAB DB (slice used and job id)
1359 if resa['lease_id'] in jobs_psql_dict:
1360 job_info = jobs_psql_dict[resa['lease_id']]
1361 logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1363 resa['slice_hrn'] = job_info['slice_hrn']
1364 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1366 #Assume it is a senslab slice:
1368 resa['slice_id'] = hrn_to_urn(self.root_auth+'.'+ resa['user'] +"_slice" , 'slice')
1369 #if resa['user'] not in resa_user_dict:
1370 #logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1371 #ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1373 #ldap_info = ldap_info[0][1]
1374 ##Get the backref :relationship table reg-researchers
1375 #user = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(email = \
1376 #ldap_info['mail'][0])
1378 #user = user.first()
1379 #user = user.__dict__
1380 #slice_info = user['reg_slices_as_researcher'][0].__dict__
1381 ##Separated in case user not in database :
1382 ##record_id not defined SA 17/07//12
1384 ##query_slice_info = slab_dbsession.query(SenslabXP).filter_by(record_id_user = user.record_id)
1385 ##if query_slice_info:
1386 ##slice_info = query_slice_info.first()
1390 #resa_user_dict[resa['user']] = {}
1391 #resa_user_dict[resa['user']]['ldap_info'] = user
1392 #resa_user_dict[resa['user']]['slice_info'] = slice_info
1394 #resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info']['hrn']
1395 #resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1398 resa['component_id_list'] = []
1399 resa['hrn'] = Xrn(resa['slice_id']).get_hrn()
1400 #Transform the hostnames into urns (component ids)
1401 for node in resa['reserved_nodes']:
1402 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1403 #self.root_auth, node['hostname']))
1404 slab_xrn = slab_xrn_object(self.root_auth, node)
1405 resa['component_id_list'].append(slab_xrn.urn)
1407 if lease_filter_dict:
1408 logger.debug("SLABDRIVER \tGetLeases resa_ %s \r\n leasefilter %s"\
1409 %(resa,lease_filter_dict))
1411 if lease_filter_dict['name'] == resa['slice_hrn']:
1412 reservation_list.append(resa)
1414 if lease_filter_dict is None:
1415 reservation_list = unfiltered_reservation_list
1417 #del unfiltered_reservation_list[unfiltered_reservation_list.index(resa)]
1420 self.update_jobs_in_slabdb(job_oar_list, jobs_psql_id_list)
1422 #for resa in unfiltered_reservation_list:
1426 #if resa['user'] in resa_user_dict:
1427 #resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info']['hrn']
1428 #resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1430 ##resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1431 #resa['component_id_list'] = []
1432 ##Transform the hostnames into urns (component ids)
1433 #for node in resa['reserved_nodes']:
1434 ##resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1435 ##self.root_auth, node['hostname']))
1436 #slab_xrn = slab_xrn_object(self.root_auth, node)
1437 #resa['component_id_list'].append(slab_xrn.urn)
1439 ##Filter the reservation list if necessary
1440 ##Returns all the leases associated with a given slice
1441 #if lease_filter_dict:
1442 #logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1443 #%(lease_filter_dict))
1444 #for resa in unfiltered_reservation_list:
1445 #if lease_filter_dict['name'] == resa['slice_hrn']:
1446 #reservation_list.append(resa)
1448 #reservation_list = unfiltered_reservation_list
1450 logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1451 %(reservation_list))
1452 return reservation_list
1454 def augment_records_with_testbed_info (self, sfa_records):
1455 return self.fill_record_info (sfa_records)
1457 def fill_record_info(self, record_list):
1459 Given a SFA record, fill in the senslab specific and SFA specific
1460 fields in the record.
1463 logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1464 if not isinstance(record_list, list):
1465 record_list = [record_list]
1468 for record in record_list:
1469 #If the record is a SFA slice record, then add information
1470 #about the user of this slice. This kind of
1471 #information is in the Senslab's DB.
1472 if str(record['type']) == 'slice':
1473 if 'reg_researchers' in record and isinstance(record['reg_researchers'],list) :
1474 record['reg_researchers'] = record['reg_researchers'][0].__dict__
1475 record.update({'PI':[record['reg_researchers']['hrn']],
1476 'researcher': [record['reg_researchers']['hrn']],
1477 'name':record['hrn'],
1480 'person_ids':[record['reg_researchers']['record_id']],
1481 'geni_urn':'', #For client_helper.py compatibility
1482 'keys':'', #For client_helper.py compatibility
1483 'key_ids':''}) #For client_helper.py compatibility
1486 #Get slab slice record.
1487 recslice_list = self.GetSlices(slice_filter = \
1488 str(record['hrn']),\
1489 slice_filter_type = 'slice_hrn')
1491 #recuser = recslice_list[0]['reg_researchers']
1492 ##recuser = dbsession.query(RegRecord).filter_by(record_id = \
1493 ##recslice_list[0]['record_id_user']).first()
1495 #record.update({'PI':[recuser['hrn']],
1496 #'researcher': [recuser['hrn']],
1497 #'name':record['hrn'],
1500 #'person_ids':[recslice_list[0]['reg_researchers']['record_id']],
1501 #'geni_urn':'', #For client_helper.py compatibility
1502 #'keys':'', #For client_helper.py compatibility
1503 #'key_ids':''}) #For client_helper.py compatibility
1504 logger.debug("SLABDRIVER \tfill_record_info TYPE SLICE RECUSER record['hrn'] %s ecord['oar_job_id'] %s " %(record['hrn'],record['oar_job_id']))
1506 for rec in recslice_list:
1507 logger.debug("SLABDRIVER\r\n \t \t fill_record_info oar_job_id %s " %(rec['oar_job_id']))
1508 #record['oar_job_id'].append(rec['oar_job_id'])
1509 #del record['_sa_instance_state']
1510 del record['reg_researchers']
1511 record['node_ids'] = [ self.root_auth + hostname for hostname in rec['node_ids']]
1515 logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1516 recslice_list %s \r\n \t RECORD %s \r\n \r\n" %(recslice_list,record))
1517 if str(record['type']) == 'user':
1518 #The record is a SFA user record.
1519 #Get the information about his slice from Senslab's DB
1520 #and add it to the user record.
1521 recslice_list = self.GetSlices(\
1522 slice_filter = record['record_id'],\
1523 slice_filter_type = 'record_id_user')
1525 logger.debug( "SLABDRIVER.PY \t fill_record_info TYPE USER \
1526 recslice_list %s \r\n \t RECORD %s \r\n" %(recslice_list , record))
1527 #Append slice record in records list,
1528 #therefore fetches user and slice info again(one more loop)
1529 #Will update PIs and researcher for the slice
1530 #recuser = dbsession.query(RegRecord).filter_by(record_id = \
1531 #recslice_list[0]['record_id_user']).first()
1532 recuser = recslice_list[0]['reg_researchers']
1533 logger.debug( "SLABDRIVER.PY \t fill_record_info USER \
1534 recuser %s \r\n \r\n" %(recuser))
1536 recslice = recslice_list[0]
1537 recslice.update({'PI':[recuser['hrn']],
1538 'researcher': [recuser['hrn']],
1539 'name':record['hrn'],
1542 'person_ids':[recuser['record_id']]})
1544 for rec in recslice_list:
1545 recslice['oar_job_id'].append(rec['oar_job_id'])
1549 recslice.update({'type':'slice', \
1550 'hrn':recslice_list[0]['hrn']})
1553 #GetPersons takes [] as filters
1554 #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1555 user_slab = self.GetPersons([record])
1558 record.update(user_slab[0])
1559 #For client_helper.py compatibility
1560 record.update( { 'geni_urn':'',
1563 record_list.append(recslice)
1565 logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1566 INFO TO USER records %s" %(record_list))
1568 logger.debug("SLABDRIVER.PY \tfill_record_info END \
1569 record %s \r\n \r\n " %(record))
1571 except TypeError, error:
1572 logger.log_exc("SLABDRIVER \t fill_record_info EXCEPTION %s"\
1574 #logger.debug("SLABDRIVER.PY \t fill_record_info ENDENDEND ")
1578 #self.fill_record_slab_info(records)
1584 #TODO Update membership? update_membership_list SA 05/07/12
1585 #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1587 ## get a list of the HRNs tht are members of the old and new records
1589 #oldList = oldRecord.get(listName, [])
1592 #newList = record.get(listName, [])
1594 ## if the lists are the same, then we don't have to update anything
1595 #if (oldList == newList):
1598 ## build a list of the new person ids, by looking up each person to get
1602 #records = table.find({'type': 'user', 'hrn': newList})
1603 #for rec in records:
1604 #newIdList.append(rec['pointer'])
1606 ## build a list of the old person ids from the person_ids field
1608 #oldIdList = oldRecord.get("person_ids", [])
1609 #containerId = oldRecord.get_pointer()
1611 ## if oldRecord==None, then we are doing a Register, instead of an
1614 #containerId = record.get_pointer()
1616 ## add people who are in the new list, but not the oldList
1617 #for personId in newIdList:
1618 #if not (personId in oldIdList):
1619 #addFunc(self.plauth, personId, containerId)
1621 ## remove people who are in the old list, but not the new list
1622 #for personId in oldIdList:
1623 #if not (personId in newIdList):
1624 #delFunc(self.plauth, personId, containerId)
1626 #def update_membership(self, oldRecord, record):
1628 #if record.type == "slice":
1629 #self.update_membership_list(oldRecord, record, 'researcher',
1630 #self.users.AddPersonToSlice,
1631 #self.users.DeletePersonFromSlice)
1632 #elif record.type == "authority":
1637 # I don't think you plan on running a component manager at this point
1638 # let me clean up the mess of ComponentAPI that is deprecated anyways
1641 #TODO FUNCTIONS SECTION 04/07/2012 SA
1643 #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1645 def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1646 """ This method is a hopefully temporary hack to let the sfa correctly
1647 detach the objects it creates from a remote peer object. This is
1648 needed so that the sfa federation link can work in parallel with
1649 RefreshPeer, as RefreshPeer depends on remote objects being correctly
1652 auth : struct, API authentication structure
1653 AuthMethod : string, Authentication method to use
1654 object_type : string, Object type, among 'site','person','slice',
1656 object_id : int, object_id
1657 shortname : string, peer shortname
1661 logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1665 #TODO Is BindObjectToPeer still necessary ? Currently does nothing
1667 def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1668 remote_object_id=None):
1669 """This method is a hopefully temporary hack to let the sfa correctly
1670 attach the objects it creates to a remote peer object. This is needed
1671 so that the sfa federation link can work in parallel with RefreshPeer,
1672 as RefreshPeer depends on remote objects being correctly marked.
1674 shortname : string, peer shortname
1675 remote_object_id : int, remote object_id, set to 0 if unknown
1679 logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1682 #TODO UpdateSlice 04/07/2012 SA
1683 #Funciton should delete and create another job since oin senslab slice=job
1684 def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1685 """Updates the parameters of an existing slice with the values in
1687 Users may only update slices of which they are members.
1688 PIs may update any of the slices at their sites, or any slices of
1689 which they are members. Admins may update any slice.
1690 Only PIs and admins may update max_nodes. Slices cannot be renewed
1691 (by updating the expires parameter) more than 8 weeks into the future.
1692 Returns 1 if successful, faults otherwise.
1696 logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1699 #TODO UpdatePerson 04/07/2012 SA
1700 def UpdatePerson(self, slab_hrn, federated_hrn, person_fields=None):
1701 """Updates a person. Only the fields specified in person_fields
1702 are updated, all other fields are left untouched.
1703 Users and techs can only update themselves. PIs can only update
1704 themselves and other non-PIs at their sites.
1705 Returns 1 if successful, faults otherwise.
1709 #new_row = FederatedToSenslab(slab_hrn, federated_hrn)
1710 #slab_dbsession.add(new_row)
1711 #slab_dbsession.commit()
1713 logger.debug("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1716 #TODO GetKeys 04/07/2012 SA
1717 def GetKeys(self, auth, key_filter=None, return_fields=None):
1718 """Returns an array of structs containing details about keys.
1719 If key_filter is specified and is an array of key identifiers,
1720 or a struct of key attributes, only keys matching the filter
1721 will be returned. If return_fields is specified, only the
1722 specified details will be returned.
1724 Admin may query all keys. Non-admins may only query their own keys.
1728 logger.warning("SLABDRIVER GetKeys EMPTY - DO NOTHING \r\n ")
1731 #TODO DeleteKey 04/07/2012 SA
1732 def DeleteKey(self, auth, key_id):
1734 Non-admins may only delete their own keys.
1735 Returns 1 if successful, faults otherwise.
1739 logger.warning("SLABDRIVER DeleteKey EMPTY - DO NOTHING \r\n ")
1743 #TODO : Check rights to delete person
1744 def DeletePerson(self, auth, person_record):
1745 """ Disable an existing account in senslab LDAP.
1746 Users and techs can only delete themselves. PIs can only
1747 delete themselves and other non-PIs at their sites.
1748 ins can delete anyone.
1749 Returns 1 if successful, faults otherwise.
1753 #Disable user account in senslab LDAP
1754 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1755 logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1758 #TODO Check DeleteSlice, check rights 05/07/2012 SA
1759 def DeleteSlice(self, auth, slice_record):
1760 """ Deletes the specified slice.
1761 Senslab : Kill the job associated with the slice if there is one
1762 using DeleteSliceFromNodes.
1763 Updates the slice record in slab db to remove the slice nodes.
1765 Users may only delete slices of which they are members. PIs may
1766 delete any of the slices at their sites, or any slices of which
1767 they are members. Admins may delete any slice.
1768 Returns 1 if successful, faults otherwise.
1772 self.DeleteSliceFromNodes(slice_record)
1773 logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1776 #TODO AddPerson 04/07/2012 SA
1777 #def AddPerson(self, auth, person_fields=None):
1778 def AddPerson(self, record):#TODO fixing 28/08//2012 SA
1779 """Adds a new account. Any fields specified in records are used,
1780 otherwise defaults are used.
1781 Accounts are disabled by default. To enable an account,
1783 Returns the new person_id (> 0) if successful, faults otherwise.
1787 ret = self.ldap.LdapAddUser(record)
1788 logger.debug("SLABDRIVER AddPerson return code %s \r\n "%(ret))
1791 #TODO AddPersonToSite 04/07/2012 SA
1792 def AddPersonToSite (self, auth, person_id_or_email, \
1793 site_id_or_login_base=None):
1794 """ Adds the specified person to the specified site. If the person is
1795 already a member of the site, no errors are returned. Does not change
1796 the person's primary site.
1797 Returns 1 if successful, faults otherwise.
1801 logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1804 #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1805 def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1806 """Grants the specified role to the person.
1807 PIs can only grant the tech and user roles to users and techs at their
1808 sites. Admins can grant any role to any user.
1809 Returns 1 if successful, faults otherwise.
1813 logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1816 #TODO AddPersonKey 04/07/2012 SA
1817 def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1818 """Adds a new key to the specified account.
1819 Non-admins can only modify their own keys.
1820 Returns the new key_id (> 0) if successful, faults otherwise.
1824 logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1827 def DeleteLeases(self, leases_id_list, slice_hrn ):
1828 logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \
1829 \r\n " %(leases_id_list, slice_hrn))
1830 for job_id in leases_id_list:
1831 self.DeleteJobs(job_id, slice_hrn)