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
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']
77 if len(nodes_in_slice) is 0:
78 raise SliverDoesNotExist("No slivers allocated ")
80 top_level_status = 'ready'
82 logger.debug("Slabdriver - sliver_status Sliver status urn %s hrn %s sl\
83 %s \r\n " %(slice_urn, slice_hrn, sl))
85 if sl['oar_job_id'] is not -1:
86 #A job is running on Senslab for this slice
87 # report about the local nodes that are in the slice only
89 nodes_all = self.GetNodes({'hostname':nodes_in_slice},
90 ['node_id', 'hostname','site','boot_state'])
91 nodeall_byhostname = dict([(n['hostname'], n) for n in nodes_all])
95 result['geni_urn'] = slice_urn
96 result['pl_login'] = sl['job_user'] #For compatibility
99 timestamp = float(sl['startTime']) + float(sl['walltime'])
100 result['pl_expires'] = strftime(self.time_format, \
101 gmtime(float(timestamp)))
102 #result['slab_expires'] = strftime(self.time_format,\
103 #gmtime(float(timestamp)))
106 for node in nodeall_byhostname:
108 #res['slab_hostname'] = node['hostname']
109 #res['slab_boot_state'] = node['boot_state']
111 res['pl_hostname'] = nodeall_byhostname[node]['hostname']
112 res['pl_boot_state'] = nodeall_byhostname[node]['boot_state']
113 res['pl_last_contact'] = strftime(self.time_format, \
114 gmtime(float(timestamp)))
115 sliver_id = urn_to_sliver_id(slice_urn, sl['record_id_slice'], \
116 nodeall_byhostname[node]['node_id'])
117 res['geni_urn'] = sliver_id
118 if nodeall_byhostname[node]['boot_state'] == 'Alive':
120 res['geni_status'] = 'ready'
122 res['geni_status'] = 'failed'
123 top_level_status = 'failed'
125 res['geni_error'] = ''
127 resources.append(res)
129 result['geni_status'] = top_level_status
130 result['geni_resources'] = resources
131 logger.debug("SLABDRIVER \tsliver_statusresources %s res %s "\
136 def create_sliver (self, slice_urn, slice_hrn, creds, rspec_string, \
138 aggregate = SlabAggregate(self)
140 slices = SlabSlices(self)
141 peer = slices.get_peer(slice_hrn)
142 sfa_peer = slices.get_sfa_peer(slice_hrn)
145 if not isinstance(creds, list):
149 slice_record = users[0].get('slice_record', {})
152 rspec = RSpec(rspec_string)
153 logger.debug("SLABDRIVER.PY \tcreate_sliver \trspec.version %s " \
157 # ensure site record exists?
158 # ensure slice record exists
159 sfa_slice = slices.verify_slice(slice_hrn, slice_record, peer, \
160 sfa_peer, options=options)
161 requested_attributes = rspec.version.get_slice_attributes()
163 logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice))
165 # ensure person records exists
166 persons = slices.verify_persons(slice_hrn, sfa_slice, users, peer, \
167 sfa_peer, options=options)
171 # add/remove slice from nodes
173 requested_slivers = [node.get('component_name') \
174 for node in rspec.version.get_nodes_with_slivers()]
175 l = [ node for node in rspec.version.get_nodes_with_slivers() ]
176 logger.debug("SLADRIVER \tcreate_sliver requested_slivers \
177 requested_slivers %s listnodes %s" %(requested_slivers,l))
179 nodes = slices.verify_slice_nodes(sfa_slice, requested_slivers, peer)
182 requested_lease_list = []
184 for lease in rspec.version.get_leases():
185 single_requested_lease = {}
186 logger.debug("SLABDRIVER.PY \tcreate_sliver lease %s " %(lease))
187 if not lease.get('lease_id'):
188 single_requested_lease['hostname'] = \
189 slab_xrn_to_hostname(lease.get('component_id').strip())
190 single_requested_lease['start_time'] = lease.get('start_time')
191 single_requested_lease['duration'] = lease.get('duration')
193 kept_leases.append(int(lease['lease_id']))
194 if single_requested_lease.get('hostname'):
195 requested_lease_list.append(single_requested_lease)
197 #dCreate dict of leases by start_time, regrouping nodes reserved at the same
198 #time, for the same amount of time = one job on OAR
199 requested_job_dict = {}
200 for lease in requested_lease_list:
202 #In case it is an asap experiment start_time is empty
203 if lease['start_time'] == '':
204 lease['start_time'] = '0'
206 if lease['start_time'] not in requested_job_dict:
207 if isinstance(lease['hostname'], str):
208 lease['hostname'] = [lease['hostname']]
210 requested_job_dict[lease['start_time']] = lease
213 job_lease = requested_job_dict[lease['start_time']]
214 if lease['duration'] == job_lease['duration'] :
215 job_lease['hostname'].append(lease['hostname'])
220 logger.debug("SLABDRIVER.PY \tcreate_sliver requested_job_dict %s " %(requested_job_dict))
222 leases = slices.verify_slice_leases(sfa_slice, \
223 requested_job_dict, kept_leases, peer)
225 return aggregate.get_rspec(slice_xrn=slice_urn, version=rspec.version)
228 def delete_sliver (self, slice_urn, slice_hrn, creds, options):
230 sfa_slice = self.GetSlices(slice_filter = slice_hrn, \
231 slice_filter_type = 'slice_hrn')
232 logger.debug("SLABDRIVER.PY delete_sliver slice %s" %(sfa_slice))
236 slices = SlabSlices(self)
237 # determine if this is a peer slice
239 peer = slices.get_peer(slice_hrn)
242 self.UnBindObjectFromPeer('slice', \
243 sfa_slice['record_id_slice'], peer)
244 self.DeleteSliceFromNodes(sfa_slice)
247 self.BindObjectToPeer('slice', sfa_slice['slice_id'], \
248 peer, sfa_slice['peer_slice_id'])
252 def AddSlice(self, slice_record):
253 slab_slice = SliceSenslab( slice_hrn = slice_record['slice_hrn'], \
254 record_id_slice= slice_record['record_id_slice'] , \
255 record_id_user= slice_record['record_id_user'], \
256 peer_authority = slice_record['peer_authority'])
257 logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s slab_slice %s" \
258 %(slice_record,slab_slice))
259 slab_dbsession.add(slab_slice)
260 slab_dbsession.commit()
263 # first 2 args are None in case of resource discovery
264 def list_resources (self, slice_urn, slice_hrn, creds, options):
265 #cached_requested = options.get('cached', True)
267 version_manager = VersionManager()
268 # get the rspec's return format from options
270 version_manager.get_version(options.get('geni_rspec_version'))
271 version_string = "rspec_%s" % (rspec_version)
273 #panos adding the info option to the caching key (can be improved)
274 if options.get('info'):
275 version_string = version_string + "_" + \
276 options.get('info', 'default')
278 # look in cache first
279 #if cached_requested and self.cache and not slice_hrn:
280 #rspec = self.cache.get(version_string)
282 #logger.debug("SlabDriver.ListResources: \
283 #returning cached advertisement")
286 #panos: passing user-defined options
287 aggregate = SlabAggregate(self)
288 origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
289 options.update({'origin_hrn':origin_hrn})
290 rspec = aggregate.get_rspec(slice_xrn=slice_urn, \
291 version=rspec_version, options=options)
294 #if self.cache and not slice_hrn:
295 #logger.debug("Slab.ListResources: stores advertisement in cache")
296 #self.cache.add(version_string, rspec)
301 def list_slices (self, creds, options):
302 # look in cache first
304 #slices = self.cache.get('slices')
306 #logger.debug("PlDriver.list_slices returns from cache")
311 slices = self.GetSlices()
312 logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices))
313 slice_hrns = [slab_slice['slice_hrn'] for slab_slice in slices]
314 #slice_hrns = [slicename_to_hrn(self.hrn, slab_slice['slice_hrn']) \
315 #for slab_slice in slices]
316 slice_urns = [hrn_to_urn(slice_hrn, 'slice') \
317 for slice_hrn in slice_hrns]
321 #logger.debug ("SlabDriver.list_slices stores value in cache")
322 #self.cache.add('slices', slice_urns)
326 #No site or node register supported
327 def register (self, sfa_record, hrn, pub_key):
328 record_type = sfa_record['type']
329 slab_record = self.sfa_fields_to_slab_fields(record_type, hrn, \
333 if record_type == 'slice':
334 acceptable_fields = ['url', 'instantiation', 'name', 'description']
335 for key in slab_record.keys():
336 if key not in acceptable_fields:
338 logger.debug("SLABDRIVER.PY register")
339 slices = self.GetSlices(slice_filter =slab_record['hrn'], \
340 slice_filter_type = 'slice_hrn')
342 pointer = self.AddSlice(slab_record)
344 pointer = slices[0]['slice_id']
346 elif record_type == 'user':
347 persons = self.GetPersons([sfa_record])
348 #persons = self.GetPersons([sfa_record['hrn']])
350 pointer = self.AddPerson(dict(sfa_record))
353 pointer = persons[0]['person_id']
355 #Does this make sense to senslab ?
356 #if 'enabled' in sfa_record and sfa_record['enabled']:
357 #self.UpdatePerson(pointer, \
358 #{'enabled': sfa_record['enabled']})
360 #TODO register Change this AddPersonToSite stuff 05/07/2012 SA
361 # add this person to the site only if
362 # she is being added for the first
363 # time by sfa and doesnt already exist in plc
364 if not persons or not persons[0]['site_ids']:
365 login_base = get_leaf(sfa_record['authority'])
366 self.AddPersonToSite(pointer, login_base)
368 # What roles should this user have?
369 #TODO : DElete this AddRoleToPerson 04/07/2012 SA
370 #Function prototype is :
371 #AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email)
372 #what's the pointer doing here?
373 self.AddRoleToPerson('user', pointer)
376 self.AddPersonKey(pointer, {'key_type' : 'ssh', \
379 #No node adding outside OAR
383 #No site or node record update allowed
384 def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
385 pointer = old_sfa_record['pointer']
386 old_sfa_record_type = old_sfa_record['type']
388 # new_key implemented for users only
389 if new_key and old_sfa_record_type not in [ 'user' ]:
390 raise UnknownSfaType(old_sfa_record_type)
392 #if (type == "authority"):
393 #self.shell.UpdateSite(pointer, new_sfa_record)
395 if old_sfa_record_type == "slice":
396 slab_record = self.sfa_fields_to_slab_fields(old_sfa_record_type, \
398 if 'name' in slab_record:
399 slab_record.pop('name')
400 #Prototype should be UpdateSlice(self,
401 #auth, slice_id_or_name, slice_fields)
402 #Senslab cannot update slice since slice = job
403 #so we must delete and create another job
404 self.UpdateSlice(pointer, slab_record)
406 elif old_sfa_record_type == "user":
408 all_fields = new_sfa_record
409 for key in all_fields.keys():
410 if key in ['first_name', 'last_name', 'title', 'email',
411 'password', 'phone', 'url', 'bio', 'accepted_aup',
413 update_fields[key] = all_fields[key]
414 self.UpdatePerson(pointer, update_fields)
417 # must check this key against the previous one if it exists
418 persons = self.GetPersons([pointer], ['key_ids'])
420 keys = person['key_ids']
421 keys = self.GetKeys(person['key_ids'])
423 # Delete all stale keys
426 if new_key != key['key']:
427 self.DeleteKey(key['key_id'])
431 self.AddPersonKey(pointer, {'key_type': 'ssh', \
438 def remove (self, sfa_record):
439 sfa_record_type = sfa_record['type']
440 hrn = sfa_record['hrn']
441 record_id = sfa_record['record_id']
442 if sfa_record_type == 'user':
444 #get user from senslab ldap
445 person = self.GetPersons(sfa_record)
446 #No registering at a given site in Senslab.
447 #Once registered to the LDAP, all senslab sites are
450 #Mark account as disabled in ldap
451 self.DeletePerson(sfa_record)
452 elif sfa_record_type == 'slice':
453 if self.GetSlices(slice_filter = hrn, \
454 slice_filter_type = 'slice_hrn'):
455 self.DeleteSlice(sfa_record_type)
457 #elif type == 'authority':
458 #if self.GetSites(pointer):
459 #self.DeleteSite(pointer)
465 #TODO clean GetPeers. 05/07/12SA
466 def GetPeers (self, auth = None, peer_filter=None, return_fields_list=None):
468 existing_records = {}
469 existing_hrns_by_types = {}
470 logger.debug("SLABDRIVER \tGetPeers auth = %s, peer_filter %s, \
471 return_field %s " %(auth , peer_filter, return_fields_list))
472 all_records = dbsession.query(RegRecord).filter(RegRecord.type.like('%authority%')).all()
473 for record in all_records:
474 existing_records[(record.hrn, record.type)] = record
475 if record.type not in existing_hrns_by_types:
476 existing_hrns_by_types[record.type] = [record.hrn]
477 logger.debug("SLABDRIVER \tGetPeer\t NOT IN \
478 existing_hrns_by_types %s " %( existing_hrns_by_types))
481 logger.debug("SLABDRIVER \tGetPeer\t \INNN type %s hrn %s " \
482 %(record.type,record.hrn))
483 existing_hrns_by_types[record.type].append(record.hrn)
486 logger.debug("SLABDRIVER \tGetPeer\texisting_hrns_by_types %s "\
487 %( existing_hrns_by_types))
492 records_list.append(existing_records[(peer_filter,'authority')])
494 for hrn in existing_hrns_by_types['authority']:
495 records_list.append(existing_records[(hrn,'authority')])
497 logger.debug("SLABDRIVER \tGetPeer \trecords_list %s " \
503 return_records = records_list
504 if not peer_filter and not return_fields_list:
508 logger.debug("SLABDRIVER \tGetPeer return_records %s " \
510 return return_records
513 #TODO : Handling OR request in make_ldap_filters_from_records
514 #instead of the for loop
515 #over the records' list
516 def GetPersons(self, person_filter=None, return_fields_list=None):
518 person_filter should be a list of dictionnaries when not set to None.
519 Returns a list of users whose accounts are enabled found in ldap.
522 logger.debug("SLABDRIVER \tGetPersons person_filter %s" \
525 if person_filter and isinstance(person_filter, list):
526 #If we are looking for a list of users (list of dict records)
527 #Usually the list contains only one user record
528 for searched_attributes in person_filter:
530 #Get only enabled user accounts in senslab LDAP :
531 #add a filter for make_ldap_filters_from_record
532 person = self.ldap.LdapFindUser(searched_attributes, \
533 is_user_enabled=True)
534 person_list.append(person)
537 #Get only enabled user accounts in senslab LDAP :
538 #add a filter for make_ldap_filters_from_record
539 person_list = self.ldap.LdapFindUser(is_user_enabled=True)
543 def GetTimezone(self):
544 server_timestamp, server_tz = self.oar.parser.\
545 SendRequest("GET_timezone")
546 return server_timestamp, server_tz
549 def DeleteJobs(self, job_id, slice_hrn):
550 if not job_id or job_id is -1:
552 username = slice_hrn.split(".")[-1].rstrip("_slice")
554 reqdict['method'] = "delete"
555 reqdict['strval'] = str(job_id)
557 answer = self.oar.POSTRequestToOARRestAPI('DELETE_jobs_id', \
559 logger.debug("SLABDRIVER \tDeleteJobs jobid %s \r\n answer %s username %s" \
560 %(job_id,answer, username))
565 ##TODO : Unused GetJobsId ? SA 05/07/12
566 #def GetJobsId(self, job_id, username = None ):
568 #Details about a specific job.
569 #Includes details about submission time, jot type, state, events,
570 #owner, assigned ressources, walltime etc...
574 #node_list_k = 'assigned_network_address'
575 ##Get job info from OAR
576 #job_info = self.oar.parser.SendRequest(req, job_id, username)
578 #logger.debug("SLABDRIVER \t GetJobsId %s " %(job_info))
580 #if job_info['state'] == 'Terminated':
581 #logger.debug("SLABDRIVER \t GetJobsId job %s TERMINATED"\
584 #if job_info['state'] == 'Error':
585 #logger.debug("SLABDRIVER \t GetJobsId ERROR message %s "\
590 #logger.error("SLABDRIVER \tGetJobsId KeyError")
593 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
595 ##Replaces the previous entry
596 ##"assigned_network_address" / "reserved_resources"
598 #job_info.update({'node_ids':parsed_job_info[node_list_k]})
599 #del job_info[node_list_k]
600 #logger.debug(" \r\nSLABDRIVER \t GetJobsId job_info %s " %(job_info))
604 def GetJobsResources(self, job_id, username = None):
605 #job_resources=['reserved_resources', 'assigned_resources',\
606 #'job_id', 'job_uri', 'assigned_nodes',\
608 #assigned_res = ['resource_id', 'resource_uri']
609 #assigned_n = ['node', 'node_uri']
611 req = "GET_jobs_id_resources"
612 node_list_k = 'reserved_resources'
614 #Get job resources list from OAR
615 node_id_list = self.oar.parser.SendRequest(req, job_id, username)
616 logger.debug("SLABDRIVER \t GetJobsResources %s " %(node_id_list))
619 self.__get_hostnames_from_oar_node_ids(node_id_list)
621 #parsed_job_info = self.get_info_on_reserved_nodes(job_info, \
623 #Replaces the previous entry "assigned_network_address" /
624 #"reserved_resources"
626 job_info = {'node_ids': hostname_list}
631 def get_info_on_reserved_nodes(self, job_info, node_list_name):
632 #Get the list of the testbed nodes records and make a
633 #dictionnary keyed on the hostname out of it
634 node_list_dict = self.GetNodes()
635 #node_hostname_list = []
636 node_hostname_list = [node['hostname'] for node in node_list_dict]
637 #for node in node_list_dict:
638 #node_hostname_list.append(node['hostname'])
639 node_dict = dict(zip(node_hostname_list, node_list_dict))
641 reserved_node_hostname_list = []
642 for index in range(len(job_info[node_list_name])):
643 #job_info[node_list_name][k] =
644 reserved_node_hostname_list[index] = \
645 node_dict[job_info[node_list_name][index]]['hostname']
647 logger.debug("SLABDRIVER \t get_info_on_reserved_nodes \
648 reserved_node_hostname_list %s" \
649 %(reserved_node_hostname_list))
651 logger.error("SLABDRIVER \t get_info_on_reserved_nodes KEYERROR " )
653 return reserved_node_hostname_list
655 def GetNodesCurrentlyInUse(self):
656 """Returns a list of all the nodes already involved in an oar job"""
657 return self.oar.parser.SendRequest("GET_running_jobs")
659 def __get_hostnames_from_oar_node_ids(self, resource_id_list ):
660 full_nodes_dict_list = self.GetNodes()
661 #Put the full node list into a dictionary keyed by oar node id
662 oar_id_node_dict = {}
663 for node in full_nodes_dict_list:
664 oar_id_node_dict[node['oar_id']] = node
666 logger.debug("SLABDRIVER \t __get_hostnames_from_oar_node_ids\
667 oar_id_node_dict %s" %(oar_id_node_dict))
669 hostname_dict_list = []
670 for resource_id in resource_id_list:
671 #Because jobs requested "asap" do not have defined resources
672 if resource_id is not "Undefined":
673 hostname_dict_list.append({'hostname' : \
674 oar_id_node_dict[resource_id]['hostname'],
675 'site_id' : oar_id_node_dict[resource_id]['site']})
677 #hostname_list.append(oar_id_node_dict[resource_id]['hostname'])
678 return hostname_dict_list
680 def GetReservedNodes(self):
681 #Get the nodes in use and the reserved nodes
682 reservation_dict_list = \
683 self.oar.parser.SendRequest("GET_reserved_nodes")
686 for resa in reservation_dict_list:
687 logger.debug ("GetReservedNodes resa %s"%(resa))
688 #dict list of hostnames and their site
689 resa['reserved_nodes'] = \
690 self.__get_hostnames_from_oar_node_ids(resa['resource_ids'])
692 #del resa['resource_ids']
693 return reservation_dict_list
695 def GetNodes(self, node_filter_dict = None, return_fields_list = None):
697 node_filter_dict : dictionnary of lists
700 node_dict_by_id = self.oar.parser.SendRequest("GET_resources_full")
701 node_dict_list = node_dict_by_id.values()
703 #No filtering needed return the list directly
704 if not (node_filter_dict or return_fields_list):
705 return node_dict_list
707 return_node_list = []
709 for filter_key in node_filter_dict:
711 #Filter the node_dict_list by each value contained in the
712 #list node_filter_dict[filter_key]
713 for value in node_filter_dict[filter_key]:
714 for node in node_dict_list:
715 if node[filter_key] == value:
716 if return_fields_list :
718 for k in return_fields_list:
720 return_node_list.append(tmp)
722 return_node_list.append(node)
724 logger.log_exc("GetNodes KeyError")
728 return return_node_list
731 def GetSites(self, site_filter_name_list = None, return_fields_list = None):
732 site_dict = self.oar.parser.SendRequest("GET_sites")
733 #site_dict : dict where the key is the sit ename
734 return_site_list = []
735 if not ( site_filter_name_list or return_fields_list):
736 return_site_list = site_dict.values()
737 return return_site_list
739 for site_filter_name in site_filter_name_list:
740 if site_filter_name in site_dict:
741 if return_fields_list:
742 for field in return_fields_list:
745 tmp[field] = site_dict[site_filter_name][field]
747 logger.error("GetSites KeyError %s "%(field))
749 return_site_list.append(tmp)
751 return_site_list.append( site_dict[site_filter_name])
754 return return_site_list
755 #warning return_fields_list paramr emoved (Not used)
756 def GetSlices(self, slice_filter = None, slice_filter_type = None):
757 #def GetSlices(self, slice_filter = None, slice_filter_type = None, \
758 #return_fields_list = None):
759 """ Get the slice records from the slab db.
760 Returns a slice ditc if slice_filter and slice_filter_type
762 Returns a list of slice dictionnaries if there are no filters
766 return_slice_list = []
769 authorized_filter_types_list = ['slice_hrn', 'record_id_user']
770 logger.debug("SLABDRIVER \tGetSlices authorized_filter_types_list %s"\
771 %(authorized_filter_types_list))
772 if slice_filter_type in authorized_filter_types_list:
773 if slice_filter_type == 'slice_hrn':
774 slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).first()
776 if slice_filter_type == 'record_id_user':
777 slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).first()
781 slicerec_dict = slicerec.dump_sqlalchemyobj_to_dict()
782 logger.debug("SLABDRIVER \tGetSlices slicerec_dict %s" \
785 login = slicerec_dict['slice_hrn'].split(".")[1].split("_")[0]
786 logger.debug("\r\n SLABDRIVER \tGetSlices login %s \
788 %(login, slicerec_dict))
789 if slicerec_dict['oar_job_id'] is not -1:
790 #Check with OAR the status of the job if a job id is in
792 rslt = self.GetJobsResources(slicerec_dict['oar_job_id'], \
796 slicerec_dict.update(rslt)
797 slicerec_dict.update({'hrn':\
798 str(slicerec_dict['slice_hrn'])})
799 #If GetJobsResources is empty, this means the job is
800 #now in the 'Terminated' state
801 #Update the slice record
803 self.db.update_job(slice_filter, job_id = -1)
804 slicerec_dict['oar_job_id'] = -1
806 update({'hrn':str(slicerec_dict['slice_hrn'])})
809 slicerec_dict['node_ids'] = slicerec_dict['node_list']
813 logger.debug("SLABDRIVER.PY \tGetSlices slicerec_dict %s"\
820 slice_list = slab_dbsession.query(SliceSenslab).all()
821 return_slice_list = []
822 for record in slice_list:
823 return_slice_list.append(record.dump_sqlalchemyobj_to_dict())
825 logger.debug("SLABDRIVER.PY \tGetSlices slices %s \
826 slice_filter %s " %(return_slice_list, slice_filter))
828 #if return_fields_list:
829 #return_slice_list = parse_filter(sliceslist, \
830 #slice_filter,'slice', return_fields_list)
832 return return_slice_list
838 def testbed_name (self): return self.hrn
840 # 'geni_request_rspec_versions' and 'geni_ad_rspec_versions' are mandatory
841 def aggregate_version (self):
842 version_manager = VersionManager()
843 ad_rspec_versions = []
844 request_rspec_versions = []
845 for rspec_version in version_manager.versions:
846 if rspec_version.content_type in ['*', 'ad']:
847 ad_rspec_versions.append(rspec_version.to_dict())
848 if rspec_version.content_type in ['*', 'request']:
849 request_rspec_versions.append(rspec_version.to_dict())
851 'testbed':self.testbed_name(),
852 'geni_request_rspec_versions': request_rspec_versions,
853 'geni_ad_rspec_versions': ad_rspec_versions,
862 # Convert SFA fields to PLC fields for use when registering up updating
863 # registry record in the PLC database
865 # @param type type of record (user, slice, ...)
866 # @param hrn human readable name
867 # @param sfa_fields dictionary of SFA fields
868 # @param slab_fields dictionary of PLC fields (output)
870 def sfa_fields_to_slab_fields(self, sfa_type, hrn, record):
872 def convert_ints(tmpdict, int_fields):
873 for field in int_fields:
875 tmpdict[field] = int(tmpdict[field])
878 #for field in record:
879 # slab_record[field] = record[field]
881 if sfa_type == "slice":
882 #instantion used in get_slivers ?
883 if not "instantiation" in slab_record:
884 slab_record["instantiation"] = "senslab-instantiated"
885 #slab_record["hrn"] = hrn_to_pl_slicename(hrn)
886 #Unused hrn_to_pl_slicename because Slab's hrn already in the appropriate form SA 23/07/12
887 slab_record["hrn"] = hrn
888 logger.debug("SLABDRIVER.PY sfa_fields_to_slab_fields \
889 slab_record %s " %(slab_record['hrn']))
891 slab_record["url"] = record["url"]
892 if "description" in record:
893 slab_record["description"] = record["description"]
894 if "expires" in record:
895 slab_record["expires"] = int(record["expires"])
897 #nodes added by OAR only and then imported to SFA
898 #elif type == "node":
899 #if not "hostname" in slab_record:
900 #if not "hostname" in record:
901 #raise MissingSfaInfo("hostname")
902 #slab_record["hostname"] = record["hostname"]
903 #if not "model" in slab_record:
904 #slab_record["model"] = "geni"
907 #elif type == "authority":
908 #slab_record["login_base"] = hrn_to_slab_login_base(hrn)
910 #if not "name" in slab_record:
911 #slab_record["name"] = hrn
913 #if not "abbreviated_name" in slab_record:
914 #slab_record["abbreviated_name"] = hrn
916 #if not "enabled" in slab_record:
917 #slab_record["enabled"] = True
919 #if not "is_public" in slab_record:
920 #slab_record["is_public"] = True
927 def __transforms_timestamp_into_date(self, xp_utc_timestamp = None):
928 """ Transforms unix timestamp into valid OAR date format """
930 #Used in case of a scheduled experiment (not immediate)
931 #To run an XP immediately, don't specify date and time in RSpec
932 #They will be set to None.
934 #transform the xp_utc_timestamp into server readable time
935 xp_server_readable_date = datetime.fromtimestamp(int(\
936 xp_utc_timestamp)).strftime(self.time_format)
938 return xp_server_readable_date
946 def LaunchExperimentOnOAR(self, added_nodes, slice_name, \
947 lease_start_time, lease_duration, slice_user=None):
949 lease_dict['lease_start_time'] = lease_start_time
950 lease_dict['lease_duration'] = lease_duration
951 lease_dict['added_nodes'] = added_nodes
952 lease_dict['slice_name'] = slice_name
953 lease_dict['slice_user'] = slice_user
954 lease_dict['grain'] = self.GetLeaseGranularity()
955 lease_dict['time_format'] = self.time_format
957 def __create_job_structure_request_for_OAR(lease_dict):
958 """ Creates the structure needed for a correct POST on OAR.
959 Makes the timestamp transformation into the appropriate format.
960 Sends the POST request to create the job with the resources in
971 reqdict['workdir'] = '/tmp'
972 reqdict['resource'] = "{network_address in ("
974 for node in lease_dict['added_nodes']:
975 logger.debug("\r\n \r\n OARrestapi \t __create_job_structure_request_for_OAR \
978 # Get the ID of the node
980 reqdict['resource'] += "'" + nodeid + "', "
981 nodeid_list.append(nodeid)
983 custom_length = len(reqdict['resource'])- 2
984 reqdict['resource'] = reqdict['resource'][0:custom_length] + \
985 ")}/nodes=" + str(len(nodeid_list))
987 def __process_walltime(duration):
988 """ Calculates the walltime in seconds from the duration in H:M:S
989 specified in the RSpec.
993 # Fixing the walltime by adding a few delays.
994 # First put the walltime in seconds oarAdditionalDelay = 20;
995 # additional delay for /bin/sleep command to
996 # take in account prologue and epilogue scripts execution
997 # int walltimeAdditionalDelay = 120; additional delay
998 desired_walltime = duration
999 total_walltime = desired_walltime + 140#+2 min 20
1000 sleep_walltime = desired_walltime + 20 #+20 sec
1002 #Put the walltime back in str form
1003 #First get the hours
1004 walltime.append(str(total_walltime / 3600))
1005 total_walltime = total_walltime - 3600 * int(walltime[0])
1006 #Get the remaining minutes
1007 walltime.append(str(total_walltime / 60))
1008 total_walltime = total_walltime - 60 * int(walltime[1])
1010 walltime.append(str(total_walltime))
1013 logger.log_exc(" __process_walltime duration null")
1015 return walltime, sleep_walltime
1018 walltime, sleep_walltime = \
1019 __process_walltime(int(lease_dict['lease_duration'])*lease_dict['grain'])
1022 reqdict['resource'] += ",walltime=" + str(walltime[0]) + \
1023 ":" + str(walltime[1]) + ":" + str(walltime[2])
1024 reqdict['script_path'] = "/bin/sleep " + str(sleep_walltime)
1026 #In case of a scheduled experiment (not immediate)
1027 #To run an XP immediately, don't specify date and time in RSpec
1028 #They will be set to None.
1029 if lease_dict['lease_start_time'] is not '0':
1030 #Readable time accepted by OAR
1031 start_time = datetime.fromtimestamp(int(lease_dict['lease_start_time'])).\
1032 strftime(lease_dict['time_format'])
1033 reqdict['reservation'] = start_time
1034 #If there is not start time, Immediate XP. No need to add special
1038 reqdict['type'] = "deploy"
1039 reqdict['directory'] = ""
1040 reqdict['name'] = "SFA_" + lease_dict['slice_user']
1045 #Create the request for OAR
1046 reqdict = __create_job_structure_request_for_OAR(lease_dict)
1047 # first step : start the OAR job and update the job
1048 logger.debug("SLABDRIVER.PY \tLaunchExperimentOnOAR reqdict %s\
1051 answer = self.oar.POSTRequestToOARRestAPI('POST_job', \
1052 reqdict, slice_user)
1053 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s " %(answer))
1055 jobid = answer['id']
1057 logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \
1058 Impossible to create job %s " %(answer))
1062 def __configure_experiment(jobid, added_nodes):
1063 # second step : configure the experiment
1064 # we need to store the nodes in a yaml (well...) file like this :
1065 # [1,56,23,14,45,75] with name /tmp/sfa<jobid>.json
1066 job_file = open('/tmp/sfa/'+ str(jobid) + '.json', 'w')
1068 job_file.write(str(added_nodes[0].strip('node')))
1069 for node in added_nodes[1:len(added_nodes)] :
1070 job_file.write(', '+ node.strip('node'))
1075 def __launch_senslab_experiment(jobid):
1076 # third step : call the senslab-experiment wrapper
1077 #command= "java -jar target/sfa-1.0-jar-with-dependencies.jar
1078 # "+str(jobid)+" "+slice_user
1079 javacmdline = "/usr/bin/java"
1081 "/opt/senslabexperimentwrapper/sfa-1.0-jar-with-dependencies.jar"
1082 #ret=subprocess.check_output(["/usr/bin/java", "-jar", ", \
1083 #str(jobid), slice_user])
1084 output = subprocess.Popen([javacmdline, "-jar", jarname, str(jobid), \
1085 slice_user],stdout=subprocess.PIPE).communicate()[0]
1087 logger.debug("SLABDRIVER \t __configure_experiment wrapper returns%s " \
1094 logger.debug("SLABDRIVER \tLaunchExperimentOnOAR jobid %s \
1095 added_nodes %s slice_user %s" %(jobid, added_nodes, slice_user))
1096 self.db.update_job( slice_name, jobid, added_nodes)
1098 __configure_experiment(jobid, added_nodes)
1099 __launch_senslab_experiment(jobid)
1103 def AddLeases(self, hostname_list, slice_record, lease_start_time, lease_duration):
1104 logger.debug("SLABDRIVER \r\n \r\n \t AddLeases hostname_list %s \
1105 slice_record %s lease_start_time %s lease_duration %s "\
1106 %( hostname_list, slice_record , lease_start_time, \
1109 tmp = slice_record['PI'][0].split(".")
1110 username = tmp[(len(tmp)-1)]
1111 self.LaunchExperimentOnOAR(hostname_list, slice_record['name'], lease_start_time, lease_duration, username)
1112 start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format)
1113 logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time))
1118 #Delete the jobs and updates the job id in the senslab table
1120 #Does not clear the node list
1121 def DeleteSliceFromNodes(self, slice_record):
1122 # Get user information
1124 self.DeleteJobs(slice_record['oar_job_id'], slice_record['hrn'])
1125 self.db.update_job(slice_record['hrn'], job_id = -1)
1129 def GetLeaseGranularity(self):
1130 """ Returns the granularity of Senslab testbed.
1131 Defined in seconds. """
1136 def GetLeases(self, lease_filter_dict=None, return_fields_list=None):
1137 unfiltered_reservation_list = self.GetReservedNodes()
1138 reservation_list = []
1139 #Find the slice associated with this user senslab ldap uid
1140 logger.debug(" SLABDRIVER.PY \tGetLeases ")
1141 #Create user dict first to avoir looking several times for
1142 #the same user in LDAP SA 27/07/12
1144 for resa in unfiltered_reservation_list:
1145 logger.debug("SLABDRIVER \tGetLeases USER %s"\
1147 if resa['user'] not in resa_user_dict:
1148 logger.debug("SLABDRIVER \tGetLeases userNOTIN ")
1149 ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1150 ldap_info = ldap_info[0][1]
1151 user = dbsession.query(RegUser).filter_by(email = \
1152 ldap_info['mail'][0]).first()
1153 #Separated in case user not in database : record_id not defined SA 17/07//12
1154 query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1155 if query_slice_info:
1156 slice_info = query_slice_info.first()
1159 resa_user_dict[resa['user']] = {}
1160 resa_user_dict[resa['user']]['ldap_info'] = user
1161 resa_user_dict[resa['user']]['slice_info'] = slice_info
1163 logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\
1165 for resa in unfiltered_reservation_list:
1167 #ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')')
1168 #ldap_info = ldap_info[0][1]
1170 #user = dbsession.query(RegUser).filter_by(email = \
1171 #ldap_info['mail'][0]).first()
1172 ##Separated in case user not in database : record_id not defined SA 17/07//12
1173 #query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id)
1174 #if query_slice_info:
1175 #slice_info = query_slice_info.first()
1177 resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info'].slice_hrn
1178 resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice')
1180 #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice')
1181 resa['component_id_list'] = []
1182 #Transform the hostnames into urns (component ids)
1183 for node in resa['reserved_nodes']:
1184 #resa['component_id_list'].append(hostname_to_urn(self.hrn, \
1185 #self.root_auth, node['hostname']))
1186 slab_xrn = slab_xrn_object(self.root_auth, node['hostname'])
1187 resa['component_id_list'].append(slab_xrn.urn)
1189 #Filter the reservation list if necessary
1190 #Returns all the leases associated with a given slice
1191 if lease_filter_dict:
1192 logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\
1193 %(lease_filter_dict))
1194 for resa in unfiltered_reservation_list:
1195 if lease_filter_dict['name'] == resa['slice_hrn']:
1196 reservation_list.append(resa)
1198 reservation_list = unfiltered_reservation_list
1200 logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\
1201 %(reservation_list))
1202 return reservation_list
1204 def augment_records_with_testbed_info (self, sfa_records):
1205 return self.fill_record_info (sfa_records)
1207 def fill_record_info(self, record_list):
1209 Given a SFA record, fill in the senslab specific and SFA specific
1210 fields in the record.
1213 logger.debug("SLABDRIVER \tfill_record_info records %s " %(record_list))
1214 if not isinstance(record_list, list):
1215 record_list = [record_list]
1218 for record in record_list:
1219 #If the record is a SFA slice record, then add information
1220 #about the user of this slice. This kind of
1221 #information is in the Senslab's DB.
1222 if str(record['type']) == 'slice':
1223 #Get slab slice record.
1224 recslice = self.GetSlices(slice_filter = \
1225 str(record['hrn']),\
1226 slice_filter_type = 'slice_hrn')
1227 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1228 recslice['record_id_user']).first()
1229 logger.debug( "SLABDRIVER.PY \t fill_record_info SLICE \
1230 rec %s \r\n \r\n" %(recslice))
1231 record.update({'PI':[recuser.hrn],
1232 'researcher': [recuser.hrn],
1233 'name':record['hrn'],
1234 'oar_job_id':recslice['oar_job_id'],
1236 'person_ids':[recslice['record_id_user']],
1237 'geni_urn':'', #For client_helper.py compatibility
1238 'keys':'', #For client_helper.py compatibility
1239 'key_ids':''}) #For client_helper.py compatibility
1241 elif str(record['type']) == 'user':
1242 #The record is a SFA user record.
1243 #Get the information about his slice from Senslab's DB
1244 #and add it to the user record.
1245 recslice = self.GetSlices(\
1246 slice_filter = record['record_id'],\
1247 slice_filter_type = 'record_id_user')
1249 logger.debug( "SLABDRIVER.PY \t fill_record_info user \
1250 rec %s \r\n \r\n" %(recslice))
1251 #Append slice record in records list,
1252 #therefore fetches user and slice info again(one more loop)
1253 #Will update PIs and researcher for the slice
1254 recuser = dbsession.query(RegRecord).filter_by(record_id = \
1255 recslice['record_id_user']).first()
1256 recslice.update({'PI':[recuser.hrn],
1257 'researcher': [recuser.hrn],
1258 'name':record['hrn'],
1259 'oar_job_id':recslice['oar_job_id'],
1261 'person_ids':[recslice['record_id_user']]})
1263 #GetPersons takes [] as filters
1264 #user_slab = self.GetPersons([{'hrn':recuser.hrn}])
1265 user_slab = self.GetPersons([record])
1267 recslice.update({'type':'slice', \
1268 'hrn':recslice['slice_hrn']})
1269 record.update(user_slab[0])
1270 #For client_helper.py compatibility
1271 record.update( { 'geni_urn':'',
1274 record_list.append(recslice)
1276 logger.debug("SLABDRIVER.PY \tfill_record_info ADDING SLICE\
1277 INFO TO USER records %s" %(record_list))
1280 except TypeError, error:
1281 logger.log_exc("SLABDRIVER \t fill_record_info EXCEPTION %s"\
1286 #self.fill_record_slab_info(records)
1292 #TODO Update membership? update_membership_list SA 05/07/12
1293 #def update_membership_list(self, oldRecord, record, listName, addFunc, \
1295 ## get a list of the HRNs tht are members of the old and new records
1297 #oldList = oldRecord.get(listName, [])
1300 #newList = record.get(listName, [])
1302 ## if the lists are the same, then we don't have to update anything
1303 #if (oldList == newList):
1306 ## build a list of the new person ids, by looking up each person to get
1310 #records = table.find({'type': 'user', 'hrn': newList})
1311 #for rec in records:
1312 #newIdList.append(rec['pointer'])
1314 ## build a list of the old person ids from the person_ids field
1316 #oldIdList = oldRecord.get("person_ids", [])
1317 #containerId = oldRecord.get_pointer()
1319 ## if oldRecord==None, then we are doing a Register, instead of an
1322 #containerId = record.get_pointer()
1324 ## add people who are in the new list, but not the oldList
1325 #for personId in newIdList:
1326 #if not (personId in oldIdList):
1327 #addFunc(self.plauth, personId, containerId)
1329 ## remove people who are in the old list, but not the new list
1330 #for personId in oldIdList:
1331 #if not (personId in newIdList):
1332 #delFunc(self.plauth, personId, containerId)
1334 #def update_membership(self, oldRecord, record):
1336 #if record.type == "slice":
1337 #self.update_membership_list(oldRecord, record, 'researcher',
1338 #self.users.AddPersonToSlice,
1339 #self.users.DeletePersonFromSlice)
1340 #elif record.type == "authority":
1345 # I don't think you plan on running a component manager at this point
1346 # let me clean up the mess of ComponentAPI that is deprecated anyways
1349 #TODO FUNCTIONS SECTION 04/07/2012 SA
1351 #TODO : Is UnBindObjectFromPeer still necessary ? Currently does nothing
1353 def UnBindObjectFromPeer(self, auth, object_type, object_id, shortname):
1354 """ This method is a hopefully temporary hack to let the sfa correctly
1355 detach the objects it creates from a remote peer object. This is
1356 needed so that the sfa federation link can work in parallel with
1357 RefreshPeer, as RefreshPeer depends on remote objects being correctly
1360 auth : struct, API authentication structure
1361 AuthMethod : string, Authentication method to use
1362 object_type : string, Object type, among 'site','person','slice',
1364 object_id : int, object_id
1365 shortname : string, peer shortname
1369 logger.warning("SLABDRIVER \tUnBindObjectFromPeer EMPTY-\
1373 #TODO Is BindObjectToPeer still necessary ? Currently does nothing
1375 def BindObjectToPeer(self, auth, object_type, object_id, shortname=None, \
1376 remote_object_id=None):
1377 """This method is a hopefully temporary hack to let the sfa correctly
1378 attach the objects it creates to a remote peer object. This is needed
1379 so that the sfa federation link can work in parallel with RefreshPeer,
1380 as RefreshPeer depends on remote objects being correctly marked.
1382 shortname : string, peer shortname
1383 remote_object_id : int, remote object_id, set to 0 if unknown
1387 logger.warning("SLABDRIVER \tBindObjectToPeer EMPTY - DO NOTHING \r\n ")
1390 #TODO UpdateSlice 04/07/2012 SA
1391 #Funciton should delete and create another job since oin senslab slice=job
1392 def UpdateSlice(self, auth, slice_id_or_name, slice_fields=None):
1393 """Updates the parameters of an existing slice with the values in
1395 Users may only update slices of which they are members.
1396 PIs may update any of the slices at their sites, or any slices of
1397 which they are members. Admins may update any slice.
1398 Only PIs and admins may update max_nodes. Slices cannot be renewed
1399 (by updating the expires parameter) more than 8 weeks into the future.
1400 Returns 1 if successful, faults otherwise.
1404 logger.warning("SLABDRIVER UpdateSlice EMPTY - DO NOTHING \r\n ")
1407 #TODO UpdatePerson 04/07/2012 SA
1408 def UpdatePerson(self, auth, person_id_or_email, person_fields=None):
1409 """Updates a person. Only the fields specified in person_fields
1410 are updated, all other fields are left untouched.
1411 Users and techs can only update themselves. PIs can only update
1412 themselves and other non-PIs at their sites.
1413 Returns 1 if successful, faults otherwise.
1417 logger.warning("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ")
1420 #TODO GetKeys 04/07/2012 SA
1421 def GetKeys(self, auth, key_filter=None, return_fields=None):
1422 """Returns an array of structs containing details about keys.
1423 If key_filter is specified and is an array of key identifiers,
1424 or a struct of key attributes, only keys matching the filter
1425 will be returned. If return_fields is specified, only the
1426 specified details will be returned.
1428 Admin may query all keys. Non-admins may only query their own keys.
1432 logger.warning("SLABDRIVER GetKeys EMPTY - DO NOTHING \r\n ")
1435 #TODO DeleteKey 04/07/2012 SA
1436 def DeleteKey(self, auth, key_id):
1438 Non-admins may only delete their own keys.
1439 Returns 1 if successful, faults otherwise.
1443 logger.warning("SLABDRIVER DeleteKey EMPTY - DO NOTHING \r\n ")
1447 #TODO : Check rights to delete person
1448 def DeletePerson(self, auth, person_record):
1449 """ Disable an existing account in senslab LDAP.
1450 Users and techs can only delete themselves. PIs can only
1451 delete themselves and other non-PIs at their sites.
1452 ins can delete anyone.
1453 Returns 1 if successful, faults otherwise.
1457 #Disable user account in senslab LDAP
1458 ret = self.ldap.LdapMarkUserAsDeleted(person_record)
1459 logger.warning("SLABDRIVER DeletePerson %s " %(person_record))
1462 #TODO Check DeleteSlice, check rights 05/07/2012 SA
1463 def DeleteSlice(self, auth, slice_record):
1464 """ Deletes the specified slice.
1465 Senslab : Kill the job associated with the slice if there is one
1466 using DeleteSliceFromNodes.
1467 Updates the slice record in slab db to remove the slice nodes.
1469 Users may only delete slices of which they are members. PIs may
1470 delete any of the slices at their sites, or any slices of which
1471 they are members. Admins may delete any slice.
1472 Returns 1 if successful, faults otherwise.
1476 self.DeleteSliceFromNodes(slice_record)
1477 self.db.update_job(slice_record['hrn'], job_id = -1, nodes = [])
1478 logger.warning("SLABDRIVER DeleteSlice %s "%(slice_record))
1481 #TODO AddPerson 04/07/2012 SA
1482 def AddPerson(self, auth, person_fields=None):
1483 """Adds a new account. Any fields specified in person_fields are used,
1484 otherwise defaults are used.
1485 Accounts are disabled by default. To enable an account,
1487 Returns the new person_id (> 0) if successful, faults otherwise.
1491 logger.warning("SLABDRIVER AddPerson EMPTY - DO NOTHING \r\n ")
1494 #TODO AddPersonToSite 04/07/2012 SA
1495 def AddPersonToSite (self, auth, person_id_or_email, \
1496 site_id_or_login_base=None):
1497 """ Adds the specified person to the specified site. If the person is
1498 already a member of the site, no errors are returned. Does not change
1499 the person's primary site.
1500 Returns 1 if successful, faults otherwise.
1504 logger.warning("SLABDRIVER AddPersonToSite EMPTY - DO NOTHING \r\n ")
1507 #TODO AddRoleToPerson : Not sure if needed in senslab 04/07/2012 SA
1508 def AddRoleToPerson(self, auth, role_id_or_name, person_id_or_email):
1509 """Grants the specified role to the person.
1510 PIs can only grant the tech and user roles to users and techs at their
1511 sites. Admins can grant any role to any user.
1512 Returns 1 if successful, faults otherwise.
1516 logger.warning("SLABDRIVER AddRoleToPerson EMPTY - DO NOTHING \r\n ")
1519 #TODO AddPersonKey 04/07/2012 SA
1520 def AddPersonKey(self, auth, person_id_or_email, key_fields=None):
1521 """Adds a new key to the specified account.
1522 Non-admins can only modify their own keys.
1523 Returns the new key_id (> 0) if successful, faults otherwise.
1527 logger.warning("SLABDRIVER AddPersonKey EMPTY - DO NOTHING \r\n ")
1530 def DeleteLeases(self, leases_id_list, slice_hrn ):
1531 for job_id in leases_id_list:
1532 self.DeleteJobs(job_id, slice_hrn)
1534 logger.debug("SLABDRIVER DeleteLeases leases_id_list %s slice_hrn %s \r\n " %(leases_id_list, slice_hrn))