3 from datetime import datetime
4 from dateutil import tz
5 from time import strftime, gmtime
7 from sfa.util.faults import SliverDoesNotExist, UnknownSfaType
8 from sfa.util.sfalogging import logger
10 from sfa.storage.alchemy import dbsession
11 from sfa.storage.model import RegRecord, RegUser, RegSlice
13 from sfa.trust.credential import Credential
16 from sfa.managers.driver import Driver
17 from sfa.rspecs.version_manager import VersionManager
18 from sfa.rspecs.rspec import RSpec
20 from sfa.util.xrn import hrn_to_urn, urn_to_sliver_id, get_leaf
23 ## thierry: everything that is API-related (i.e. handling incoming requests)
25 # SlabDriver should be really only about talking to the senslab testbed
28 from sfa.senslab.OARrestapi import OARrestapi
29 from sfa.senslab.LDAPapi import LDAPapi
31 from sfa.senslab.slabpostgres import SlabDB, slab_dbsession, SliceSenslab
32 from sfa.senslab.slabaggregate import SlabAggregate, slab_xrn_to_hostname, slab_xrn_object
33 from sfa.senslab.slabslices import SlabSlices
40 # this inheritance scheme is so that the driver object can receive
41 # GetNodes or GetSites sorts of calls directly
42 # and thus minimize the differences in the managers with the pl version
43 class SlabDriver(Driver):
45 def __init__(self, config):
46 Driver.__init__ (self, config)
48 self.hrn = config.SFA_INTERFACE_HRN
50 self.root_auth = config.SFA_REGISTRY_ROOT_AUTH
52 self.oar = OARrestapi()
54 self.time_format = "%Y-%m-%d %H:%M:%S"
55 self.db = SlabDB(config,debug = True)
59 def sliver_status(self, slice_urn, slice_hrn):
60 """Receive a status request for slice named urn/hrn
61 urn:publicid:IDN+senslab+nturro_slice hrn senslab.nturro_slice
62 shall return a structure as described in
63 http://groups.geni.net/geni/wiki/GAPI_AM_API_V2#SliverStatus
64 NT : not sure if we should implement this or not, but used by sface.
68 #First get the slice with the slice hrn
69 sl = self.GetSlices(slice_filter = slice_hrn, \
70 slice_filter_type = 'slice_hrn')
72 raise SliverDoesNotExist("%s slice_hrn" % (slice_hrn))
74 top_level_status = 'unknown'
75 nodes_in_slice = sl['node_ids']
76 recuser = dbsession.query(RegRecord).filter_by(record_id = \
77 sl['record_id_user']).first()
78 sl.update({'user':recuser.hrn})
79 if len(nodes_in_slice) is 0:
80 raise SliverDoesNotExist("No slivers allocated ")
82 top_level_status = 'ready'
84 logger.debug("Slabdriver - sliver_status Sliver status urn %s hrn %s sl\
85 %s \r\n " %(slice_urn, slice_hrn, sl))
87 if sl['oar_job_id'] is not -1:
88 #A job is running on Senslab for this slice
89 # report about the local nodes that are in the slice only
91 nodes_all = self.GetNodes({'hostname':nodes_in_slice},
92 ['node_id', 'hostname','site','boot_state'])
93 nodeall_byhostname = dict([(n['hostname'], n) for n in nodes_all])
97 result['geni_urn'] = slice_urn
98 result['pl_login'] = sl['user'] #For compatibility
101 timestamp = float(sl['startTime']) + float(sl['walltime'])
102 result['pl_expires'] = strftime(self.time_format, \
103 gmtime(float(timestamp)))
104 #result['slab_expires'] = strftime(self.time_format,\
105 #gmtime(float(timestamp)))
108 for node in nodeall_byhostname:
110 #res['slab_hostname'] = node['hostname']
111 #res['slab_boot_state'] = node['boot_state']
113 res['pl_hostname'] = nodeall_byhostname[node]['hostname']
114 res['pl_boot_state'] = nodeall_byhostname[node]['boot_state']
115 res['pl_last_contact'] = strftime(self.time_format, \
116 gmtime(float(timestamp)))
117 sliver_id = urn_to_sliver_id(slice_urn, sl['record_id_slice'], \
118 nodeall_byhostname[node]['node_id'])
119 res['geni_urn'] = sliver_id
120 if nodeall_byhostname[node]['boot_state'] == 'Alive':
122 res['geni_status'] = 'ready'
124 res['geni_status'] = 'failed'
125 top_level_status = 'failed'
127 res['geni_error'] = ''
129 resources.append(res)
131 result['geni_status'] = top_level_status
132 result['geni_resources'] = resources
133 logger.debug("SLABDRIVER \tsliver_statusresources %s res %s "\
138 def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, \
140 aggregate = SlabAggregate(self)
142 slices = SlabSlices(self)
143 peer = slices.get_peer(slice_hrn)
144 sfa_peer = slices.get_sfa_peer(slice_hrn)
147 if not isinstance(creds, list):
151 slice_record = users[0].get('slice_record', {})
154 rspec = RSpec(rspec_string)
155 logger.debug("SLABDRIVER.PY \tcreate_sliver \trspec.version %s " \
159 # ensure site record exists?
160 # ensure slice record exists
161 sfa_slice = slices.verify_slice(slice_hrn, slice_record, peer, \
162 sfa_peer, options=options)
163 requested_attributes = rspec.version.get_slice_attributes()
165 logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice))
167 # ensure person records exists
168 persons = slices.verify_persons(slice_hrn, sfa_slice, users, peer, \
169 sfa_peer, options=options)
173 # add/remove slice from nodes
175 requested_slivers = [node.get('component_name') \
176 for node in rspec.version.get_nodes_with_slivers()]
177 l = [ node for node in rspec.version.get_nodes_with_slivers() ]
178 logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
179 requested_slivers %s listnodes %s" %(requested_slivers,l))
181 nodes = slices.verify_slice_nodes(sfa_slice, requested_slivers, peer)
184 requested_lease_list = []
186 for lease in rspec.version.get_leases():
187 single_requested_lease = {}
188 logger.debug("SLABDRIVER.PY \tcreate_sliver lease %s " %(lease))
189 if not lease.get('lease_id'):
190 single_requested_lease['hostname'] = \
191 slab_xrn_to_hostname(lease.get('component_id').strip())
192 single_requested_lease['start_time'] = lease.get('start_time')
193 single_requested_lease['duration'] = lease.get('duration')
195 kept_leases.append(int(lease['lease_id']))
196 if single_requested_lease.get('hostname'):
197 requested_lease_list.append(single_requested_lease)
199 #dCreate dict of leases by start_time, regrouping nodes reserved at the same
200 #time, for the same amount of time = one job on OAR
201 requested_job_dict = {}
202 for lease in requested_lease_list:
204 #In case it is an asap experiment start_time is empty
205 if lease['start_time'] == '':
206 lease['start_time'] = '0'
208 if lease['start_time'] not in requested_job_dict:
209 if isinstance(lease['hostname'], str):
210 lease['hostname'] = [lease['hostname']]
212 requested_job_dict[lease['start_time']] = lease
215 job_lease = requested_job_dict[lease['start_time']]
216 if lease['duration'] == job_lease['duration'] :
217 job_lease['hostname'].append(lease['hostname'])
222 logger.debug("SLABDRIVER.PY \tcreate_sliver requested_job_dict %s " %(requested_job_dict))
224 leases = slices.verify_slice_leases(sfa_slice, \
225 requested_job_dict, kept_leases, peer)
227 return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
230 def delete_sliver (self, slice_urn, slice_hrn, creds, options):
232 sfa_slice = self.GetSlices(slice_filter = slice_hrn, \
233 slice_filter_type = 'slice_hrn')
234 logger.debug("SLABDRIVER.PY delete_sliver slice %s" %(sfa_slice))
238 slices = SlabSlices(self)
239 # determine if this is a peer slice
241 peer = slices.get_peer(slice_hrn)
242 logger.debug("SLABDRIVER.PY delete_sliver peer %s" %(peer))
245 self.UnBindObjectFromPeer('slice', \
246 sfa_slice['record_id_slice'], peer)
247 self.DeleteSliceFromNodes(sfa_slice)
250 self.BindObjectToPeer('slice', sfa_slice['record_id_slice'], \
251 peer, sfa_slice['peer_slice_id'])
255 def AddSlice(self, slice_record):
256 slab_slice = SliceSenslab( slice_hrn = slice_record['slice_hrn'], \
257 record_id_slice= slice_record['record_id_slice'] , \
258 record_id_user= slice_record['record_id_user'], \
259 peer_authority = slice_record['peer_authority'])
260 logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s slab_slice %s" \
261 %(slice_record,slab_slice))
262 slab_dbsession.add(slab_slice)
263 slab_dbsession.commit()
266 # first 2 args are None in case of resource discovery
267 def list_resources (self, slice_urn, slice_hrn, creds, options):
268 #cached_requested = options.get('cached', True)
270 version_manager = VersionManager()
271 # get the rspec's return format from options
273 version_manager.get_version(options.get('geni_rspec_version'))
274 version_string = "rspec_%s" % (rspec_version)
276 #panos adding the info option to the caching key (can be improved)
277 if options.get('info'):
278 version_string = version_string + "_" + \
279 options.get('info', 'default')
281 # look in cache first
282 #if cached_requested and self.cache and not slice_hrn:
283 #rspec = self.cache.get(version_string)
285 #logger.debug("SlabDriver.ListResources: \
286 #returning cached advertisement")
289 #panos: passing user-defined options
290 aggregate = SlabAggregate(self)
291 origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
292 options.update({'origin_hrn':origin_hrn})
293 rspec = aggregate.get_rspec(slice_xrn=slice_urn, \
294 version=rspec_version, options=options)
297 #if self.cache and not slice_hrn:
298 #logger.debug("Slab.ListResources: stores advertisement in cache")
299 #self.cache.add(version_string, rspec)
304 def list_slices (self, creds, options):
305 # look in cache first
307 #slices = self.cache.get('slices')
309 #logger.debug("PlDriver.list_slices returns from cache")
314 slices = self.GetSlices()
315 logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices))
316 slice_hrns = [slab_slice['slice_hrn'] for slab_slice in slices]
317 #slice_hrns = [slicename_to_hrn(self.hrn, slab_slice['slice_hrn']) \
318 #for slab_slice in slices]
319 slice_urns = [hrn_to_urn(slice_hrn, 'slice') \
320 for slice_hrn in slice_hrns]
324 #logger.debug ("SlabDriver.list_slices stores value in cache")
325 #self.cache.add('slices', slice_urns)
329 #No site or node register supported
330 def register (self, sfa_record, hrn, pub_key):
331 record_type = sfa_record['type']
332 slab_record = self.sfa_fields_to_slab_fields(record_type, hrn, \
336 if record_type == 'slice':
337 acceptable_fields = ['url', 'instantiation', 'name', 'description']
338 for key in slab_record.keys():
339 if key not in acceptable_fields:
341 logger.debug("SLABDRIVER.PY register")
342 slices = self.GetSlices(slice_filter =slab_record['hrn'], \
343 slice_filter_type = 'slice_hrn')
345 pointer = self.AddSlice(slab_record)
347 pointer = slices[0]['slice_id']
349 elif record_type == 'user':
350 persons = self.GetPersons([sfa_record])
351 #persons = self.GetPersons([sfa_record['hrn']])
353 pointer = self.AddPerson(dict(sfa_record))
356 pointer = persons[0]['person_id']
358 #Does this make sense to senslab ?
359 #if 'enabled' in sfa_record and sfa_record['enabled']:
360 #self.UpdatePerson(pointer, \
361 #{'enabled': sfa_record['enabled']})
363 #TODO register Change this AddPersonToSite stuff 05/07/2012 SA
364 # add this person to the site only if
365 # she is being added for the first
366 # time by sfa and doesnt already exist in plc
367 if not persons or not persons[0]['site_ids']:
368 login_base = get_leaf(sfa_record['authority'])
369 self.AddPersonToSite(pointer, login_base)
371 # What roles should this user have?
372 #TODO : DElete this AddRoleToPerson 04/07/2012 SA
373 #Function prototype is :
374 #AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email)
375 #what's the pointer doing here?
376 self.AddRoleToPerson('user', pointer)
379 self.AddPersonKey(pointer, {'key_type' : 'ssh', \
382 #No node adding outside OAR
386 #No site or node record update allowed
387 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
388 pointer = old_sfa_record['pointer']
389 old_sfa_record_type = old_sfa_record['type']
391 # new_key implemented for users only
392 if new_key and old_sfa_record_type not in [ 'user' ]:
393 raise UnknownSfaType(old_sfa_record_type)
395 #if (type == "authority"):
396 #self.shell.UpdateSite(pointer, new_sfa_record)
398 if old_sfa_record_type == "slice":
399 slab_record = self.sfa_fields_to_slab_fields(old_sfa_record_type, \
401 if 'name' in slab_record:
402 slab_record.pop('name')
403 #Prototype should be UpdateSlice(self,
404 #auth, slice_id_or_name, slice_fields)
405 #Senslab cannot update slice since slice = job
406 #so we must delete and create another job
407 self.UpdateSlice(pointer, slab_record)
409 elif old_sfa_record_type == "user":
411 all_fields = new_sfa_record
412 for key in all_fields.keys():
413 if key in ['first_name', 'last_name', 'title', 'email',
414 'password', 'phone', 'url', 'bio', 'accepted_aup',
416 update_fields[key] = all_fields[key]
417 self.UpdatePerson(pointer, update_fields)
420 # must check this key against the previous one if it exists
421 persons = self.GetPersons([pointer], ['key_ids'])
423 keys = person['key_ids']
424 keys = self.GetKeys(person['key_ids'])
426 # Delete all stale keys
429 if new_key != key['key']:
430 self.DeleteKey(key['key_id'])
434 self.AddPersonKey(pointer, {'key_type': 'ssh', \
441 def remove (self, sfa_record):
442 sfa_record_type = sfa_record['type']
443 hrn = sfa_record['hrn']
444 record_id = sfa_record['record_id']
445 if sfa_record_type == 'user':
447 #get user from senslab ldap
448 person = self.GetPersons(sfa_record)
449 #No registering at a given site in Senslab.
450 #Once registered to the LDAP, all senslab sites are
453 #Mark account as disabled in ldap
454 self.DeletePerson(sfa_record)
455 elif sfa_record_type == 'slice':
456 if self.GetSlices(slice_filter = hrn, \
457 slice_filter_type = 'slice_hrn'):
458 self.DeleteSlice(sfa_record_type)
460 #elif type == 'authority':
461 #if self.GetSites(pointer):
462 #self.DeleteSite(pointer)
468 #TODO clean GetPeers. 05/07/12SA
469 def GetPeers (self, auth = None, peer_filter=None, return_fields_list=None):
471 existing_records = {}
472 existing_hrns_by_types = {}
473 logger.debug("SLABDRIVER \tGetPeers auth = %s, peer_filter %s, \
474 return_field %s " %(auth , peer_filter, return_fields_list))
475 all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
476 for record in all_records:
477 existing_records[(record.hrn, record.type)] = record
478 if record.type not in existing_hrns_by_types:
479 existing_hrns_by_types[record.type] = [record.hrn]
480 logger.debug("SLABDRIVER \tGetPeer\t NOT IN \
481 existing_hrns_by_types %s " %( existing_hrns_by_types))
484 logger.debug("SLABDRIVER \tGetPeer\t \INNN type %s hrn %s " \
485 %(record.type,record.hrn))
486 existing_hrns_by_types[record.type].append(record.hrn)
489 logger.debug("SLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
490 %( existing_hrns_by_types))
495 records_list.append(existing_records[(peer_filter,'authority')])
497 for hrn in existing_hrns_by_types['authority']:
498 records_list.append(existing_records[(hrn,'authority')])
500 logger.debug("SLABDRIVER \tGetPeer \trecords_list %s " \
506 return_records = records_list
507 if not peer_filter and not return_fields_list:
511 logger.debug("SLABDRIVER \tGetPeer return_records %s " \
513 return return_records
516 #TODO : Handling OR request in make_ldap_filters_from_records
517 #instead of the for loop
518 #over the records' list
519 def GetPersons(self, person_filter=None, return_fields_list=None):
521 person_filter should be a list of dictionnaries when not set to None.
522 Returns a list of users whose accounts are enabled found in ldap.
525 logger.debug("SLABDRIVER \tGetPersons person_filter %s" \
528 if person_filter and isinstance(person_filter, list):
529 #If we are looking for a list of users (list of dict records)
530 #Usually the list contains only one user record
531 for searched_attributes in person_filter:
533 #Get only enabled user accounts in senslab LDAP :
534 #add a filter for make_ldap_filters_from_record
535 person = self.ldap.LdapFindUser(searched_attributes, \
536 is_user_enabled=True)
537 person_list.append(person)
540 #Get only enabled user accounts in senslab LDAP :
541 #add a filter for make_ldap_filters_from_record
542 person_list = self.ldap.LdapFindUser(is_user_enabled=True)
546 def GetTimezone(self):
547 server_timestamp, server_tz = self.oar.parser.\
548 SendRequest("GET_timezone")
549 return server_timestamp, server_tz
552 def DeleteJobs(self, job_id, slice_hrn):
553 if not job_id or job_id is -1:
555 username = slice_hrn.split(".")[-1].rstrip("_slice")
557 reqdict['method'] = "delete"
558 reqdict['strval'] = str(job_id)
560 answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id', \
562 logger.debug("SLABDRIVER \tDeleteJobs jobid %s \r\n answer %s username %s" \
563 %(job_id,answer, username))
568 ##TODO : Unused GetJobsId ? SA 05/07/12
569 #def GetJobsId(self, job_id, username = None ):
571 #Details about a specific job.
572 #Includes details about submission time, jot type, state, events,
573 #owner, assigned ressources, walltime etc...
577 #node_list_k = 'assigned_network_address'
578 ##Get job info from OAR
579 #job_info = self.oar.parser.SendRequest(req, job_id, username)
581 #logger.debug("SLABDRIVER \t GetJobsId %s " %(job_info))
583 #if job_info['state'] == 'Terminated':
584 #logger.debug("SLABDRIVER \t GetJobsId job %s TERMINATED"\
587 #if job_info['state'] == 'Error':
588 #logger.debug("SLABDRIVER \t GetJobsId ERROR message %s "\
593 #logger.error("SLABDRIVER \tGetJobsId KeyError")
596 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
598 ##Replaces the previous entry
599 ##"assigned_network_address" / "reserved_resources"
601 #job_info.update({'node_ids':parsed_job_info[node_list_k]})
602 #del job_info[node_list_k]
603 #logger.debug(" \r\nSLABDRIVER \t GetJobsId job_info %s " %(job_info))
607 def GetJobsResources(self, job_id, username = None):
608 #job_resources=['reserved_resources', 'assigned_resources',\
609 #'job_id', 'job_uri', 'assigned_nodes',\
611 #assigned_res = ['resource_id', 'resource_uri']
612 #assigned_n = ['node', 'node_uri']
614 req = "GET_jobs_id_resources"
615 node_list_k = 'reserved_resources'
617 #Get job resources list from OAR
618 node_id_list = self.oar.parser.SendRequest(req, job_id, username)
619 logger.debug("SLABDRIVER \t GetJobsResources %s " %(node_id_list))
622 self.__get_hostnames_from_oar_node_ids(node_id_list)
624 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
626 #Replaces the previous entry "assigned_network_address" /
627 #"reserved_resources"
629 job_info = {'node_ids': hostname_list}
634 def get_info_on_reserved_nodes(self, job_info, node_list_name):
635 #Get the list of the testbed nodes records and make a
636 #dictionnary keyed on the hostname out of it
637 node_list_dict = self.GetNodes()
638 #node_hostname_list = []
639 node_hostname_list = [node['hostname'] for node in node_list_dict]
640 #for node in node_list_dict:
641 #node_hostname_list.append(node['hostname'])
642 node_dict = dict(zip(node_hostname_list, node_list_dict))
644 reserved_node_hostname_list = []
645 for index in range(len(job_info[node_list_name])):
646 #job_info[node_list_name][k] =
647 reserved_node_hostname_list[index] = \
648 node_dict[job_info[node_list_name][index]]['hostname']
650 logger.debug("SLABDRIVER \t get_info_on_reserved_nodes \
651 reserved_node_hostname_list %s" \
652 %(reserved_node_hostname_list))
654 logger.error("SLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
656 return reserved_node_hostname_list
658 def GetNodesCurrentlyInUse(self):
659 """Returns a list of all the nodes already involved in an oar job"""
660 return self.oar.parser.SendRequest("GET_running_jobs")
662 def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
663 full_nodes_dict_list = self.GetNodes()
664 #Put the full node list into a dictionary keyed by oar node id
665 oar_id_node_dict = {}
666 for node in full_nodes_dict_list:
667 oar_id_node_dict[node['oar_id']] = node
669 logger.debug("SLABDRIVER \t __get_hostnames_from_oar_node_ids\
670 oar_id_node_dict %s" %(oar_id_node_dict))
672 hostname_dict_list = []
673 for resource_id in resource_id_list:
674 #Because jobs requested "asap" do not have defined resources
675 if resource_id is not "Undefined":
676 hostname_dict_list.append({'hostname' : \
677 oar_id_node_dict[resource_id]['hostname'],
678 'site_id' : oar_id_node_dict[resource_id]['site']})
680 #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
681 return hostname_dict_list
683 def GetReservedNodes(self):
684 #Get the nodes in use and the reserved nodes
685 reservation_dict_list = \
686 self.oar.parser.SendRequest("GET_reserved_nodes")
689 for resa in reservation_dict_list:
690 logger.debug ("GetReservedNodes resa %s"%(resa))
691 #dict list of hostnames and their site
692 resa['reserved_nodes'] = \
693 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
695 #del resa['resource_ids']
696 return reservation_dict_list
698 def GetNodes(self, node_filter_dict = None, return_fields_list = None):
700 node_filter_dict : dictionnary of lists
703 node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
704 node_dict_list = node_dict_by_id.values()
706 #No filtering needed return the list directly
707 if not (node_filter_dict or return_fields_list):
708 return node_dict_list
710 return_node_list = []
712 for filter_key in node_filter_dict:
714 #Filter the node_dict_list by each value contained in the
715 #list node_filter_dict[filter_key]
716 for value in node_filter_dict[filter_key]:
717 for node in node_dict_list:
718 if node[filter_key] == value:
719 if return_fields_list :
721 for k in return_fields_list:
723 return_node_list.append(tmp)
725 return_node_list.append(node)
727 logger.log_exc("GetNodes KeyError")
731 return return_node_list
734 def GetSites(self, site_filter_name_list = None, return_fields_list = None):
735 site_dict = self.oar.parser.SendRequest("GET_sites")
736 #site_dict : dict where the key is the sit ename
737 return_site_list = []
738 if not ( site_filter_name_list or return_fields_list):
739 return_site_list = site_dict.values()
740 return return_site_list
742 for site_filter_name in site_filter_name_list:
743 if site_filter_name in site_dict:
744 if return_fields_list:
745 for field in return_fields_list:
748 tmp[field] = site_dict[site_filter_name][field]
750 logger.error("GetSites KeyError %s "%(field))
752 return_site_list.append(tmp)
754 return_site_list.append( site_dict[site_filter_name])
757 return return_site_list
758 #warning return_fields_list paramr emoved (Not used)
759 def GetSlices(self, slice_filter = None, slice_filter_type = None):
760 #def GetSlices(self, slice_filter = None, slice_filter_type = None, \
761 #return_fields_list = None):
762 """ Get the slice records from the slab db.
763 Returns a slice ditc if slice_filter and slice_filter_type
765 Returns a list of slice dictionnaries if there are no filters
770 return_slice_list = []
773 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
775 if slice_filter_type in authorized_filter_types_list:
776 #Get list of slices based on the slice hrn
777 if slice_filter_type == 'slice_hrn':
778 #There can be several jobs running for one slices
779 login = slice_filter.split(".")[1].split("_")[0]
781 #DO NOT USE RegSlice - reg_researchers to get the hrn of the user
782 #otherwise will mess up the RegRecord in Resolve, don't know
785 slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).all()
787 #Get list of slices base on user id
788 if slice_filter_type == 'record_id_user':
789 slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).all()
794 slicerec_dictlist = []
795 for record in slicerec:
796 slicerec_dictlist.append(record.dump_sqlalchemyobj_to_dict())
798 login = slicerec_dictlist[0]['slice_hrn'].split(".")[1].split("_")[0]
802 logger.debug("\r\n SLABDRIVER \tGetSlices login %s \
804 %(login, slicerec_dictlist))
805 for slicerec_dict in slicerec_dictlist :
806 if slicerec_dict['oar_job_id'] is not -1:
807 #Check with OAR the status of the job if a job id is in
809 rslt = self.GetJobsResources(slicerec_dict['oar_job_id'], \
811 logger.debug("SLABDRIVER.PY \tGetSlices rslt fromn GetJobsResources %s"\
814 slicerec_dict.update(rslt)
815 slicerec_dict.update({'hrn':\
816 str(slicerec_dict['slice_hrn'])})
817 #If GetJobsResources is empty, this means the job is
818 #now in the 'Terminated' state
819 #Update the slice record
821 self.db.update_job(slice_filter, job_id = -1)
822 slicerec_dict['oar_job_id'] = -1
824 update({'hrn':str(slicerec_dict['slice_hrn'])})
827 slicerec_dict['node_ids'] = slicerec_dict['node_list']
831 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slicerec_dictlist %s"\
832 %(slicerec_dictlist))
834 return slicerec_dictlist
838 slice_list = slab_dbsession.query(SliceSenslab).all()
839 return_slice_list = []
840 for record in slice_list:
841 return_slice_list.append(record.dump_sqlalchemyobj_to_dict())
843 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slices %s \
844 slice_filter %s " %(return_slice_list, slice_filter))
846 #if return_fields_list:
847 #return_slice_list = parse_filter(sliceslist, \
848 #slice_filter,'slice', return_fields_list)
850 return return_slice_list
856 def testbed_name (self): return self.hrn
858 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
859 def aggregate_version (self):
860 version_manager = VersionManager()
861 ad_rspec_versions = []
862 request_rspec_versions = []
863 for rspec_version in version_manager.versions:
864 if rspec_version.content_type in ['*', 'ad']:
865 ad_rspec_versions.append(rspec_version.to_dict())
866 if rspec_version.content_type in ['*', 'request']:
867 request_rspec_versions.append(rspec_version.to_dict())
869 'testbed':self.testbed_name(),
870 'geni_request_rspec_versions': request_rspec_versions,
871 'geni_ad_rspec_versions': ad_rspec_versions,
880 # Convert SFA fields to PLC fields for use when registering up updating
881 # registry record in the PLC database
883 # @param type type of record (user, slice, ...)
884 # @param hrn human readable name
885 # @param sfa_fields dictionary of SFA fields
886 # @param slab_fields dictionary of PLC fields (output)
888 def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
890 def convert_ints(tmpdict, int_fields):
891 for field in int_fields:
893 tmpdict[field] = int(tmpdict[field])
896 #for field in record:
897 # slab_record[field] = record[field]
899 if sfa_type == "slice":
900 #instantion used in get_slivers ?
901 if not "instantiation" in slab_record:
902 slab_record["instantiation"] = "senslab-instantiated"
903 #slab_record["hrn"] = hrn_to_pl_slicename(hrn)
904 #Unused hrn_to_pl_slicename because Slab's hrn already in the appropriate form SA 23/07/12
905 slab_record["hrn"] = hrn
906 logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
907 slab_record %s " %(slab_record['hrn']))
909 slab_record["url"] = record["url"]
910 if "description" in record:
911 slab_record["description"] = record["description"]
912 if "expires" in record:
913 slab_record["expires"] = int(record["expires"])
915 #nodes added by OAR only and then imported to SFA
916 #elif type == "node":
917 #if not "hostname" in slab_record:
918 #if not "hostname" in record:
919 #raise MissingSfaInfo("hostname")
920 #slab_record["hostname"] = record["hostname"]
921 #if not "model" in slab_record:
922 #slab_record["model"] = "geni"
925 #elif type == "authority":
926 #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
928 #if not "name" in slab_record:
929 #slab_record["name"] = hrn
931 #if not "abbreviated_name" in slab_record:
932 #slab_record["abbreviated_name"] = hrn
934 #if not "enabled" in slab_record:
935 #slab_record["enabled"] = True
937 #if not "is_public" in slab_record:
938 #slab_record["is_public"] = True
945 def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
946 """ Transforms unix timestamp into valid OAR date format """
948 #Used in case of a scheduled experiment (not immediate)
949 #To run an XP immediately, don't specify date and time in RSpec
950 #They will be set to None.
952 #transform the xp_utc_timestamp into server readable time
953 xp_server_readable_date = datetime.fromtimestamp(int(\
954 xp_utc_timestamp)).strftime(self.time_format)
956 return xp_server_readable_date
964 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
965 lease_start_time, lease_duration, slice_user=None):
967 lease_dict['lease_start_time'] = lease_start_time
968 lease_dict['lease_duration'] = lease_duration
969 lease_dict['added_nodes'] = added_nodes
970 lease_dict['slice_name'] = slice_name
971 lease_dict['slice_user'] = slice_user
972 lease_dict['grain'] = self.GetLeaseGranularity()
973 lease_dict['time_format'] = self.time_format
975 def __create_job_structure_request_for_OAR(lease_dict):
976 """ Creates the structure needed for a correct POST on OAR.
977 Makes the timestamp transformation into the appropriate format.
978 Sends the POST request to create the job with the resources in
989 reqdict['workdir'] = '/tmp'
990 reqdict['resource'] = "{network_address in ("
992 for node in lease_dict['added_nodes']:
993 logger.debug("\r\n \r\n OARrestapi \t __create_job_structure_request_for_OAR \
996 # Get the ID of the node
998 reqdict['resource'] += "'" + nodeid + "', "
999 nodeid_list.append(nodeid)
1001 custom_length = len(reqdict['resource'])- 2
1002 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
1003 ")}/nodes=" + str(len(nodeid_list))
1005 def __process_walltime(duration):
1006 """ Calculates the walltime in seconds from the duration in H:M:S
1007 specified in the RSpec.
1011 # Fixing the walltime by adding a few delays.
1012 # First put the walltime in seconds oarAdditionalDelay = 20;
1013 # additional delay for /bin/sleep command to
1014 # take in account prologue and epilogue scripts execution
1015 # int walltimeAdditionalDelay = 120; additional delay
1016 desired_walltime = duration
1017 total_walltime = desired_walltime + 140#+2 min 20
1018 sleep_walltime = desired_walltime + 20 #+20 sec
1020 #Put the walltime back in str form
1021 #First get the hours
1022 walltime.append(str(total_walltime / 3600))
1023 total_walltime = total_walltime - 3600 * int(walltime[0])
1024 #Get the remaining minutes
1025 walltime.append(str(total_walltime / 60))
1026 total_walltime = total_walltime - 60 * int(walltime[1])
1028 walltime.append(str(total_walltime))
1031 logger.log_exc(" __process_walltime duration null")
1033 return walltime, sleep_walltime
1036 walltime, sleep_walltime = \
1037 __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1040 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1041 ":" + str(walltime[1]) + ":" + str(walltime[2])
1042 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1044 #In case of a scheduled experiment (not immediate)
1045 #To run an XP immediately, don't specify date and time in RSpec
1046 #They will be set to None.
1047 if lease_dict['lease_start_time'] is not '0':
1048 #Readable time accepted by OAR
1049 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1050 strftime(lease_dict['time_format'])
1051 reqdict['reservation'] = start_time
1052 #If there is not start time, Immediate XP. No need to add special
1056 reqdict['type'] = "deploy"
1057 reqdict['directory'] = ""
1058 reqdict['name'] = "SFA_" + lease_dict['slice_user']
1063 #Create the request for OAR
1064 reqdict = __create_job_structure_request_for_OAR(lease_dict)
1065 # first step : start the OAR job and update the job
1066 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1069 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1070 reqdict, slice_user)
1071 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s " %(answer))
1073 jobid = answer['id']
1075 logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1076 Impossible to create job %s " %(answer))
1080 def __configure_experiment(jobid, added_nodes):
1081 # second step : configure the experiment
1082 # we need to store the nodes in a yaml (well...) file like this :
1083 # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1084 job_file = open('/tmp/sfa/'+ str(jobid) + '.json', 'w')
1086 job_file.write(str(added_nodes[0].strip('node')))
1087 for node in added_nodes[1:len(added_nodes)] :
1088 job_file.write(', '+ node.strip('node'))
1093 def __launch_senslab_experiment(jobid):
1094 # third step : call the senslab-experiment wrapper
1095 #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar
1096 # "+str(jobid)+" "+slice_user
1097 javacmdline = "/usr/bin/java"
1099 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1100 #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", \
1101 #str(jobid), slice_user])
1102 output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1103 slice_user],stdout=subprocess.PIPE).communicate()[0]
1105 logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1112 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1113 added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1114 self.db.update_job( slice_name, jobid, added_nodes)
1116 __configure_experiment(jobid, added_nodes)
1117 __launch_senslab_experiment(jobid)
1121 def AddLeases(self, hostname_list, slice_record, lease_start_time, lease_duration):
1122 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s \
1123 slice_record %s lease_start_time %s lease_duration %s "\
1124 %( hostname_list, slice_record , lease_start_time, \
1127 tmp = slice_record['PI'][0].split(".")
1128 username = tmp[(len(tmp)-1)]
1129 self.LaunchExperimentOnOAR(hostname_list, slice_record['name'], lease_start_time, lease_duration, username)
1130 start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1131 logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1136 #Delete the jobs and updates the job id in the senslab table
1138 #Does not clear the node list
1139 def DeleteSliceFromNodes(self, slice_record):
1140 # Get user information
1142 self.DeleteJobs(slice_record['oar_job_id'], slice_record['hrn'])
1143 self.db.update_job(slice_record['hrn'], job_id = -1)
1147 def GetLeaseGranularity(self):
1148 """ Returns the granularity of Senslab testbed.
1149 Defined in seconds. """
1154 def GetLeases(self, lease_filter_dict=None, return_fields_list=None):
1155 unfiltered_reservation_list = self.GetReservedNodes()
1156 reservation_list = []
1157 #Find the slice associated with this user senslab ldap uid
1158 logger.debug(" SLABDRIVER.PY \tGetLeases ")
1159 #Create user dict first to avoir looking several times for
1160 #the same user in LDAP SA 27/07/12
1162 for resa in unfiltered_reservation_list:
1163 logger.debug("SLABDRIVER \tGetLeases USER %s"\
1165 if resa['user'] not in resa_user_dict:
1166 logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1167 ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1168 ldap_info = ldap_info[0][1]
1169 user = dbsession.query(RegUser).filter_by(email = \
1170 ldap_info['mail'][0]).first()
1171 #Separated in case user not in database : record_id not defined SA 17/07//12
1172 query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1173 if query_slice_info:
1174 slice_info = query_slice_info.first()
1177 resa_user_dict[resa['user']] = {}
1178 resa_user_dict[resa['user']]['ldap_info'] = user
1179 resa_user_dict[resa['user']]['slice_info'] = slice_info
1181 logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1183 for resa in unfiltered_reservation_list:
1185 #ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1186 #ldap_info = ldap_info[0][1]
1188 #user = dbsession.query(RegUser).filter_by(email = \
1189 #ldap_info['mail'][0]).first()
1190 ##Separated in case user not in database : record_id not defined SA 17/07//12
1191 #query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1192 #if query_slice_info:
1193 #slice_info = query_slice_info.first()
1195 resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info'].slice_hrn
1196 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1198 #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1199 resa['component_id_list'] = []
1200 #Transform the hostnames into urns (component ids)
1201 for node in resa['reserved_nodes']:
1202 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1203 #self.root_auth, node['hostname']))
1204 slab_xrn = slab_xrn_object(self.root_auth, node['hostname'])
1205 resa['component_id_list'].append(slab_xrn.urn)
1207 #Filter the reservation list if necessary
1208 #Returns all the leases associated with a given slice
1209 if lease_filter_dict:
1210 logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1211 %(lease_filter_dict))
1212 for resa in unfiltered_reservation_list:
1213 if lease_filter_dict['name'] == resa['slice_hrn']:
1214 reservation_list.append(resa)
1216 reservation_list = unfiltered_reservation_list
1218 logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1219 %(reservation_list))
1220 return reservation_list
1222 def augment_records_with_testbed_info (self, sfa_records):
1223 return self.fill_record_info (sfa_records)
1225 def fill_record_info(self, record_list):
1227 Given a SFA record, fill in the senslab specific and SFA specific
1228 fields in the record.
1231 logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1232 if not isinstance(record_list, list):
1233 record_list = [record_list]
1236 for record in record_list:
1237 #If the record is a SFA slice record, then add information
1238 #about the user of this slice. This kind of
1239 #information is in the Senslab's DB.
1240 if str(record['type']) == 'slice':
1241 #Get slab slice record.
1242 recslice_list = self.GetSlices(slice_filter = \
1243 str(record['hrn']),\
1244 slice_filter_type = 'slice_hrn')
1246 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1247 recslice_list[0]['record_id_user']).first()
1248 logger.debug("SLABDRIVER \tfill_record_info TYPE SLICE RECUSER %s " %(recuser))
1249 record.update({'PI':[recuser.hrn],
1250 'researcher': [recuser.hrn],
1251 'name':record['hrn'],
1252 'oar_job_id':[rec['oar_job_id'] for rec in recslice_list],
1254 'person_ids':[recslice_list[0]['record_id_user']],
1255 'geni_urn':'', #For client_helper.py compatibility
1256 'keys':'', #For client_helper.py compatibility
1257 'key_ids':''}) #For client_helper.py compatibility
1259 #for rec in recslice_list:
1260 #record['oar_job_id'].append(rec['oar_job_id'])
1261 logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1262 recslice_list %s \r\n \t RECORD %s \r\n \r\n" %(recslice_list,record))
1263 if str(record['type']) == 'user':
1264 #The record is a SFA user record.
1265 #Get the information about his slice from Senslab's DB
1266 #and add it to the user record.
1267 recslice_list = self.GetSlices(\
1268 slice_filter = record['record_id'],\
1269 slice_filter_type = 'record_id_user')
1271 logger.debug( "SLABDRIVER.PY \t fill_record_info TYPE USER \
1272 recslice_list %s \r\n \t RECORD %s \r\n" %(recslice_list , record))
1273 #Append slice record in records list,
1274 #therefore fetches user and slice info again(one more loop)
1275 #Will update PIs and researcher for the slice
1276 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1277 recslice_list[0]['record_id_user']).first()
1278 logger.debug( "SLABDRIVER.PY \t fill_record_info USER \
1279 recuser %s \r\n \r\n" %(recuser))
1281 recslice = recslice_list[0]
1282 recslice.update({'PI':[recuser.hrn],
1283 'researcher': [recuser.hrn],
1284 'name':record['hrn'],
1286 'oar_job_id': [rec['oar_job_id'] for rec in recslice_list],
1287 'person_ids':[recslice_list[0]['record_id_user']]})
1288 recslice.update({'type':'slice', \
1289 'hrn':recslice_list[0]['slice_hrn']})
1290 #for rec in recslice_list:
1291 #recslice['oar_job_id'].append(rec['oar_job_id'])
1293 #GetPersons takes [] as filters
1294 #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1295 user_slab = self.GetPersons([record])
1298 record.update(user_slab[0])
1299 #For client_helper.py compatibility
1300 record.update( { 'geni_urn':'',
1303 record_list.append(recslice)
1305 logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1306 INFO TO USER records %s" %(record_list))
1307 logger.debug("SLABDRIVER.PY \tfill_record_info END \
1308 #record %s \r\n \r\n " %(record))
1310 except TypeError, error:
1311 logger.log_exc("SLABDRIVER \t fill_record_info EXCEPTION %s"\
1313 #logger.debug("SLABDRIVER.PY \t fill_record_info ENDENDEND ")
1317 #self.fill_record_slab_info(records)
1323 #TODO Update membership? update_membership_list SA 05/07/12
1324 #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1326 ## get a list of the HRNs tht are members of the old and new records
1328 #oldList = oldRecord.get(listName, [])
1331 #newList = record.get(listName, [])
1333 ## if the lists are the same, then we don't have to update anything
1334 #if (oldList == newList):
1337 ## build a list of the new person ids, by looking up each person to get
1341 #records = table.find({'type': 'user', 'hrn': newList})
1342 #for rec in records:
1343 #newIdList.append(rec['pointer'])
1345 ## build a list of the old person ids from the person_ids field
1347 #oldIdList = oldRecord.get("person_ids", [])
1348 #containerId = oldRecord.get_pointer()
1350 ## if oldRecord==None, then we are doing a Register, instead of an
1353 #containerId = record.get_pointer()
1355 ## add people who are in the new list, but not the oldList
1356 #for personId in newIdList:
1357 #if not (personId in oldIdList):
1358 #addFunc(self.plauth, personId, containerId)
1360 ## remove people who are in the old list, but not the new list
1361 #for personId in oldIdList:
1362 #if not (personId in newIdList):
1363 #delFunc(self.plauth, personId, containerId)
1365 #def update_membership(self, oldRecord, record):
1367 #if record.type == "slice":
1368 #self.update_membership_list(oldRecord, record, 'researcher',
1369 #self.users.AddPersonToSlice,
1370 #self.users.DeletePersonFromSlice)
1371 #elif record.type == "authority":
1376 # I don't think you plan on running a component manager at this point
1377 # let me clean up the mess of ComponentAPI that is deprecated anyways
1380 #TODO FUNCTIONS SECTION 04/07/2012 SA
1382 #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1384 def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1385 """ This method is a hopefully temporary hack to let the sfa correctly
1386 detach the objects it creates from a remote peer object. This is
1387 needed so that the sfa federation link can work in parallel with
1388 RefreshPeer, as RefreshPeer depends on remote objects being correctly
1391 auth : struct, API authentication structure
1392 AuthMethod : string, Authentication method to use
1393 object_type : string, Object type, among 'site','person','slice',
1395 object_id : int, object_id
1396 shortname : string, peer shortname
1400 logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1404 #TODO Is BindObjectToPeer still necessary ? Currently does nothing
1406 def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1407 remote_object_id=None):
1408 """This method is a hopefully temporary hack to let the sfa correctly
1409 attach the objects it creates to a remote peer object. This is needed
1410 so that the sfa federation link can work in parallel with RefreshPeer,
1411 as RefreshPeer depends on remote objects being correctly marked.
1413 shortname : string, peer shortname
1414 remote_object_id : int, remote object_id, set to 0 if unknown
1418 logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1421 #TODO UpdateSlice 04/07/2012 SA
1422 #Funciton should delete and create another job since oin senslab slice=job
1423 def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1424 """Updates the parameters of an existing slice with the values in
1426 Users may only update slices of which they are members.
1427 PIs may update any of the slices at their sites, or any slices of
1428 which they are members. Admins may update any slice.
1429 Only PIs and admins may update max_nodes. Slices cannot be renewed
1430 (by updating the expires parameter) more than 8 weeks into the future.
1431 Returns 1 if successful, faults otherwise.
1435 logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1438 #TODO UpdatePerson 04/07/2012 SA
1439 def UpdatePerson(self, auth, person_id_or_email, person_fields=None):
1440 """Updates a person. Only the fields specified in person_fields
1441 are updated, all other fields are left untouched.
1442 Users and techs can only update themselves. PIs can only update
1443 themselves and other non-PIs at their sites.
1444 Returns 1 if successful, faults otherwise.
1448 logger.warning("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1451 #TODO GetKeys 04/07/2012 SA
1452 def GetKeys(self, auth, key_filter=None, return_fields=None):
1453 """Returns an array of structs containing details about keys.
1454 If key_filter is specified and is an array of key identifiers,
1455 or a struct of key attributes, only keys matching the filter
1456 will be returned. If return_fields is specified, only the
1457 specified details will be returned.
1459 Admin may query all keys. Non-admins may only query their own keys.
1463 logger.warning("SLABDRIVER GetKeys EMPTY - DO NOTHING \r\n ")
1466 #TODO DeleteKey 04/07/2012 SA
1467 def DeleteKey(self, auth, key_id):
1469 Non-admins may only delete their own keys.
1470 Returns 1 if successful, faults otherwise.
1474 logger.warning("SLABDRIVER DeleteKey EMPTY - DO NOTHING \r\n ")
1478 #TODO : Check rights to delete person
1479 def DeletePerson(self, auth, person_record):
1480 """ Disable an existing account in senslab LDAP.
1481 Users and techs can only delete themselves. PIs can only
1482 delete themselves and other non-PIs at their sites.
1483 ins can delete anyone.
1484 Returns 1 if successful, faults otherwise.
1488 #Disable user account in senslab LDAP
1489 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1490 logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1493 #TODO Check DeleteSlice, check rights 05/07/2012 SA
1494 def DeleteSlice(self, auth, slice_record):
1495 """ Deletes the specified slice.
1496 Senslab : Kill the job associated with the slice if there is one
1497 using DeleteSliceFromNodes.
1498 Updates the slice record in slab db to remove the slice nodes.
1500 Users may only delete slices of which they are members. PIs may
1501 delete any of the slices at their sites, or any slices of which
1502 they are members. Admins may delete any slice.
1503 Returns 1 if successful, faults otherwise.
1507 self.DeleteSliceFromNodes(slice_record)
1508 self.db.update_job(slice_record['hrn'], job_id = -1)
1509 logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1512 #TODO AddPerson 04/07/2012 SA
1513 def AddPerson(self, auth, person_fields=None):
1514 """Adds a new account. Any fields specified in person_fields are used,
1515 otherwise defaults are used.
1516 Accounts are disabled by default. To enable an account,
1518 Returns the new person_id (> 0) if successful, faults otherwise.
1522 logger.warning("SLABDRIVER AddPerson EMPTY - DO NOTHING \r\n ")
1525 #TODO AddPersonToSite 04/07/2012 SA
1526 def AddPersonToSite (self, auth, person_id_or_email, \
1527 site_id_or_login_base=None):
1528 """ Adds the specified person to the specified site. If the person is
1529 already a member of the site, no errors are returned. Does not change
1530 the person's primary site.
1531 Returns 1 if successful, faults otherwise.
1535 logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1538 #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1539 def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1540 """Grants the specified role to the person.
1541 PIs can only grant the tech and user roles to users and techs at their
1542 sites. Admins can grant any role to any user.
1543 Returns 1 if successful, faults otherwise.
1547 logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1550 #TODO AddPersonKey 04/07/2012 SA
1551 def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1552 """Adds a new key to the specified account.
1553 Non-admins can only modify their own keys.
1554 Returns the new key_id (> 0) if successful, faults otherwise.
1558 logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1561 def DeleteLeases(self, leases_id_list, slice_hrn ):
1562 for job_id in leases_id_list:
1563 self.DeleteJobs(job_id, slice_hrn)
1565 logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \r\n " %(leases_id_list, slice_hrn))