From: Sandrine Avakian Date: Mon, 10 Dec 2012 12:52:36 +0000 (+0100) Subject: Deleted slice_senslab table (redundancy with reg-researchers relationship X-Git-Tag: sfa-2.1-24~3^2~25 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=9a49858036ce55608fe0284cea3a2861a0d88720;p=sfa.git Deleted slice_senslab table (redundancy with reg-researchers relationship in SFA). Created slab_xp giving information about which slice has been used for whcih experiment. Modified GetSlices, GetLeases, AddLeases as well as slabimporter accordingly. --- diff --git a/sfa/importer/slabimporter.py b/sfa/importer/slabimporter.py index e74fbf1c..97372729 100644 --- a/sfa/importer/slabimporter.py +++ b/sfa/importer/slabimporter.py @@ -4,7 +4,7 @@ from sfa.util.config import Config from sfa.util.xrn import Xrn, get_authority, hrn_to_urn from sfa.senslab.slabdriver import SlabDriver -from sfa.senslab.slabpostgres import SliceSenslab, slab_dbsession +from sfa.senslab.slabpostgres import SenslabXP, slab_dbsession from sfa.trust.certificate import Keypair,convert_public_key from sfa.trust.gid import create_uuid @@ -63,9 +63,9 @@ class SlabImporter: #Create special slice table for senslab - if not slabdriver.db.exists('slice_senslab'): + if not slabdriver.db.exists('slab_xp'): slabdriver.db.createtable() - self.logger.info ("SlabImporter.run: slice_senslab table created ") + self.logger.info ("SlabImporter.run: slab_xp table created ") #retrieve all existing SFA objects all_records = dbsession.query(RegRecord).all() @@ -257,8 +257,7 @@ class SlabImporter: dbsession.commit() - user_record.stale=False - print>>sys.stderr,"SlabImporter: STALE!! PERSON : %s" %user_record + user_record.stale = False except: self.logger.log_exc("SlabImporter: failed to import person %s"%(person) ) @@ -284,11 +283,11 @@ class SlabImporter: #Get it sl_rec = dbsession.query(RegSlice).filter(RegSlice.hrn.match(slice_hrn)).all() - slab_slice = SliceSenslab( slice_hrn = slice_hrn, record_id_slice=sl_rec[0].record_id, record_id_user= user_record.record_id) - print>>sys.stderr, "\r\n \r\n SLAB IMPORTER SLICE IMPORT NOTslice_record %s \r\n slab_slice %s" %(sl_rec,slab_slice) - slab_dbsession.add(slab_slice) - slab_dbsession.commit() - self.logger.info("SlabImporter: imported slice: %s" % slice_record) + #slab_slice = SenslabXP( slice_hrn = slice_hrn, record_id_slice=sl_rec[0].record_id, record_id_user= user_record.record_id) + #print>>sys.stderr, "\r\n \r\n SLAB IMPORTER SLICE IMPORT NOTslice_record %s \r\n slab_slice %s" %(sl_rec,slab_slice) + #slab_dbsession.add(slab_slice) + #slab_dbsession.commit() + #self.logger.info("SlabImporter: imported slice: %s" % slice_record) self.update_just_added_records_dict ( slice_record ) except: @@ -328,10 +327,10 @@ class SlabImporter: self.logger.warning("stale not found with %s"%record) if stale: self.logger.info("SlabImporter: deleting stale record: %s" % record) - if record.type == 'user': - rec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = record.record_id).first() - slab_dbsession.delete(rec) - slab_dbsession.commit() + #if record.type == 'user': + #rec = slab_dbsession.query(SenslabXP).filter_by(record_id_user = record.record_id).first() + #slab_dbsession.delete(rec) + #slab_dbsession.commit() dbsession.delete(record) dbsession.commit() diff --git a/sfa/senslab/slabaggregate.py b/sfa/senslab/slabaggregate.py index 337f8889..a464eb23 100644 --- a/sfa/senslab/slabaggregate.py +++ b/sfa/senslab/slabaggregate.py @@ -1,5 +1,5 @@ import time -from sfa.util.xrn import hrn_to_urn, urn_to_hrn +from sfa.util.xrn import hrn_to_urn, urn_to_hrn, get_authority from sfa.rspecs.rspec import RSpec from sfa.rspecs.elements.versions.slabv1Node import SlabPosition @@ -83,7 +83,7 @@ class SlabAggregate: sliver_xrn.set_authority(self.driver.hrn) #node_id = self.driver.root_auth + '.' + node_id sliver = Sliver({'sliver_id':sliver_xrn.urn, - 'name': sfa_slice['slice_hrn'], + 'name': sfa_slice['hrn'], 'type': 'slab-node', 'tags': []}) @@ -92,10 +92,13 @@ class SlabAggregate: #Add default sliver attribute : #connection information for senslab - tmp = sfa_slice['slice_hrn'].split('.') - ldap_username = tmp[1].split('_')[0] - vmaddr = 'ssh ' + ldap_username + '@grenoble.senslab.info' - slivers['default_sliver'] = {'vm': vmaddr , 'login': ldap_username} + if get_authority (sfa_slice['hrn']) == self.driver.root_auth: + tmp = sfa_slice['hrn'].split('.') + ldap_username = tmp[1].split('_')[0] + vmaddr = 'ssh ' + ldap_username + '@grenoble.senslab.info' + slivers['default_sliver'] = {'vm': vmaddr , 'login': ldap_username} + + #TODO get_slice_and_slivers Find the login of the external user logger.debug("SLABAGGREGATE api get_slice_and_slivers slivers %s "\ %(slivers)) @@ -331,8 +334,8 @@ class SlabAggregate: #rspec.xml.set('expires', datetime_to_epoch(slice['expires'])) # add sliver defaults #nodes, links = self.get_nodes(slice, slivers) - logger.debug("\r\n \r\n SlabAggregate \tget_rspec ******* slice_xrn %s \r\n \r\n"\ - %(slice_xrn)) + logger.debug("\r\n \r\n SlabAggregate \tget_rspec ******* slice_xrn %s slices %s\r\n \r\n"\ + %(slice_xrn, slices)) try: lease_option = options['list_leases'] @@ -357,7 +360,7 @@ class SlabAggregate: #for one_slice in slices : - ldap_username = slices[0]['slice_hrn'] + ldap_username = slices[0]['hrn'] tmp = ldap_username.split('.') ldap_username = tmp[1].split('_')[0] diff --git a/sfa/senslab/slabdriver.py b/sfa/senslab/slabdriver.py index 902c3993..205dbda7 100644 --- a/sfa/senslab/slabdriver.py +++ b/sfa/senslab/slabdriver.py @@ -7,7 +7,7 @@ from sfa.util.sfalogging import logger from sfa.storage.alchemy import dbsession from sfa.storage.model import RegRecord, RegUser, RegSlice - +from sqlalchemy.orm import joinedload from sfa.trust.credential import Credential @@ -26,8 +26,8 @@ from sfa.util.xrn import hrn_to_urn, get_authority from sfa.senslab.OARrestapi import OARrestapi from sfa.senslab.LDAPapi import LDAPapi -from sfa.senslab.slabpostgres import SlabDB, slab_dbsession, SliceSenslab, \ - FederatedToSenslab +from sfa.senslab.slabpostgres import SlabDB, slab_dbsession, SenslabXP + from sfa.senslab.slabaggregate import SlabAggregate, slab_xrn_to_hostname, \ slab_xrn_object @@ -208,11 +208,7 @@ class SlabDriver(Driver): rspec.version.get_slice_attributes() logger.debug("SLABDRIVER.PY create_sliver slice %s " %(sfa_slice)) - - - - # add/remove slice from nodes requested_slivers = [node.get('component_id') \ @@ -339,16 +335,16 @@ class SlabDriver(Driver): dbsession.commit() #Update the senslab table with the new slice - slab_slice = SliceSenslab( slice_hrn = slice_record['slice_hrn'], \ - record_id_slice = sfa_record.record_id , \ - record_id_user = slice_record['record_id_user'], \ - peer_authority = slice_record['peer_authority']) + #slab_slice = SenslabXP( slice_hrn = slice_record['slice_hrn'], \ + #record_id_slice = sfa_record.record_id , \ + #record_id_user = slice_record['record_id_user'], \ + #peer_authority = slice_record['peer_authority']) - logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s \ - slab_slice %s sfa_record %s" \ - %(slice_record,slab_slice, sfa_record)) - slab_dbsession.add(slab_slice) - slab_dbsession.commit() + #logger.debug("SLABDRIVER.PY \tAddSlice slice_record %s \ + #slab_slice %s sfa_record %s" \ + #%(slice_record,slab_slice, sfa_record)) + #slab_dbsession.add(slab_slice) + #slab_dbsession.commit() return # first 2 args are None in case of resource discovery @@ -376,8 +372,8 @@ class SlabDriver(Driver): #panos: passing user-defined options aggregate = SlabAggregate(self) - origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn() - options.update({'origin_hrn':origin_hrn}) + #origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn() + #options.update({'origin_hrn':origin_hrn}) rspec = aggregate.get_rspec(slice_xrn=slice_urn, \ version=rspec_version, options=options) @@ -401,7 +397,7 @@ class SlabDriver(Driver): slices = self.GetSlices() logger.debug("SLABDRIVER.PY \tlist_slices hrn %s \r\n \r\n" %(slices)) - slice_hrns = [slab_slice['slice_hrn'] for slab_slice in slices] + slice_hrns = [slab_slice['hrn'] for slab_slice in slices] slice_urns = [hrn_to_urn(slice_hrn, 'slice') \ for slice_hrn in slice_hrns] @@ -829,30 +825,35 @@ class SlabDriver(Driver): login = None #Get list of slices based on the slice hrn if slice_filter_type == 'slice_hrn': - - login = slice_filter.split(".")[1].split("_")[0] + + if get_authority(slice_filter) == self.root_auth: + login = slice_filter.split(".")[1].split("_")[0] #DO NOT USE RegSlice - reg_researchers to get the hrn #of the user otherwise will mess up the RegRecord in #Resolve, don't know why - SA 08/08/2012 - #Only one entry for one user = one slice in slice_senslab table - slicerec = slab_dbsession.query(SliceSenslab).filter_by(slice_hrn = slice_filter).first() + #Only one entry for one user = one slice in slab_xp table + slicerec = dbsession.query(RegRecord).filter_by(hrn = slice_filter).first() + #slicerec = slab_dbsession.query(SenslabXP).filter_by(slice_hrn = slice_filter).first() if slicerec is None: return login, None #Get slice based on user id - if slice_filter_type == 'record_id_user': - slicerec = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = slice_filter).first() + if slice_filter_type == 'record_id_user': + slicerec = dbsession.query(RegRecord).filter_by(record_id = slice_filter).first() + #slicerec = slab_dbsession.query(SenslabXP).filter_by(record_id_user = slice_filter).first() if slicerec: - fixed_slicerec_dict = slicerec.dump_sqlalchemyobj_to_dict() + fixed_slicerec_dict = slicerec.__dict__ #At this point if the there is no login it means #record_id_user filter has been used for filtering if login is None : - login = fixed_slicerec_dict['slice_hrn'].split(".")[1].split("_")[0] + #If theslice record is from senslab + if fixed_slicerec_dict['peer_authority'] is None: + login = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0] return login, fixed_slicerec_dict @@ -886,8 +887,8 @@ class SlabDriver(Driver): #Update lease dict with the slice record if fixed_slicerec_dict: slicerec_dict.update(fixed_slicerec_dict) - slicerec_dict.update({'hrn':\ - str(fixed_slicerec_dict['slice_hrn'])}) + #slicerec_dict.update({'hrn':\ + #str(fixed_slicerec_dict['slice_hrn'])}) return_slicerec_dictlist.append(slicerec_dict) @@ -906,11 +907,12 @@ class SlabDriver(Driver): else: #Get all slices from the senslab sfa database , - #put them in dict format - query_slice_list = slab_dbsession.query(SliceSenslab).all() + #put them in dict format + query_slice_list = dbsession.query(RegRecord).filter_by(type='slice').all() + #query_slice_list = slab_dbsession.query(SenslabXP).all() return_slicerec_dictlist = [] for record in query_slice_list: - return_slicerec_dictlist.append(record.dump_sqlalchemyobj_to_dict()) + return_slicerec_dictlist.append(record.__dict__) #Get all the jobs reserved nodes leases_list = self.GetReservedNodes() @@ -918,7 +920,11 @@ class SlabDriver(Driver): for fixed_slicerec_dict in return_slicerec_dictlist: slicerec_dict = {} - owner = fixed_slicerec_dict['slice_hrn'].split(".")[1].split("_")[0] + #Check if the slice belongs to a senslab user + if fixed_slicerec_dict['peer_authority'] is None: + owner = fixed_slicerec_dict['hrn'].split(".")[1].split("_")[0] + else: + owner = None for lease in leases_list: if owner == lease['user']: slicerec_dict['oar_job_id'] = lease['lease_id'] @@ -932,8 +938,8 @@ class SlabDriver(Driver): slicerec_dict.update({'node_ids':lease['reserved_nodes']}) slicerec_dict.update({'list_node_ids':{'hostname':reserved_list}}) slicerec_dict.update(fixed_slicerec_dict) - slicerec_dict.update({'hrn':\ - str(fixed_slicerec_dict['slice_hrn'])}) + #slicerec_dict.update({'hrn':\ + #str(fixed_slicerec_dict['slice_hrn'])}) #return_slicerec_dictlist.append(slicerec_dict) fixed_slicerec_dict.update(slicerec_dict) @@ -1056,6 +1062,7 @@ class SlabDriver(Driver): lease_dict['slice_user'] = slice_user lease_dict['grain'] = self.GetLeaseGranularity() lease_dict['time_format'] = self.time_format + def __create_job_structure_request_for_OAR(lease_dict): """ Creates the structure needed for a correct POST on OAR. @@ -1157,7 +1164,7 @@ class SlabDriver(Driver): except KeyError: logger.log_exc("SLABDRIVER \tLaunchExperimentOnOAR \ Impossible to create job %s " %(answer)) - return + return None def __configure_experiment(jobid, added_nodes): @@ -1198,7 +1205,8 @@ class SlabDriver(Driver): __configure_experiment(jobid, added_nodes) __launch_senslab_experiment(jobid) - return + return jobid + def AddLeases(self, hostname_list, slice_record, \ lease_start_time, lease_duration): @@ -1209,9 +1217,15 @@ class SlabDriver(Driver): tmp = slice_record['reg-researchers'][0].split(".") username = tmp[(len(tmp)-1)] - self.LaunchExperimentOnOAR(hostname_list, slice_record['slice_hrn'], \ + job_id = self.LaunchExperimentOnOAR(hostname_list, slice_record['hrn'], \ lease_start_time, lease_duration, username) start_time = datetime.fromtimestamp(int(lease_start_time)).strftime(self.time_format) + end_time = lease_start_time + lease_duration + slab_ex_row = SenslabXP(slice_record['hrn'], job_id, end_time) + logger.debug("SLABDRIVER \r\n \r\n \t slab_ex_row %s" %(slab_ex_row)) + slab_dbsession.add(slab_ex_row) + slab_dbsession.commit() + logger.debug("SLABDRIVER \t AddLeases hostname_list start_time %s " %(start_time)) return @@ -1232,6 +1246,23 @@ class SlabDriver(Driver): grain = 60 return grain + def update_jobs_in_slabdb(self, job_oar_list): + #Get all the entries in slab_xp table + jobs_psql_query = slab_dbsession.query(SenslabXP).all() + jobs_psql = [ row.job_id for row in jobs_psql_query ] + jobs_psql = set(jobs_psql) + kept_jobs = set(job_oar_list).intersection(jobs_psql) + + deleted_jobs = set(jobs_psql).difference(kept_jobs) + deleted_jobs = list(deleted_jobs) + + slab_dbsession.query(SenslabXP).filter(SenslabXP.job_id.in_(deleted_jobs)).delete(synchronize_session='fetch') + slab_dbsession.commit() + + return + + + def GetLeases(self, lease_filter_dict=None): @@ -1243,27 +1274,55 @@ class SlabDriver(Driver): #Create user dict first to avoid looking several times for #the same user in LDAP SA 27/07/12 resa_user_dict = {} + job_oar_list = [] for resa in unfiltered_reservation_list: logger.debug("SLABDRIVER \tGetLeases USER %s"\ - %(resa['user'])) + %(resa['user'])) + #Cosntruct list of jobs (runing, waiting..) in oar + job_oar_list.append(resa['lease_id']) if resa['user'] not in resa_user_dict: logger.debug("SLABDRIVER \tGetLeases userNOTIN ") ldap_info = self.ldap.LdapSearch('(uid='+resa['user']+')') if ldap_info: ldap_info = ldap_info[0][1] - user = dbsession.query(RegUser).filter_by(email = \ - ldap_info['mail'][0]).first() + #Get the backref :relationship table reg-researchers + user = dbsession.query(RegUser).options(joinedload('reg_slices_as_researcher')).filter_by(email = \ + ldap_info['mail'][0]) + if user: + user = user.first() + user = user.__dict__ + slice_info = user['reg_slices_as_researcher'][0].__dict__ #Separated in case user not in database : #record_id not defined SA 17/07//12 - query_slice_info = slab_dbsession.query(SliceSenslab).filter_by(record_id_user = user.record_id) - if query_slice_info: - slice_info = query_slice_info.first() - else: - slice_info = None + + #query_slice_info = slab_dbsession.query(SenslabXP).filter_by(record_id_user = user.record_id) + #if query_slice_info: + #slice_info = query_slice_info.first() + #else: + #slice_info = None resa_user_dict[resa['user']] = {} resa_user_dict[resa['user']]['ldap_info'] = user resa_user_dict[resa['user']]['slice_info'] = slice_info + + resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info']['hrn'] + resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice') + #Put the slice_urn + #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice') + resa['component_id_list'] = [] + #Transform the hostnames into urns (component ids) + for node in resa['reserved_nodes']: + #resa['component_id_list'].append(hostname_to_urn(self.hrn, \ + #self.root_auth, node['hostname'])) + slab_xrn = slab_xrn_object(self.root_auth, node) + resa['component_id_list'].append(slab_xrn.urn) + + if lease_filter_dict: + if lease_filter_dict['name'] == resa['slice_hrn']: + reservation_list.append(resa) + + if lease_filter_dict is None: + reservation_list = unfiltered_reservation_list #else: #del unfiltered_reservation_list[unfiltered_reservation_list.index(resa)] @@ -1271,33 +1330,33 @@ class SlabDriver(Driver): logger.debug("SLABDRIVER \tGetLeases resa_user_dict %s"\ %(resa_user_dict)) - for resa in unfiltered_reservation_list: + #for resa in unfiltered_reservation_list: - #Put the slice_urn - if resa['user'] in resa_user_dict: - resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info'].slice_hrn - resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice') - #Put the slice_urn - #resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice') - resa['component_id_list'] = [] - #Transform the hostnames into urns (component ids) - for node in resa['reserved_nodes']: - #resa['component_id_list'].append(hostname_to_urn(self.hrn, \ - #self.root_auth, node['hostname'])) - slab_xrn = slab_xrn_object(self.root_auth, node) - resa['component_id_list'].append(slab_xrn.urn) - - #Filter the reservation list if necessary - #Returns all the leases associated with a given slice - if lease_filter_dict: - logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\ - %(lease_filter_dict)) - for resa in unfiltered_reservation_list: - if lease_filter_dict['name'] == resa['slice_hrn']: - reservation_list.append(resa) - else: - reservation_list = unfiltered_reservation_list + ##Put the slice_urn + #if resa['user'] in resa_user_dict: + #resa['slice_hrn'] = resa_user_dict[resa['user']]['slice_info']['hrn'] + #resa['slice_id'] = hrn_to_urn(resa['slice_hrn'], 'slice') + ##Put the slice_urn + ##resa['slice_id'] = hrn_to_urn(slice_info.slice_hrn, 'slice') + #resa['component_id_list'] = [] + ##Transform the hostnames into urns (component ids) + #for node in resa['reserved_nodes']: + ##resa['component_id_list'].append(hostname_to_urn(self.hrn, \ + ##self.root_auth, node['hostname'])) + #slab_xrn = slab_xrn_object(self.root_auth, node) + #resa['component_id_list'].append(slab_xrn.urn) + + ##Filter the reservation list if necessary + ##Returns all the leases associated with a given slice + #if lease_filter_dict: + #logger.debug("SLABDRIVER \tGetLeases lease_filter_dict %s"\ + #%(lease_filter_dict)) + #for resa in unfiltered_reservation_list: + #if lease_filter_dict['name'] == resa['slice_hrn']: + #reservation_list.append(resa) + #else: + #reservation_list = unfiltered_reservation_list logger.debug(" SLABDRIVER.PY \tGetLeases reservation_list %s"\ %(reservation_list)) @@ -1539,9 +1598,9 @@ class SlabDriver(Driver): FROM PLC API DOC """ - new_row = FederatedToSenslab(slab_hrn, federated_hrn) - slab_dbsession.add(new_row) - slab_dbsession.commit() + #new_row = FederatedToSenslab(slab_hrn, federated_hrn) + #slab_dbsession.add(new_row) + #slab_dbsession.commit() logger.debug("SLABDRIVER UpdatePerson EMPTY - DO NOTHING \r\n ") return diff --git a/sfa/senslab/slabpostgres.py b/sfa/senslab/slabpostgres.py index b0c90184..ca217760 100644 --- a/sfa/senslab/slabpostgres.py +++ b/sfa/senslab/slabpostgres.py @@ -20,97 +20,51 @@ CASCADE ON UPDATE CASCADE','oar_job_id':'integer DEFAULT -1', \ 'record_id_slice':'integer', 'slice_hrn':'text NOT NULL'} #Dict with all the specific senslab tables -tablenames_dict = {'slice_senslab': slice_table} +tablenames_dict = {'slab_xp': slice_table} SlabBase = declarative_base() -class FederatedToSenslab( SlabBase): - - __tablename__ = 'identities' - slab_hrn = Column(String, primary_key=True) - aka_hrn = Column(String) - email = Column(String) - - def __init__ (self, slab_hrn = None, aka_hrn = None, email= None): - self.slab_hrn = slab_hrn - self.aka_hrn = aka_hrn - self.email = email - - def __repr__(self): - """Prints the SQLAlchemy record to the format defined - by the function. - """ - result = "< slab_hrn =%s, aka_hrn=%s , email=%s"% (self.slab_hrn, self.aka_hrn, self.email) - result += ">" - return result - - def dump_sqlalchemyobj_to_dict(self): - """Transforms a SQLalchemy record object to a python dictionary. - Returns the dictionary. - """ - - dump_dict = {'slab_hrn':self.slab_hrn, - 'aka_hrn':self.aka_hrn, - 'email' : self.email, } - return dump_dict - - - + -class SliceSenslab (SlabBase): +class SenslabXP (SlabBase): """ SQL alchemy class to manipulate slice_senslab table in slab_sfa database. """ - __tablename__ = 'slice_senslab' - #record_id_user = Column(Integer, primary_key=True) + __tablename__ = 'slab_xp' + + + slice_hrn = Column(String) + job_id = Column(Integer, primary_key = True) + end_time = Column(Integer, nullable = False) - slice_hrn = Column(String, primary_key=True) - peer_authority = Column(String, nullable = True) - record_id_slice = Column(Integer) - record_id_user = Column(Integer) #oar_job_id = Column( Integer,default = -1) #node_list = Column(postgresql.ARRAY(String), nullable =True) - def __init__ (self, slice_hrn =None, record_id_slice=None, \ - record_id_user= None,peer_authority=None): + def __init__ (self, slice_hrn =None, job_id=None, end_time=None): """ Defines a row of the slice_senslab table """ - if record_id_slice: - self.record_id_slice = record_id_slice if slice_hrn: self.slice_hrn = slice_hrn - if record_id_user: - self.record_id_user = record_id_user - if peer_authority: - self.peer_authority = peer_authority + if job_id : + self.job_id = job_id + if end_time: + self.end_time = end_time def __repr__(self): """Prints the SQLAlchemy record to the format defined by the function. """ - result = "