package com.dgrid.driver; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; import org.springframework.context.support.AbstractApplicationContext; import com.dgrid.errors.TransportException; import com.dgrid.gen.Constants; import com.dgrid.gen.InvalidApiKey; import com.dgrid.gen.InvalidHost; import com.dgrid.gen.JOB_STATUS; import com.dgrid.gen.Joblet; import com.dgrid.gen.JobletResult; import com.dgrid.service.DGridClient; import com.dgrid.util.ApiCallbackTypes; import com.dgrid.util.io.InputStreamUtils; public class DShell extends BaseDgridDriver { private static Log log = LogFactory.getLog(DShell.class); @Option(name = "--ps", usage = "show active process list") private boolean ps = false; @Option(name = "--submit", usage = "submit a new joblet") private boolean submit = true; @Option(name = "--jobid", usage = "append to an existing job (default is no (0 value))") private int jobId = 0; @Option(name = "--priority", usage = "priority (default 1)") private int priority = 1; @Option(name = "--type", usage = "joblet type (required)") private String jobletType = "system"; @Option(name = "--description", usage = "description (default is empty)") private String description = ""; @Option(name = "--content", usage = "joblet contents (default is empty") private String content = ""; @Option(name = "--contentFromFile", usage = "joblet contents from filename (default is empty") private String contentFromFile = ""; @Option(name = "--host", usage = "run on a specific host (default is no)") private String host; @Option(name = "--callbackType", usage = "completion callback type (valid values are: xmpp|email|http|job)") private String callbackType = "none"; @Option(name = "--callbackAddress", usage = "address for callback (xmpp jid, http url, or email address)") private String callbackAddress = ""; @Option(name = "--callbackContent", usage = "contents of callback") private String callbackContent = ""; @Option(name = "--param", usage = "set a parameter (name:value)") private List<String> paramList = new ArrayList<String>(); @Option(name = "--execute", usage = "execute immediately") private boolean execute = false; private DGridClient gridClient; public static void main(String[] args) throws Exception { DShell shell = new DShell(); CmdLineParser parser = new CmdLineParser(shell); parser.setUsageWidth(80); int exitValue = 0; try { parser.parseArgument(args); if (shell.ps) { exitValue = shell.ps(); } else if (shell.submit) { exitValue = shell.submit(); } else { throw new CmdLineException( "One of either --ps or --submit must be provided"); } } catch (CmdLineException e) { System.err.println("Usage: dshell [options...] arguments..."); parser.printUsage(System.err); log.error("Could not parse options:", e); exitValue = 1; } System.exit(exitValue); } DShell() throws Exception { AbstractApplicationContext ctx = getContext(); gridClient = (DGridClient) ctx.getBean(DGridClient.NAME); } public int submit() throws Exception { log.trace("submit()"); int returnCode = 0; try { String jobletContent = (content.length() > 0) ? content : ((contentFromFile.length() > 0) ? InputStreamUtils .getFileAsString(new File(contentFromFile)) : ""); Map<String, String> params = parseMap(paramList); Joblet joblet = new Joblet(0, 0l, jobId, 0, getUser(), priority, jobletType, description, params, jobletContent, JOB_STATUS.RECEIVED); String message = null; if (execute) { JobletResult result = gridClient.gridExecute(joblet, 1); message = String.format("Return code: %1$d, status: %2$d", result.getReturnCode(), result.getStatus()); System.out.println(result.getDetails()); returnCode = result.getReturnCode(); } else if ((host == null) || (host.length() == 0)) { Joblet j = gridClient.submitJoblet(joblet, jobId, ApiCallbackTypes.getCallbackType(callbackType), callbackAddress, callbackContent); message = String.format( "Joblet submitted to job %1$d with joblet id (%2$d)", j .getJobId(), j.getId()); returnCode = 0; } else { Joblet j = gridClient.submitHostJoblet(host, joblet, jobId, ApiCallbackTypes.getCallbackType(callbackType), callbackAddress, callbackContent); message = String .format( "Joblet submitted to host %1$s and job %2$d with joblet id (%3$d)", host, j.getJobId(), j.getId()); returnCode = 0; } System.out.println(message); } finally { } return returnCode; } private int ps() throws TransportException, InvalidApiKey, InvalidHost { log.trace("ps()"); int returnCode = 0; List<Joblet> joblets = gridClient.listActiveJoblets(getUser(), 0, 100); System.out .println("Job\tJoblet\tType\tScript\tUser\tHost\tStatus\tAge\tDescription"); for (Joblet j : joblets) { String hostLabel = (j.getHostId() == 0) ? "n/a" : gridClient .getHost(j.getHostId()).getHostname(); String scriptLabel = ((j.getJobletType().contains("groovy")) || (j .getJobletType().contains("javascript"))) ? j .getParameters().get("script") : "n/a"; System.out.format( "%1$d\t%2$d\t%3$s\t%4$s\t%5$s\t%6$s\t%7$s\t%8$s\n", j .getJobId(), j.getId(), j.getJobletType(), scriptLabel, j.getSubmitter(), hostLabel, getJobletStatusString(j.getStatus()), getJobletAge(j .getTimeCreated()), j.getDescription()); } return returnCode; } private String getUser() { return System.getProperty("user.name"); } private Map<String, String> parseMap(List<String> list) throws CmdLineException { Map<String, String> retval = new HashMap<String, String>(list.size()); for (String string : list) { if (string.matches("[\\w\\:.+]")) { throw (new CmdLineException( String .format( "Argument \"%1$s\" does not match required format name:value", string))); } String name = string.substring(0, string.indexOf(':')); String value = string.substring((string.indexOf(':') + 1), string .length()); retval.put(name, value); } return retval; } private String getJobletAge(long birth) { long millis = System.currentTimeMillis() - birth; long seconds = millis / 1000; long minutes = seconds / 60; long hours = minutes / 60; long days = hours / 24; return String.format("%1$dd %2$d:%3$d", days, hours, minutes); } private String getJobletStatusString(int jobletStatus) { switch (jobletStatus) { case JOB_STATUS.COMPLETED: return "completed"; case JOB_STATUS.FAILED: return "failed"; case JOB_STATUS.PROCESSING: return "working"; case JOB_STATUS.QUEUED: return "queued"; case JOB_STATUS.RECEIVED: return "received"; case JOB_STATUS.SAVED: return "saved"; default: return "n/a"; } } }