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'], \
813 slicerec_dict.update(rslt)
814 slicerec_dict.update({'hrn':\
815 str(slicerec_dict['slice_hrn'])})
816 #If GetJobsResources is empty, this means the job is
817 #now in the 'Terminated' state
818 #Update the slice record
820 self.db.update_job(slice_filter, job_id = -1)
821 slicerec_dict['oar_job_id'] = -1
823 update({'hrn':str(slicerec_dict['slice_hrn'])})
826 slicerec_dict['node_ids'] = slicerec_dict['node_list']
830 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slicerec_dictlist %s"\
831 %(slicerec_dictlist))
833 return slicerec_dictlist
837 slice_list = slab_dbsession.query(SliceSenslab).all()
838 return_slice_list = []
839 for record in slice_list:
840 return_slice_list.append(record.dump_sqlalchemyobj_to_dict())
842 logger.debug("SLABDRIVER.PY \tGetSlices RETURN slices %s \
843 slice_filter %s " %(return_slice_list, slice_filter))
845 #if return_fields_list:
846 #return_slice_list = parse_filter(sliceslist, \
847 #slice_filter,'slice', return_fields_list)
849 return return_slice_list
855 def testbed_name (self): return self.hrn
857 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
858 def aggregate_version (self):
859 version_manager = VersionManager()
860 ad_rspec_versions = []
861 request_rspec_versions = []
862 for rspec_version in version_manager.versions:
863 if rspec_version.content_type in ['*', 'ad']:
864 ad_rspec_versions.append(rspec_version.to_dict())
865 if rspec_version.content_type in ['*', 'request']:
866 request_rspec_versions.append(rspec_version.to_dict())
868 'testbed':self.testbed_name(),
869 'geni_request_rspec_versions': request_rspec_versions,
870 'geni_ad_rspec_versions': ad_rspec_versions,
879 # Convert SFA fields to PLC fields for use when registering up updating
880 # registry record in the PLC database
882 # @param type type of record (user, slice, ...)
883 # @param hrn human readable name
884 # @param sfa_fields dictionary of SFA fields
885 # @param slab_fields dictionary of PLC fields (output)
887 def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
889 def convert_ints(tmpdict, int_fields):
890 for field in int_fields:
892 tmpdict[field] = int(tmpdict[field])
895 #for field in record:
896 # slab_record[field] = record[field]
898 if sfa_type == "slice":
899 #instantion used in get_slivers ?
900 if not "instantiation" in slab_record:
901 slab_record["instantiation"] = "senslab-instantiated"
902 #slab_record["hrn"] = hrn_to_pl_slicename(hrn)
903 #Unused hrn_to_pl_slicename because Slab's hrn already in the appropriate form SA 23/07/12
904 slab_record["hrn"] = hrn
905 logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
906 slab_record %s " %(slab_record['hrn']))
908 slab_record["url"] = record["url"]
909 if "description" in record:
910 slab_record["description"] = record["description"]
911 if "expires" in record:
912 slab_record["expires"] = int(record["expires"])
914 #nodes added by OAR only and then imported to SFA
915 #elif type == "node":
916 #if not "hostname" in slab_record:
917 #if not "hostname" in record:
918 #raise MissingSfaInfo("hostname")
919 #slab_record["hostname"] = record["hostname"]
920 #if not "model" in slab_record:
921 #slab_record["model"] = "geni"
924 #elif type == "authority":
925 #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
927 #if not "name" in slab_record:
928 #slab_record["name"] = hrn
930 #if not "abbreviated_name" in slab_record:
931 #slab_record["abbreviated_name"] = hrn
933 #if not "enabled" in slab_record:
934 #slab_record["enabled"] = True
936 #if not "is_public" in slab_record:
937 #slab_record["is_public"] = True
944 def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
945 """ Transforms unix timestamp into valid OAR date format """
947 #Used in case of a scheduled experiment (not immediate)
948 #To run an XP immediately, don't specify date and time in RSpec
949 #They will be set to None.
951 #transform the xp_utc_timestamp into server readable time
952 xp_server_readable_date = datetime.fromtimestamp(int(\
953 xp_utc_timestamp)).strftime(self.time_format)
955 return xp_server_readable_date
963 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
964 lease_start_time, lease_duration, slice_user=None):
966 lease_dict['lease_start_time'] = lease_start_time
967 lease_dict['lease_duration'] = lease_duration
968 lease_dict['added_nodes'] = added_nodes
969 lease_dict['slice_name'] = slice_name
970 lease_dict['slice_user'] = slice_user
971 lease_dict['grain'] = self.GetLeaseGranularity()
972 lease_dict['time_format'] = self.time_format
974 def __create_job_structure_request_for_OAR(lease_dict):
975 """ Creates the structure needed for a correct POST on OAR.
976 Makes the timestamp transformation into the appropriate format.
977 Sends the POST request to create the job with the resources in
988 reqdict['workdir'] = '/tmp'
989 reqdict['resource'] = "{network_address in ("
991 for node in lease_dict['added_nodes']:
992 logger.debug("\r\n \r\n OARrestapi \t __create_job_structure_request_for_OAR \
995 # Get the ID of the node
997 reqdict['resource'] += "'" + nodeid + "', "
998 nodeid_list.append(nodeid)
1000 custom_length = len(reqdict['resource'])- 2
1001 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
1002 ")}/nodes=" + str(len(nodeid_list))
1004 def __process_walltime(duration):
1005 """ Calculates the walltime in seconds from the duration in H:M:S
1006 specified in the RSpec.
1010 # Fixing the walltime by adding a few delays.
1011 # First put the walltime in seconds oarAdditionalDelay = 20;
1012 # additional delay for /bin/sleep command to
1013 # take in account prologue and epilogue scripts execution
1014 # int walltimeAdditionalDelay = 120; additional delay
1015 desired_walltime = duration
1016 total_walltime = desired_walltime + 140#+2 min 20
1017 sleep_walltime = desired_walltime + 20 #+20 sec
1019 #Put the walltime back in str form
1020 #First get the hours
1021 walltime.append(str(total_walltime / 3600))
1022 total_walltime = total_walltime - 3600 * int(walltime[0])
1023 #Get the remaining minutes
1024 walltime.append(str(total_walltime / 60))
1025 total_walltime = total_walltime - 60 * int(walltime[1])
1027 walltime.append(str(total_walltime))
1030 logger.log_exc(" __process_walltime duration null")
1032 return walltime, sleep_walltime
1035 walltime, sleep_walltime = \
1036 __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1039 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1040 ":" + str(walltime[1]) + ":" + str(walltime[2])
1041 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1043 #In case of a scheduled experiment (not immediate)
1044 #To run an XP immediately, don't specify date and time in RSpec
1045 #They will be set to None.
1046 if lease_dict['lease_start_time'] is not '0':
1047 #Readable time accepted by OAR
1048 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1049 strftime(lease_dict['time_format'])
1050 reqdict['reservation'] = start_time
1051 #If there is not start time, Immediate XP. No need to add special
1055 reqdict['type'] = "deploy"
1056 reqdict['directory'] = ""
1057 reqdict['name'] = "SFA_" + lease_dict['slice_user']
1062 #Create the request for OAR
1063 reqdict = __create_job_structure_request_for_OAR(lease_dict)
1064 # first step : start the OAR job and update the job
1065 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1068 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1069 reqdict, slice_user)
1070 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s " %(answer))
1072 jobid = answer['id']
1074 logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1075 Impossible to create job %s " %(answer))
1079 def __configure_experiment(jobid, added_nodes):
1080 # second step : configure the experiment
1081 # we need to store the nodes in a yaml (well...) file like this :
1082 # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1083 job_file = open('/tmp/sfa/'+ str(jobid) + '.json', 'w')
1085 job_file.write(str(added_nodes[0].strip('node')))
1086 for node in added_nodes[1:len(added_nodes)] :
1087 job_file.write(', '+ node.strip('node'))
1092 def __launch_senslab_experiment(jobid):
1093 # third step : call the senslab-experiment wrapper
1094 #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar
1095 # "+str(jobid)+" "+slice_user
1096 javacmdline = "/usr/bin/java"
1098 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1099 #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", \
1100 #str(jobid), slice_user])
1101 output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1102 slice_user],stdout=subprocess.PIPE).communicate()[0]
1104 logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1111 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1112 added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1113 self.db.update_job( slice_name, jobid, added_nodes)
1115 __configure_experiment(jobid, added_nodes)
1116 __launch_senslab_experiment(jobid)
1120 def AddLeases(self, hostname_list, slice_record, lease_start_time, lease_duration):
1121 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s \
1122 slice_record %s lease_start_time %s lease_duration %s "\
1123 %( hostname_list, slice_record , lease_start_time, \
1126 tmp = slice_record['PI'][0].split(".")
1127 username = tmp[(len(tmp)-1)]
1128 self.LaunchExperimentOnOAR(hostname_list, slice_record['name'], lease_start_time, lease_duration, username)
1129 start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1130 logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1135 #Delete the jobs and updates the job id in the senslab table
1137 #Does not clear the node list
1138 def DeleteSliceFromNodes(self, slice_record):
1139 # Get user information
1141 self.DeleteJobs(slice_record['oar_job_id'], slice_record['hrn'])
1142 self.db.update_job(slice_record['hrn'], job_id = -1)
1146 def GetLeaseGranularity(self):
1147 """ Returns the granularity of Senslab testbed.
1148 Defined in seconds. """
1153 def GetLeases(self, lease_filter_dict=None, return_fields_list=None):
1154 unfiltered_reservation_list = self.GetReservedNodes()
1155 reservation_list = []
1156 #Find the slice associated with this user senslab ldap uid
1157 logger.debug(" SLABDRIVER.PY \tGetLeases ")
1158 #Create user dict first to avoir looking several times for
1159 #the same user in LDAP SA 27/07/12
1161 for resa in unfiltered_reservation_list:
1162 logger.debug("SLABDRIVER \tGetLeases USER %s"\
1164 if resa['user'] not in resa_user_dict:
1165 logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1166 ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1167 ldap_info = ldap_info[0][1]
1168 user = dbsession.query(RegUser).filter_by(email = \
1169 ldap_info['mail'][0]).first()
1170 #Separated in case user not in database : record_id not defined SA 17/07//12
1171 query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1172 if query_slice_info:
1173 slice_info = query_slice_info.first()
1176 resa_user_dict[resa['user']] = {}
1177 resa_user_dict[resa['user']]['ldap_info'] = user
1178 resa_user_dict[resa['user']]['slice_info'] = slice_info
1180 logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1182 for resa in unfiltered_reservation_list:
1184 #ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1185 #ldap_info = ldap_info[0][1]
1187 #user = dbsession.query(RegUser).filter_by(email = \
1188 #ldap_info['mail'][0]).first()
1189 ##Separated in case user not in database : record_id not defined SA 17/07//12
1190 #query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1191 #if query_slice_info:
1192 #slice_info = query_slice_info.first()
1194 resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info'].slice_hrn
1195 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1197 #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1198 resa['component_id_list'] = []
1199 #Transform the hostnames into urns (component ids)
1200 for node in resa['reserved_nodes']:
1201 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1202 #self.root_auth, node['hostname']))
1203 slab_xrn = slab_xrn_object(self.root_auth, node['hostname'])
1204 resa['component_id_list'].append(slab_xrn.urn)
1206 #Filter the reservation list if necessary
1207 #Returns all the leases associated with a given slice
1208 if lease_filter_dict:
1209 logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1210 %(lease_filter_dict))
1211 for resa in unfiltered_reservation_list:
1212 if lease_filter_dict['name'] == resa['slice_hrn']:
1213 reservation_list.append(resa)
1215 reservation_list = unfiltered_reservation_list
1217 logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1218 %(reservation_list))
1219 return reservation_list
1221 def augment_records_with_testbed_info (self, sfa_records):
1222 return self.fill_record_info (sfa_records)
1224 def fill_record_info(self, record_list):
1226 Given a SFA record, fill in the senslab specific and SFA specific
1227 fields in the record.
1230 logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1231 if not isinstance(record_list, list):
1232 record_list = [record_list]
1235 for record in record_list:
1236 #If the record is a SFA slice record, then add information
1237 #about the user of this slice. This kind of
1238 #information is in the Senslab's DB.
1239 if str(record['type']) == 'slice':
1240 #Get slab slice record.
1241 recslice_list = self.GetSlices(slice_filter = \
1242 str(record['hrn']),\
1243 slice_filter_type = 'slice_hrn')
1245 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1246 recslice_list[0]['record_id_user']).first()
1247 logger.debug("SLABDRIVER \tfill_record_info TYPE SLICE RECUSER %s " %(recuser))
1248 record.update({'PI':[recuser.hrn],
1249 'researcher': [recuser.hrn],
1250 'name':record['hrn'],
1251 'oar_job_id':[rec['oar_job_id'] for rec in recslice_list],
1253 'person_ids':[recslice_list[0]['record_id_user']],
1254 'geni_urn':'', #For client_helper.py compatibility
1255 'keys':'', #For client_helper.py compatibility
1256 'key_ids':''}) #For client_helper.py compatibility
1258 #for rec in recslice_list:
1259 #record['oar_job_id'].append(rec['oar_job_id'])
1260 logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1261 recslice_list %s \r\n \t RECORD %s \r\n \r\n" %(recslice_list,record))
1262 if str(record['type']) == 'user':
1263 #The record is a SFA user record.
1264 #Get the information about his slice from Senslab's DB
1265 #and add it to the user record.
1266 recslice_list = self.GetSlices(\
1267 slice_filter = record['record_id'],\
1268 slice_filter_type = 'record_id_user')
1270 logger.debug( "SLABDRIVER.PY \t fill_record_info TYPE USER \
1271 recslice_list %s \r\n \t RECORD %s \r\n" %(recslice_list , record))
1272 #Append slice record in records list,
1273 #therefore fetches user and slice info again(one more loop)
1274 #Will update PIs and researcher for the slice
1275 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1276 recslice_list[0]['record_id_user']).first()
1277 logger.debug( "SLABDRIVER.PY \t fill_record_info USER \
1278 recuser %s \r\n \r\n" %(recuser))
1280 recslice = recslice_list[0]
1281 recslice.update({'PI':[recuser.hrn],
1282 'researcher': [recuser.hrn],
1283 'name':record['hrn'],
1285 'oar_job_id': [rec['oar_job_id'] for rec in recslice_list],
1286 'person_ids':[recslice_list[0]['record_id_user']]})
1287 recslice.update({'type':'slice', \
1288 'hrn':recslice_list[0]['slice_hrn']})
1289 #for rec in recslice_list:
1290 #recslice['oar_job_id'].append(rec['oar_job_id'])
1292 #GetPersons takes [] as filters
1293 #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1294 user_slab = self.GetPersons([record])
1297 record.update(user_slab[0])
1298 #For client_helper.py compatibility
1299 record.update( { 'geni_urn':'',
1302 record_list.append(recslice)
1304 logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1305 INFO TO USER records %s" %(record_list))
1306 logger.debug("SLABDRIVER.PY \tfill_record_info END \
1307 #record %s \r\n \r\n " %(record))
1309 except TypeError, error:
1310 logger.log_exc("SLABDRIVER \t fill_record_info EXCEPTION %s"\
1312 #logger.debug("SLABDRIVER.PY \t fill_record_info ENDENDEND ")
1316 #self.fill_record_slab_info(records)
1322 #TODO Update membership? update_membership_list SA 05/07/12
1323 #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1325 ## get a list of the HRNs tht are members of the old and new records
1327 #oldList = oldRecord.get(listName, [])
1330 #newList = record.get(listName, [])
1332 ## if the lists are the same, then we don't have to update anything
1333 #if (oldList == newList):
1336 ## build a list of the new person ids, by looking up each person to get
1340 #records = table.find({'type': 'user', 'hrn': newList})
1341 #for rec in records:
1342 #newIdList.append(rec['pointer'])
1344 ## build a list of the old person ids from the person_ids field
1346 #oldIdList = oldRecord.get("person_ids", [])
1347 #containerId = oldRecord.get_pointer()
1349 ## if oldRecord==None, then we are doing a Register, instead of an
1352 #containerId = record.get_pointer()
1354 ## add people who are in the new list, but not the oldList
1355 #for personId in newIdList:
1356 #if not (personId in oldIdList):
1357 #addFunc(self.plauth, personId, containerId)
1359 ## remove people who are in the old list, but not the new list
1360 #for personId in oldIdList:
1361 #if not (personId in newIdList):
1362 #delFunc(self.plauth, personId, containerId)
1364 #def update_membership(self, oldRecord, record):
1366 #if record.type == "slice":
1367 #self.update_membership_list(oldRecord, record, 'researcher',
1368 #self.users.AddPersonToSlice,
1369 #self.users.DeletePersonFromSlice)
1370 #elif record.type == "authority":
1375 # I don't think you plan on running a component manager at this point
1376 # let me clean up the mess of ComponentAPI that is deprecated anyways
1379 #TODO FUNCTIONS SECTION 04/07/2012 SA
1381 #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1383 def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1384 """ This method is a hopefully temporary hack to let the sfa correctly
1385 detach the objects it creates from a remote peer object. This is
1386 needed so that the sfa federation link can work in parallel with
1387 RefreshPeer, as RefreshPeer depends on remote objects being correctly
1390 auth : struct, API authentication structure
1391 AuthMethod : string, Authentication method to use
1392 object_type : string, Object type, among 'site','person','slice',
1394 object_id : int, object_id
1395 shortname : string, peer shortname
1399 logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1403 #TODO Is BindObjectToPeer still necessary ? Currently does nothing
1405 def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1406 remote_object_id=None):
1407 """This method is a hopefully temporary hack to let the sfa correctly
1408 attach the objects it creates to a remote peer object. This is needed
1409 so that the sfa federation link can work in parallel with RefreshPeer,
1410 as RefreshPeer depends on remote objects being correctly marked.
1412 shortname : string, peer shortname
1413 remote_object_id : int, remote object_id, set to 0 if unknown
1417 logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1420 #TODO UpdateSlice 04/07/2012 SA
1421 #Funciton should delete and create another job since oin senslab slice=job
1422 def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1423 """Updates the parameters of an existing slice with the values in
1425 Users may only update slices of which they are members.
1426 PIs may update any of the slices at their sites, or any slices of
1427 which they are members. Admins may update any slice.
1428 Only PIs and admins may update max_nodes. Slices cannot be renewed
1429 (by updating the expires parameter) more than 8 weeks into the future.
1430 Returns 1 if successful, faults otherwise.
1434 logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1437 #TODO UpdatePerson 04/07/2012 SA
1438 def UpdatePerson(self, auth, person_id_or_email, person_fields=None):
1439 """Updates a person. Only the fields specified in person_fields
1440 are updated, all other fields are left untouched.
1441 Users and techs can only update themselves. PIs can only update
1442 themselves and other non-PIs at their sites.
1443 Returns 1 if successful, faults otherwise.
1447 logger.warning("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1450 #TODO GetKeys 04/07/2012 SA
1451 def GetKeys(self, auth, key_filter=None, return_fields=None):
1452 """Returns an array of structs containing details about keys.
1453 If key_filter is specified and is an array of key identifiers,
1454 or a struct of key attributes, only keys matching the filter
1455 will be returned. If return_fields is specified, only the
1456 specified details will be returned.
1458 Admin may query all keys. Non-admins may only query their own keys.
1462 logger.warning("SLABDRIVER GetKeys EMPTY - DO NOTHING \r\n ")
1465 #TODO DeleteKey 04/07/2012 SA
1466 def DeleteKey(self, auth, key_id):
1468 Non-admins may only delete their own keys.
1469 Returns 1 if successful, faults otherwise.
1473 logger.warning("SLABDRIVER DeleteKey EMPTY - DO NOTHING \r\n ")
1477 #TODO : Check rights to delete person
1478 def DeletePerson(self, auth, person_record):
1479 """ Disable an existing account in senslab LDAP.
1480 Users and techs can only delete themselves. PIs can only
1481 delete themselves and other non-PIs at their sites.
1482 ins can delete anyone.
1483 Returns 1 if successful, faults otherwise.
1487 #Disable user account in senslab LDAP
1488 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1489 logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1492 #TODO Check DeleteSlice, check rights 05/07/2012 SA
1493 def DeleteSlice(self, auth, slice_record):
1494 """ Deletes the specified slice.
1495 Senslab : Kill the job associated with the slice if there is one
1496 using DeleteSliceFromNodes.
1497 Updates the slice record in slab db to remove the slice nodes.
1499 Users may only delete slices of which they are members. PIs may
1500 delete any of the slices at their sites, or any slices of which
1501 they are members. Admins may delete any slice.
1502 Returns 1 if successful, faults otherwise.
1506 self.DeleteSliceFromNodes(slice_record)
1507 self.db.update_job(slice_record['hrn'], job_id = -1)
1508 logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1511 #TODO AddPerson 04/07/2012 SA
1512 def AddPerson(self, auth, person_fields=None):
1513 """Adds a new account. Any fields specified in person_fields are used,
1514 otherwise defaults are used.
1515 Accounts are disabled by default. To enable an account,
1517 Returns the new person_id (> 0) if successful, faults otherwise.
1521 logger.warning("SLABDRIVER AddPerson EMPTY - DO NOTHING \r\n ")
1524 #TODO AddPersonToSite 04/07/2012 SA
1525 def AddPersonToSite (self, auth, person_id_or_email, \
1526 site_id_or_login_base=None):
1527 """ Adds the specified person to the specified site. If the person is
1528 already a member of the site, no errors are returned. Does not change
1529 the person's primary site.
1530 Returns 1 if successful, faults otherwise.
1534 logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1537 #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1538 def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1539 """Grants the specified role to the person.
1540 PIs can only grant the tech and user roles to users and techs at their
1541 sites. Admins can grant any role to any user.
1542 Returns 1 if successful, faults otherwise.
1546 logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1549 #TODO AddPersonKey 04/07/2012 SA
1550 def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1551 """Adds a new key to the specified account.
1552 Non-admins can only modify their own keys.
1553 Returns the new key_id (> 0) if successful, faults otherwise.
1557 logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1560 def DeleteLeases(self, leases_id_list, slice_hrn ):
1561 for job_id in leases_id_list:
1562 self.DeleteJobs(job_id, slice_hrn)
1564 logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \r\n " %(leases_id_list, slice_hrn))