def create_arc_job(job, configuration, logger): """Analog to create_job_script for ARC jobs: Creates symLinks for receiving result files, translates job dict to ARC xrsl, and stores resulting job script (xrsl + sh script) for submitting. We do _not_ create a separate job_dict with copies and SESSIONID inside, as opposed to create_job_script, all we need is the link from webserver_home / sessionID into the user's home directory ("job_output/job['JOB_ID']" is added to the result upload URLs in the translation). Returns message (ARC job ID if no error) and sessionid (None if error) """ if not configuration.arc_clusters: return (None, "No ARC support!") if not job["JOBTYPE"] == "arc": return (None, "Error. This is not an ARC job") # Deep copy job for local changes job_dict = deepcopy(job) # Finally expand reserved job variables like +JOBID+ and +JOBNAME+ job_dict = expand_variables(job_dict) # ... no more changes to job_dict from here on client_id = str(job_dict["USER_CERT"]) # we do not want to see empty jobs here. Test as done in create_job_script. if client_id == configuration.empty_job_name: return (None, "Error. empty job for ARC?") # generate random session ID: sessionid = hexlify(open("/dev/urandom").read(32)) logger.debug("session ID (for creating links): %s" % sessionid) client_dir = client_id_dir(client_id) # make symbolic links inside webserver_home: # # we need: link to owner's dir. to receive results, # job mRSL inside sessid_to_mrsl_link_home linklist = [ (configuration.user_home + client_dir, configuration.webserver_home + sessionid), ( configuration.mrsl_files_dir + client_dir + "/" + str(job_dict["JOB_ID"]) + ".mRSL", configuration.sessid_to_mrsl_link_home + sessionid + ".mRSL", ), ] for (dest, loc) in linklist: make_symlink(dest, loc, logger) # the translation generates an xRSL object which specifies to execute # a shell script with script_name. If sessionid != None, results will # be uploaded to sid_redirect/sessionid/job_output/job_id try: (xrsl, script, script_name) = mrsltoxrsl.translate(job_dict, sessionid) logger.debug("translated to xRSL: %s" % xrsl) logger.debug("script:\n %s" % script) except Exception, err: # error during translation, pass a message logger.error("Error during xRSL translation: %s" % err.__str__()) return (None, err.__str__())
def create_job_script(unique_resource_name, exe, job, resource_config, localjobname, configuration, logger): """Helper to create actual jobs for handout to a resource. Returns tuple with job dict on success and None otherwise. The job dict includes random generated sessionid and a I/O session id. """ job_dict = {"": ""} sessionid = hexlify(open("/dev/urandom").read(32)) iosessionid = hexlify(open("/dev/urandom").read(32)) helper_dict_filename = os.path.join( configuration.resource_home, unique_resource_name, "empty_job_helper_dict.%s" % exe ) # Deep copy job for local changes job_dict = deepcopy(job) job_dict["SESSIONID"] = sessionid job_dict["IOSESSIONID"] = iosessionid # Create ssh rsa keys and known_hosts for job mount mount_private_key = "" mount_public_key = "" mount_known_hosts = "" if job_dict.get("MOUNT", []) != []: # Generate public/private key pair for sshfs (mount_private_key, mount_public_key) = generate_ssh_rsa_key_pair() # Generate known_hosts if not os.path.exists(configuration.user_sftp_key_pub): msg = "job generation failed:" msg = "%s user_sftp_key_pub: '%s' -> File _NOT_ found" % (msg, configuration.user_sftp_key_pub) print msg logger.error(msg) return (None, msg) sftp_address = configuration.user_sftp_show_address sftp_addresses = socket.gethostbyname_ex(sftp_address or socket.getfqdn()) sftp_port = configuration.user_sftp_show_port mount_known_hosts = "%s,[%s]:%s" % (sftp_addresses[0], sftp_addresses[0], sftp_port) for list_idx in xrange(1, len(sftp_addresses)): for sftp_address in sftp_addresses[list_idx]: mount_known_hosts += ",%s,[%s]:%s" % (sftp_address, sftp_address, sftp_port) fd = open(configuration.user_sftp_key_pub, "r") mount_known_hosts = "%s %s" % (mount_known_hosts, fd.read()) fd.close() job_dict["MOUNTSSHPUBLICKEY"] = mount_public_key job_dict["MOUNTSSHPRIVATEKEY"] = mount_private_key job_dict["MOUNTSSHKNOWNHOSTS"] = mount_known_hosts if not job_dict.has_key("MAXPRICE"): job_dict["MAXPRICE"] = "0" # Finally expand reserved job variables like +JOBID+ and +JOBNAME+ job_dict = expand_variables(job_dict) # ... no more changes to job_dict from here on client_id = str(job_dict["USER_CERT"]) client_dir = client_id_dir(client_id) # if not job: if client_id == configuration.empty_job_name: # create link to empty job linkdest_empty_job = helper_dict_filename linkloc_empty_job = configuration.sessid_to_mrsl_link_home + sessionid + ".mRSL" make_symlink(linkdest_empty_job, linkloc_empty_job, logger) else: # link sessionid to mrsl file linkdest1 = configuration.mrsl_files_dir + client_dir + "/" + str(job_dict["JOB_ID"]) + ".mRSL" linkloc1 = configuration.sessid_to_mrsl_link_home + sessionid + ".mRSL" make_symlink(linkdest1, linkloc1, logger) # link sessionid to job owners home directory linkdest2 = configuration.user_home + client_dir linkloc2 = configuration.webserver_home + sessionid make_symlink(linkdest2, linkloc2, logger) # link iosessionid to job owners home directory linkdest3 = configuration.user_home + client_dir linkloc3 = configuration.webserver_home + iosessionid make_symlink(linkdest3, linkloc3, logger) # link sessionid to .job file linkdest4 = configuration.mig_system_files + str(job_dict["JOB_ID"]) + ".job" linkloc4 = configuration.webserver_home + sessionid + ".job" make_symlink(linkdest4, linkloc4, logger) # link sessionid to .getupdatefiles file linkdest5 = configuration.mig_system_files + str(job_dict["JOB_ID"]) + ".getupdatefiles" linkloc5 = configuration.webserver_home + sessionid + ".getupdatefiles" make_symlink(linkdest5, linkloc5, logger) # link sessionid to .sendoutputfiles file linkdest4 = configuration.mig_system_files + str(job_dict["JOB_ID"]) + ".sendoutputfiles" linkloc4 = configuration.webserver_home + sessionid + ".sendoutputfiles" make_symlink(linkdest4, linkloc4, logger) # link sessionid to .sendupdatefiles file linkdest5 = configuration.mig_system_files + str(job_dict["JOB_ID"]) + ".sendupdatefiles" linkloc5 = configuration.webserver_home + sessionid + ".sendupdatefiles" make_symlink(linkdest5, linkloc5, logger) path_without_extension = os.path.join(configuration.resource_home, unique_resource_name, localjobname) gen_res = gen_job_script( job_dict, resource_config, configuration, localjobname, path_without_extension, client_dir, exe, logger ) if not gen_res: msg = "job scripts were not generated. Perhaps you have specified " + "an invalid SCRIPTLANGUAGE ? " print msg logger.error(msg) return (None, msg) inputfiles_path = path_without_extension + ".getinputfiles" # hack to ensure that a resource has a sandbox keyword if resource_config.get("SANDBOX", False): # Move file to webserver_home for download as we can't push it to # sandboxes try: # RA TODO: change download filename to something that # includes sessionid webserver_path = os.path.join(configuration.webserver_home, localjobname + ".getinputfiles") os.rename(inputfiles_path, webserver_path) # ########## ATTENTION HACK TO MAKE JVM SANDBOXES WORK ############ # This should be changed to use the (to be developed) RE pre/post # processing framework. For now the user must have a jvm dir in his # home dir where the classfiles is located this should be changed # so that the execution homepath can be specified in the mRSL # jobfile # Martin Rehr 08/09/06 # If this is a oneclick job link the users jvm dir to # webserver_home/sandboxkey.oneclick # This is done because the client applet uses the # codebase from which it is originaly loaded # Therefore the codebase must be dynamicaly changed # for every job if resource_config.has_key("PLATFORM") and resource_config["PLATFORM"] == "ONE-CLICK": # A two step link is made. # First sandboxkey.oneclick is made to point to # sessiondid.jvm # Second sessionid.jvm is set to point to # USER_HOME/jvm # This is done for security and easy cleanup, # sessionid.jvm is cleaned up # by the server upon job finish/timeout and # thereby leaving no open entryes to the users # jvm dir. linkintermediate = configuration.webserver_home + sessionid + ".jvm" if client_dir == configuration.empty_job_name: linkdest = os.path.abspath(configuration.javabin_home) else: linkdest = configuration.user_home + client_dir + os.sep + "jvm" # Make link sessionid.jvm -> USER_HOME/jvm make_symlink(linkdest, linkintermediate, logger) linkloc = configuration.webserver_home + resource_config["SANDBOXKEY"] + ".oneclick" # Remove previous symlink # This must be done in a try/catch as the symlink, # may be a dead link and 'if os.path.exists(linkloc):' # will then return false, even though the link exists. try: os.remove(linkloc) except: pass # Make link sandboxkey.oneclick -> sessionid.jvm make_symlink(linkintermediate, linkloc, logger) except Exception, err: # ######### End JVM SANDBOX HACK ########### msg = "File '%s' was not copied to the webserver home." % inputfiles_path print "\nERROR: " + str(err) logger.error(msg) return (None, msg) return (job_dict, "OK")
def create_arc_job( job, configuration, logger, ): """Analog to create_job_script for ARC jobs: Creates symLinks for receiving result files, translates job dict to ARC xrsl, and stores resulting job script (xrsl + sh script) for submitting. We do _not_ create a separate job_dict with copies and SESSIONID inside, as opposed to create_job_script, all we need is the link from webserver_home / sessionID into the user's home directory ("job_output/job['JOB_ID']" is added to the result upload URLs in the translation). Returns message (ARC job ID if no error) and sessionid (None if error) """ if not configuration.arc_clusters: return (None, 'No ARC support!') if not job['JOBTYPE'] == 'arc': return (None, 'Error. This is not an ARC job') # Deep copy job for local changes job_dict = deepcopy(job) # Finally expand reserved job variables like +JOBID+ and +JOBNAME+ job_dict = expand_variables(job_dict) # ... no more changes to job_dict from here on client_id = str(job_dict['USER_CERT']) # we do not want to see empty jobs here. Test as done in create_job_script. if client_id == configuration.empty_job_name: return (None, 'Error. empty job for ARC?') # generate random session ID: sessionid = hexlify(open('/dev/urandom').read(session_id_bytes)) logger.debug('session ID (for creating links): %s' % sessionid) client_dir = client_id_dir(client_id) # make symbolic links inside webserver_home: # # we need: link to owner's dir. to receive results, # job mRSL inside sessid_to_mrsl_link_home linklist = [(configuration.user_home + client_dir, configuration.webserver_home + sessionid), (configuration.mrsl_files_dir + client_dir + '/' + str(job_dict['JOB_ID']) + '.mRSL', configuration.sessid_to_mrsl_link_home + sessionid + '.mRSL') ] for (dest, loc) in linklist: make_symlink(dest, loc, logger) # the translation generates an xRSL object which specifies to execute # a shell script with script_name. If sessionid != None, results will # be uploaded to sid_redirect/sessionid/job_output/job_id try: (xrsl, script, script_name) = mrsltoxrsl.translate(job_dict, sessionid) logger.debug('translated to xRSL: %s' % xrsl) logger.debug('script:\n %s' % script) except Exception, err: # error during translation, pass a message logger.error('Error during xRSL translation: %s' % err.__str__()) return (None, err.__str__())
def create_job_script( unique_resource_name, exe, job, resource_config, localjobname, configuration, logger, ): """Helper to create actual jobs for handout to a resource. Returns tuple with job dict on success and None otherwise. The job dict includes random generated sessionid and a I/O session id. """ job_dict = {'': ''} # TODO: hexlify is an awfully space wasting URL-safe encoding. # We should just use something like the proposed secure method from # http://stackoverflow.com/a/23728630/2213647 sessionid = hexlify(open('/dev/urandom').read(session_id_bytes)) iosessionid = hexlify(open('/dev/urandom').read(session_id_bytes)) helper_dict_filename = os.path.join(configuration.resource_home, unique_resource_name, 'empty_job_helper_dict.%s' % exe) # Deep copy job for local changes job_dict = deepcopy(job) # Bump requested values to any resource specs requested in MAXFILL job_maxfill = job_dict.get('MAXFILL', []) if keyword_all in job_maxfill: job_maxfill = maxfill_fields for name in maxfill_fields: if name in job_maxfill: job_dict[name] = resource_config[name] job_dict['SESSIONID'] = sessionid job_dict['IOSESSIONID'] = iosessionid # Create ssh rsa keys and known_hosts for job mount mount_private_key = "" mount_public_key = "" mount_known_hosts = "" if job_dict.get('MOUNT', []) != []: # Generate public/private key pair for sshfs (mount_private_key, mount_public_key) = generate_ssh_rsa_key_pair() # Generate known_hosts if not os.path.exists(configuration.user_sftp_key_pub): msg = "job generation failed:" msg = "%s user_sftp_key_pub: '%s' -> File NOT found" % \ (msg, configuration.user_sftp_key_pub) print msg logger.error(msg) return (None, msg) # Use best available sftp implementation - configuration picks it sftp_address = configuration.user_sftp_show_address sftp_port = configuration.user_sftp_show_port sftp_addresses = socket.gethostbyname_ex(sftp_address or socket.getfqdn()) mount_known_hosts = "%s,[%s]:%s" % (sftp_addresses[0], sftp_addresses[0], sftp_port) for list_idx in xrange(1, len(sftp_addresses)): for sftp_address in sftp_addresses[list_idx]: mount_known_hosts += ",%s,[%s]:%s" % (sftp_address, sftp_address, sftp_port) fd = open(configuration.user_sftp_key_pub, 'r') mount_known_hosts = "%s %s" % (mount_known_hosts, fd.read()) fd.close() job_dict['MOUNTSSHPUBLICKEY'] = mount_public_key job_dict['MOUNTSSHPRIVATEKEY'] = mount_private_key job_dict['MOUNTSSHKNOWNHOSTS'] = mount_known_hosts if not job_dict.has_key('MAXPRICE'): job_dict['MAXPRICE'] = '0' # Finally expand reserved job variables like +JOBID+ and +JOBNAME+ job_dict = expand_variables(job_dict) # ... no more changes to job_dict from here on client_id = str(job_dict['USER_CERT']) client_dir = client_id_dir(client_id) # if not job: if client_id == configuration.empty_job_name: # create link to empty job linkdest_empty_job = helper_dict_filename linkloc_empty_job = configuration.sessid_to_mrsl_link_home + \ sessionid + '.mRSL' make_symlink(linkdest_empty_job, linkloc_empty_job, logger) else: # link sessionid to mrsl file linkdest1 = configuration.mrsl_files_dir + client_dir + '/' + \ str(job_dict['JOB_ID']) + '.mRSL' linkloc1 = configuration.sessid_to_mrsl_link_home + sessionid + '.mRSL' make_symlink(linkdest1, linkloc1, logger) # link sessionid to job owners home directory linkdest2 = configuration.user_home + client_dir linkloc2 = configuration.webserver_home + sessionid make_symlink(linkdest2, linkloc2, logger) # link iosessionid to job owners home directory linkdest3 = configuration.user_home + client_dir linkloc3 = configuration.webserver_home + iosessionid make_symlink(linkdest3, linkloc3, logger) # link sessionid to .job file linkdest4 = configuration.mig_system_files + str(job_dict['JOB_ID']) + \ '.job' linkloc4 = configuration.webserver_home + sessionid + '.job' make_symlink(linkdest4, linkloc4, logger) # link sessionid to .getupdatefiles file linkdest5 = configuration.mig_system_files + str(job_dict['JOB_ID']) + \ '.getupdatefiles' linkloc5 = configuration.webserver_home + sessionid + \ '.getupdatefiles' make_symlink(linkdest5, linkloc5, logger) # link sessionid to .sendoutputfiles file linkdest4 = configuration.mig_system_files + str(job_dict['JOB_ID']) + \ '.sendoutputfiles' linkloc4 = configuration.webserver_home + sessionid + \ '.sendoutputfiles' make_symlink(linkdest4, linkloc4, logger) # link sessionid to .sendupdatefiles file linkdest5 = configuration.mig_system_files + str(job_dict['JOB_ID']) + \ '.sendupdatefiles' linkloc5 = configuration.webserver_home + sessionid + \ '.sendupdatefiles' make_symlink(linkdest5, linkloc5, logger) path_without_extension = os.path.join(configuration.resource_home, unique_resource_name, localjobname) gen_res = gen_job_script( job_dict, resource_config, configuration, localjobname, path_without_extension, client_dir, exe, logger, ) if not gen_res: msg = \ 'job scripts were not generated. Perhaps you have specified ' + \ 'an invalid SCRIPTLANGUAGE ? ' print msg logger.error(msg) return (None, msg) inputfiles_path = path_without_extension + '.getinputfiles' # hack to ensure that a resource has a sandbox keyword if resource_config.get('SANDBOX', False): # Move file to webserver_home for download as we can't push it to # sandboxes try: # RA TODO: change download filename to something that # includes sessionid webserver_path = os.path.join(configuration.webserver_home, localjobname + '.getinputfiles') os.rename(inputfiles_path, webserver_path) # ########## ATTENTION HACK TO MAKE JVM SANDBOXES WORK ############ # This should be changed to use the (to be developed) RE pre/post # processing framework. For now the user must have a jvm dir in his # home dir where the classfiles is located this should be changed # so that the execution homepath can be specified in the mRSL # jobfile # Martin Rehr 08/09/06 # If this is a oneclick job link the users jvm dir to # webserver_home/sandboxkey.oneclick # This is done because the client applet uses the # codebase from which it is originaly loaded # Therefore the codebase must be dynamicaly changed # for every job if resource_config.has_key('PLATFORM') and \ resource_config['PLATFORM'] == 'ONE-CLICK': # A two step link is made. # First sandboxkey.oneclick is made to point to # sessiondid.jvm # Second sessionid.jvm is set to point to # USER_HOME/jvm # This is done for security and easy cleanup, # sessionid.jvm is cleaned up # by the server upon job finish/timeout and # thereby leaving no open entryes to the users # jvm dir. linkintermediate = configuration.webserver_home + \ sessionid + '.jvm' if client_dir == configuration.empty_job_name: linkdest = os.path.abspath(configuration.javabin_home) else: linkdest = configuration.user_home + client_dir + \ os.sep + 'jvm' # Make link sessionid.jvm -> USER_HOME/jvm make_symlink(linkdest, linkintermediate, logger) linkloc = configuration.webserver_home + \ resource_config['SANDBOXKEY'] + '.oneclick' # Remove previous symlink # This must be done in a try/catch as the symlink, # may be a dead link and 'if os.path.exists(linkloc):' # will then return false, even though the link exists. try: os.remove(linkloc) except: pass # Make link sandboxkey.oneclick -> sessionid.jvm make_symlink(linkintermediate, linkloc, logger) except Exception, err: # ######### End JVM SANDBOX HACK ########### msg = "File '%s' was not copied to the webserver home." % \ inputfiles_path print '\nERROR: ' + str(err) logger.error(msg) return (None, msg) return (job_dict, 'OK')
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: logger.error("jobstatus input validation failed: %s" % accepted) return (accepted, returnvalues.CLIENT_ERROR) flags = ''.join(accepted['flags']) max_jobs = int(accepted['max_jobs'][-1]) order = 'unsorted ' if sorted(flags): order = 'sorted ' patterns = accepted['job_id'] project_names = accepted['project_name'] if len(project_names) > 0: for project_name in project_names: project_name_job_ids = \ get_job_ids_with_specified_project_name(client_id, project_name, configuration.mrsl_files_dir, logger) patterns.extend(project_name_job_ids) if not configuration.site_enable_jobs: output_objects.append({ 'object_type': 'error_text', 'text': '''Job execution is not enabled on this system''' }) return (output_objects, returnvalues.SYSTEM_ERROR) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = \ os.path.abspath(os.path.join(configuration.mrsl_files_dir, client_dir)) + os.sep output_objects.append({'object_type': 'header', 'text' : '%s %s job status' % \ (configuration.short_title, order)}) if not patterns: output_objects.append({ 'object_type': 'error_text', 'text': 'No job_id specified!' }) return (output_objects, returnvalues.NO_SUCH_JOB_ID) if verbose(flags): for flag in flags: output_objects.append({ 'object_type': 'text', 'text': '%s using flag: %s' % (op_name, flag) }) if not os.path.isdir(base_dir): output_objects.append( {'object_type': 'error_text', 'text' : ('You have not been created as a user on the %s server! ' \ 'Please contact the %s team.') % \ (configuration.short_title, configuration.short_title)}) return (output_objects, returnvalues.CLIENT_ERROR) filelist = [] for pattern in patterns: pattern = pattern.strip() # Backward compatibility - all_jobs keyword should match all jobs if pattern == all_jobs: pattern = '*' # Check directory traversal attempts before actual handling to # avoid leaking information about file system layout while # allowing consistent error messages unfiltered_match = glob.glob(base_dir + pattern + '.mRSL') match = [] for server_path in unfiltered_match: # IMPORTANT: path must be expanded to abs for proper chrooting abs_path = os.path.abspath(server_path) if not valid_user_path(configuration, abs_path, base_dir, True): # out of bounds - save user warning for later to allow # partial match: # ../*/* is technically allowed to match own files. logger.warning('%s tried to %s restricted path %s ! (%s)' % (client_id, op_name, abs_path, pattern)) continue # Insert valid job files in filelist for later treatment match.append(abs_path) # Now actually treat list of allowed matchings and notify if no # (allowed) match.... if not match: output_objects.append({ 'object_type': 'error_text', 'text': '%s: You do not have any matching job IDs!' % pattern }) status = returnvalues.CLIENT_ERROR else: filelist += match if sorted(flags): sort(filelist) if max_jobs > 0 and max_jobs < len(filelist): output_objects.append({ 'object_type': 'text', 'text': 'Only showing first %d of the %d matching jobs as requested' % (max_jobs, len(filelist)) }) filelist = filelist[:max_jobs] # Iterate through jobs and list details for each job_list = {'object_type': 'job_list', 'jobs': []} for filepath in filelist: # Extract job_id from filepath (replace doesn't modify filepath) mrsl_file = filepath.replace(base_dir, '') job_id = mrsl_file.replace('.mRSL', '') job_dict = unpickle(filepath, logger) if not job_dict: status = returnvalues.CLIENT_ERROR output_objects.append( {'object_type': 'error_text', 'text' : 'No such job: %s (could not load mRSL file %s)' % \ (job_id, filepath)}) continue # Expand any job variables before use job_dict = expand_variables(job_dict) job_obj = {'object_type': 'job', 'job_id': job_id} job_obj['status'] = job_dict['STATUS'] time_fields = [ 'VERIFIED', 'VERIFIED_TIMESTAMP', 'RECEIVED_TIMESTAMP', 'QUEUED_TIMESTAMP', 'SCHEDULE_TIMESTAMP', 'EXECUTING_TIMESTAMP', 'FINISHED_TIMESTAMP', 'FAILED_TIMESTAMP', 'CANCELED_TIMESTAMP', ] for name in time_fields: if job_dict.has_key(name): # time objects cannot be marshalled, asctime if timestamp try: job_obj[name.lower()] = time.asctime(job_dict[name]) except Exception, exc: # not a time object, just add job_obj[name.lower()] = job_dict[name] ########################################### # ARC job status retrieval on demand: # But we should _not_ update the status in the mRSL files, since # other MiG code might rely on finding only valid "MiG" states. if configuration.arc_clusters and \ job_dict.get('UNIQUE_RESOURCE_NAME', 'unset') == 'ARC' \ and job_dict['STATUS'] == 'EXECUTING': try: home = os.path.join(configuration.user_home, client_dir) arcsession = arc.Ui(home) arcstatus = arcsession.jobStatus(job_dict['EXE']) job_obj['status'] = arcstatus['status'] except arc.ARCWrapperError, err: logger.error('Error retrieving ARC job status: %s' % \ err.what()) job_obj['status'] += '(Error: ' + err.what() + ')' except arc.NoProxyError, err: logger.error('While retrieving ARC job status: %s' % \ err.what()) job_obj['status'] += '(Error: ' + err.what() + ')'
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: logger.error("jobstatus input validation failed: %s" % accepted) return (accepted, returnvalues.CLIENT_ERROR) flags = ''.join(accepted['flags']) max_jobs = int(accepted['max_jobs'][-1]) order = 'unsorted ' if sorted(flags): order = 'sorted ' patterns = accepted['job_id'] project_names = accepted['project_name'] if len(project_names) > 0: for project_name in project_names: project_name_job_ids = \ get_job_ids_with_specified_project_name(client_id, project_name, configuration.mrsl_files_dir, logger) patterns.extend(project_name_job_ids) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = \ os.path.abspath(os.path.join(configuration.mrsl_files_dir, client_dir)) + os.sep output_objects.append({'object_type': 'header', 'text' : '%s %s job status' % \ (configuration.short_title, order)}) if not patterns: output_objects.append({'object_type': 'error_text', 'text' : 'No job_id specified!'}) return (output_objects, returnvalues.NO_SUCH_JOB_ID) if verbose(flags): for flag in flags: output_objects.append({'object_type': 'text', 'text' : '%s using flag: %s' % (op_name, flag)}) if not os.path.isdir(base_dir): output_objects.append( {'object_type': 'error_text', 'text' : ('You have not been created as a user on the %s server! ' \ 'Please contact the %s team.') % \ (configuration.short_title, configuration.short_title)}) return (output_objects, returnvalues.CLIENT_ERROR) filelist = [] for pattern in patterns: pattern = pattern.strip() # Backward compatibility - all_jobs keyword should match all jobs if pattern == all_jobs: pattern = '*' # Check directory traversal attempts before actual handling to # avoid leaking information about file system layout while # allowing consistent error messages unfiltered_match = glob.glob(base_dir + pattern + '.mRSL') match = [] for server_path in unfiltered_match: real_path = os.path.abspath(server_path) if not valid_user_path(real_path, base_dir, True): # out of bounds - save user warning for later to allow # partial match: # ../*/* is technically allowed to match own files. logger.warning('%s tried to %s restricted path %s ! (%s)' % (client_id, op_name, real_path, pattern)) continue # Insert valid job files in filelist for later treatment match.append(real_path) # Now actually treat list of allowed matchings and notify if no # (allowed) match.... if not match: output_objects.append( {'object_type': 'error_text', 'text' : '%s: You do not have any matching job IDs!' % pattern}) status = returnvalues.CLIENT_ERROR else: filelist += match if sorted(flags): sort(filelist) if max_jobs < len(filelist): output_objects.append( {'object_type': 'text', 'text' : 'Only showing first %d of the %d matching jobs as requested' % (max_jobs, len(filelist))}) filelist = filelist[:max_jobs] # Iterate through jobs and print details for each job_list = {'object_type': 'job_list', 'jobs': []} for filepath in filelist: # Extract job_id from filepath (replace doesn't modify filepath) mrsl_file = filepath.replace(base_dir, '') job_id = mrsl_file.replace('.mRSL', '') job_dict = unpickle(filepath, logger) if not job_dict: status = returnvalues.CLIENT_ERROR output_objects.append( {'object_type': 'error_text', 'text' : 'No such job: %s (could not load mRSL file %s)' % \ (job_id, filepath)}) continue # Expand any job variables before use job_dict = expand_variables(job_dict) job_obj = {'object_type': 'job', 'job_id': job_id} job_obj['status'] = job_dict['STATUS'] time_fields = [ 'VERIFIED', 'VERIFIED_TIMESTAMP', 'RECEIVED_TIMESTAMP', 'QUEUED_TIMESTAMP', 'SCHEDULE_TIMESTAMP', 'EXECUTING_TIMESTAMP', 'FINISHED_TIMESTAMP', 'FAILED_TIMESTAMP', 'CANCELED_TIMESTAMP', ] for name in time_fields: if job_dict.has_key(name): # time objects cannot be marshalled, asctime if timestamp try: job_obj[name.lower()] = time.asctime(job_dict[name]) except Exception, exc: # not a time object, just add job_obj[name.lower()] = job_dict[name] ########################################### # ARC job status retrieval on demand: # But we should _not_ update the status in the mRSL files, since # other MiG code might rely on finding only valid "MiG" states. if configuration.arc_clusters and \ job_dict.get('UNIQUE_RESOURCE_NAME', 'unset') == 'ARC' \ and job_dict['STATUS'] == 'EXECUTING': try: home = os.path.join(configuration.user_home, client_dir) arcsession = arc.Ui(home) arcstatus = arcsession.jobStatus(job_dict['EXE']) job_obj['status'] = arcstatus['status'] except arc.ARCWrapperError, err: logger.error('Error retrieving ARC job status: %s' % \ err.what()) job_obj['status'] += '(Error: ' + err.what() + ')' except arc.NoProxyError, err: logger.error('While retrieving ARC job status: %s' % \ err.what()) job_obj['status'] += '(Error: ' + err.what() + ')'