package io.seqware; import com.google.common.base.Objects; import io.seqware.common.model.WorkflowRunStatus; import static io.seqware.common.model.WorkflowRunStatus.pending; import static io.seqware.common.model.WorkflowRunStatus.running; import static io.seqware.common.model.WorkflowRunStatus.submitted; import io.seqware.pipeline.SqwKeys; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; import net.sourceforge.seqware.common.metadata.Metadata; import net.sourceforge.seqware.common.metadata.MetadataFactory; import net.sourceforge.seqware.common.model.WorkflowRun; import net.sourceforge.seqware.common.util.Log; import net.sourceforge.seqware.common.util.configtools.ConfigTools; import org.apache.oozie.client.OozieClient; import org.apache.oozie.client.OozieClientException; import org.apache.oozie.client.WorkflowAction; import org.apache.oozie.client.WorkflowJob; public class WorkflowRuns { public static void submitCancel(int... workflowRunAccessions) { multithreadTransition(Transition.CANCEL, workflowRunAccessions); } private static void cancelWorkflowRun(int workflowRunAccession) throws UnsupportedOperationException { Metadata md = MetadataFactory.get(ConfigTools.getSettings()); WorkflowRun wr = md.getWorkflowRun(workflowRunAccession); if (Engines.supportsCancel(wr.getWorkflowEngine())) { switch (wr.getStatus()) { case submitted: case pending: case running: wr.setStatus(WorkflowRunStatus.submitted_cancel); md.updateWorkflowRun(wr); default: // do nothing } } else { throw new UnsupportedOperationException("Workflow run cancellation not supported for engine: " + wr.getWorkflowEngine()); } } public static void failWorkflowRuns(int... workflowRunAccessions) { multithreadTransition(Transition.FAIL, workflowRunAccessions); } private static void failWorkflowRun(int workflowRunAccession) { Metadata md = MetadataFactory.get(ConfigTools.getSettings()); WorkflowRun wr = md.getWorkflowRun(workflowRunAccession); wr.setStatus(WorkflowRunStatus.failed); md.updateWorkflowRun(wr); } public static void submitRetry(int... workflowRunAccessions) { multithreadTransition(Transition.RETRY, workflowRunAccessions); } private enum Transition { FAIL, CANCEL, RETRY } private static void multithreadTransition(final Transition transition, int[] workflowRunAccessions) { ExecutorService pool = Executors.newFixedThreadPool(Math.min(10, workflowRunAccessions.length)); List<Future<?>> futures = new ArrayList<>(workflowRunAccessions.length); for (int workflowRunAccession : workflowRunAccessions) { final int workflowRunAccessionCopy = workflowRunAccession; futures.add(pool.submit(new Runnable() { @Override public void run() { if (transition == Transition.RETRY) { retryWorkflowRun(workflowRunAccessionCopy); } else if (transition == Transition.CANCEL) { cancelWorkflowRun(workflowRunAccessionCopy); } else if (transition == Transition.FAIL) { failWorkflowRun(workflowRunAccessionCopy); } } })); } for (Future<?> future : futures) { try { future.get(); } catch (InterruptedException | ExecutionException ex) { Log.fatal(ex); } } pool.shutdown(); } private static void retryWorkflowRun(int workflowRunAccession) throws UnsupportedOperationException { Metadata md = MetadataFactory.get(ConfigTools.getSettings()); WorkflowRun wr = md.getWorkflowRun(workflowRunAccession); if (Engines.supportsRetry(wr.getWorkflowEngine())) { switch (wr.getStatus()) { case failed: case cancelled: wr.setStatus(WorkflowRunStatus.submitted_retry); md.updateWorkflowRun(wr); default: // do nothing } } else { throw new UnsupportedOperationException("Workflow run retrying not supported for engine: " + wr.getWorkflowEngine()); } } public static String workflowRunIni(int workflowRunAccession) { Metadata md = MetadataFactory.get(ConfigTools.getSettings()); WorkflowRun workflowRun = md.getWorkflowRun(workflowRunAccession); return workflowRun.getIniFile(); } /** * Convert from status command to workflow run * * @param statusCmd * @return */ public static WorkflowRun getWorkflowRunByStatusCmd(String statusCmd) { Metadata md = MetadataFactory.get(ConfigTools.getSettings()); List<WorkflowRun> workflowRuns = md.getWorkflowRunsByStatusCmd(statusCmd); // assume that this is unique for now (should be a safe assumption for Oozie) if (!workflowRuns.isEmpty()) { return workflowRuns.get(0); } return null; } /** * Extremely extremely expensive! Converts between sge id and determines the workflow run accession that it corresponds to. * * This is expensive because the Oozie-sge engine doesn't expose the external ID, instead we need to do a really expensive search. * * @param sgeid * @return */ public static Integer getAccessionByActionExternalID(String sgeid) { Map<String, String> config = ConfigTools.getSettings(); OozieClient oc = new OozieClient(config.get(SqwKeys.OOZIE_URL.getSettingKey())); try { for (int i = 0;; i++) { int rangeStart = i * 10; int rangeEnd = i * 10 + 10; Log.debug("Requesting " + rangeStart + " " + rangeEnd); List<WorkflowJob> jobsInfo = oc.getJobsInfo("", rangeStart, rangeEnd); if (jobsInfo.isEmpty()) { break; } for (WorkflowJob job : jobsInfo) { job = oc.getJobInfo(job.getId()); for (WorkflowAction action : job.getActions()) { if (Objects.equal(action.getExternalId(), sgeid)) { return getWorkflowRunByStatusCmd(job.getId()).getSwAccession(); } } } } } catch (OozieClientException ex) { Logger.getLogger(WorkflowRuns.class.getName()).log(Level.SEVERE, null, ex); throw new RuntimeException(ex); } return null; } }