package org.molgenis.compute.host; import java.io.IOException; import java.util.UUID; import org.molgenis.util.SimpleTuple; import org.molgenis.util.SshResult; /** Facade to use Glite over ssh */ public class Glite extends AbstractComputeHost implements ComputeHost { public Glite(String host, String user, String password) throws IOException { super(host, user, password, 22); this.close(); } @Override public void submit(Job job) throws IOException { this.connect(); // if no name set, create one if (job.getName() == null) job.setName(UUID.randomUUID().toString().replace("-", "")); // create prefix path String path = getWorkingDir() + ("".equals(this.getWorkingDir()) ? "" : "/") + job.getName(); // create standard jdl // String jdl = String.format("Type=\"Job\";" + "\nJobType=\"Normal\";" // + "\n" + "\nExecutable = \"/bin/sh\";" // + "\nVirtualOrganisation = \"lsgrid\";" // + "\nArguments = \"%1$s.sh\";" + "\n" + "\nStdError = \"%1$s.err\";" // + "StdOutput = \"%1$s.out\";" // + "\n" + "InputSandbox = {\"$HOME/%2$s.sh\"};" + // "\nOutputSandbox = {\"%1$s.err\", \"%1$s.out\"};" // + "\nMyProxyServer = \"px.grid.sara.nl\";", // job.getName(), path); String jdl = String.format("# General\n" + "Type = \"Job\";\n" + "VirtualOrganisation = \"bbmri.nl\";\n" + "DefaultNodeShallowRetryCount = 5;\n" + "\n" + "# Executables, input and output\n" + "Executable = \"/bin/sh\";\n" + "Arguments = \"%1$s.sh\";\n" + "StdOutput = \"%1$s.out\";\n" + "StdError = \"%1$s.err\";\n" + "InputSandbox = {\"$HOME/%2$s.sh\"};\n" + "OutputSandbox = {\"%1$s.err\",\"%1$s.out\"};\n" + "MyProxyServer = \"px.grid.sara.nl\";\n" + "RetryCount = 0;", job.getName(), path); // copy .sh and .jdl String filename = job.getName() + ".sh"; logger.debug("uploading script as file: " + filename); String script = job.getScript(); script = script.replaceAll("\r", ""); this.uploadStringToFile(script, filename, this.getWorkingDir()); filename = job.getName() + ".jdl"; logger.debug("uploading jdl as file: " + filename); this.uploadStringToFile(jdl, filename, this.getWorkingDir()); // start the scrip String command = String.format("glite-wms-job-submit -d $USER -o %1$s $HOME/%2$s.jdl", job.getName(), path); // cd to working directory (otherwise stuff is in wrong dir) if (!"".equals(getWorkingDir())) command = "cd " + getWorkingDir() + " && " + command; SshResult result = this.executeCommand(command); if (!"".equals(result.getStdErr())) { throw new IOException(result.getStdErr()); } // get the id for (String line : result.getStdOut().split("\n")) { if (line.startsWith("https")) job.setId(line); } // set the paths, incl working dir job.setError_path(path + ".err"); job.setOutput_path(path + ".out"); logger.debug("job sumitted: " + job); // remember job this.jobs.put(job.getId(), job); this.close(); } public void submitPilot(Job job) throws IOException { // if no name set, create one if (job.getName() == null) job.setName(UUID.randomUUID().toString().replace("-", "")); // create prefix path String path = getWorkingDir() + ("".equals(this.getWorkingDir()) ? "" : "/") + job.getName(); // start the scrip String command = String.format("glite-wms-job-submit -d $USER -o %1$s $HOME/maverick/maverick.jdl", job.getName(), path); // cd to working directory (otherwise stuff is in wrong dir) if (!"".equals(getWorkingDir())) command = "cd " + getWorkingDir() + " && " + command; SshResult result = this.executeCommand(command); if (!"".equals(result.getStdErr())) { throw new IOException(result.getStdErr()); } // get the id for (String line : result.getStdOut().split("\n")) { if (line.startsWith("https")) job.setId(line); } // set the paths, incl working dir // job.setError_path( path +".err"); // job.setOutput_path( path + ".out"); logger.debug("job sumitted: " + job); // remember job this.jobs.put(job.getId(), job); } @Override public void remove(Job job) throws IOException { // TODO Auto-generated method stub } @Override public void refresh(Job job) throws IOException { if (job.getState() == JobState.COMPLETED) return; try { this.connect(); // cd to working directory String command = "glite-wms-job-status " + job.getId(); if (!"".equals(getWorkingDir())) command = "cd " + getWorkingDir() + " && " + command; // retrieve the state SshResult gliteOutput = executeCommand(command); this.parse(job, gliteOutput.getStdOut()); // if complete, retrieve logs if (job.getState() == JobState.COMPLETED) { command = "glite-wms-job-output --dir $HOME/" + getWorkingDir() + " --nosubdir --noint " + job.getId(); if (!"".equals(getWorkingDir())) command = "cd " + getWorkingDir() + " && " + command; SshResult result = executeCommand(command); logger.debug(result.getStdOut() + "\n" + result.getStdOut()); // if(!"".equals(result.getStdErr())) throw new // Exception(result.getStdErr()); job.setError_log(this.downloadFile(job.getError_path())); job.setOutput_log(this.downloadFile(job.getOutput_path())); } this.close(); } catch (Exception e) { e.printStackTrace(); } } private void parse(Job job, String log) { SimpleTuple parse = new SimpleTuple(); if (log == null || "".equals(log)) return; logger.info("parsing log: " + log); String[] keyValuePairs = log.split("\n"); for (String keyValue : keyValuePairs) { keyValue = keyValue.trim(); String[] split = null; if (keyValue.contains(":")) split = keyValue.split(":"); else split = keyValue.split("="); String key = null, value = null; if (split.length > 1) { key = split[0].trim(); value = split[1].trim(); parse.set(key, value); } } // translate status job.setExec_host(parse.getString("Destination")); String status = parse.getString("Current Status"); if (status != null) { if (status.startsWith("Submitted")) job.setState(JobState.SUBMITTED); else if (status.startsWith("Running")) job.setState(JobState.RUNNING); else if (status.startsWith("Scheduled")) job.setState(JobState.QUEUED); else if (status.startsWith("Done")) job.setState(JobState.COMPLETED); else if (status.startsWith("Aborted")) job.setState(JobState.ERROR); else if (status.startsWith("Cancelled")) job.setState(JobState.CANCELLED); } // else we ignore. // Status: // SUBMITTED The job has been submitted by the user but not yet // processed by the Network Server // WAITING The job has been accepted by the Network Server but not yet // processed by the Workload Manager // READY The job has been assigned to a Computing Element but not yet // transferred to it // SCHEDULED The job is waiting in the Computing Element's queue // RUNNING The job is running // DONE The job has finished // ABORTED The job has been aborted by the WMS (e.g. because it was too // long, or the proxy certificated expired, etc.) // CANCELLED The job has been cancelled by the user // CLEARED The Output Sandbox has been transferred to the User Interface // When you have multiple jobs with same id we will parse last one // ======================= glite-wms-job-status Success // ===================== // BOOKKEEPING INFORMATION: // // Status info for the Job : // https://wms4.grid.sara.nl:9000/DoUwj8kcREp95KTx5VSwcQ // Current Status: Running // Status Reason: unavailable // Destination: phoebe.htc.biggrid.nl:8443/cream-pbs-short // Submitted: Sat Jul 14 21:18:29 2012 CEST // ========================================================================== } }