/* * This file or a portion of this file is licensed under the terms of * the Globus Toolkit Public License, found in file GTPL, or at * http://www.globus.org/toolkit/download/license.html. This notice must * appear in redistributions of this file, with or without modification. * * Redistributions of this Software, with or without modification, must * reproduce the GTPL in: (1) the Software, or (2) the Documentation or * some other similar material which is provided with the Software (if * any). * * Copyright 1999-2004 University of Chicago and The University of * Southern California. All rights reserved. */ package org.griphyn.vdl.directive; import java.io.*; import org.griphyn.vdl.directive.WorkflowJob; import org.griphyn.vdl.util.*; import java.sql.SQLException; /** * * A <code>Workflow</code> object defines a context for running a * derivation graph on the Grid as a DAG, and managing its execution. * It serves as a front-end to an associated shell script (by default * located in $PEGASUS_HOME/bin/vds-Workflow-script-runwf) * * The workflow to be executed is designated by its terminal derivation (DV). * * The Workflow instance is returned by the class method Workflow.run(). * * The Workflow class variables contain status cached from period * queries of the workflow database. * * @author Douglas Scheftner * @author Mike Wilde * @author Eric Gilbert * @version $Revision$ * */ public class Workflow { /* Class Variables */ public static String runwfCmd = "/home/dscheftn/vds/bin/vds-Workflow-script-runwf"; public static String wfstatCmd = "/home/dscheftn/vds/bin/vds-Workflow-script-wfstat"; public static String defaultVOGroup = "quarknet"; public static String logicalFileNameBase = "/export/d1/dscheftn/quarknet_testing/runs"; /** parent directory for run-dir tree ala vds-plan/vds-run. */ public static String defaultBaseDir = "/no/base/dir"; public static String rlsURL = "rls://terminable.uchicago.edu"; public static final int MAXWF = 100000; public static Workflow[] workflows = new Workflow[MAXWF]; public static int nworkflows; public static long millisecsToRefreshStatus = 30000; // 30 secs between auto-refresh of status public static long timeOfLastRefresh = 0; // really want this publically read-only // private static String voGroup; /* Instance Variables */ /* sample data from database: id | basedir | vogroup | workflow | run | creator | ----+-----------------+---------+------------+---------+---------+ 1 | /home/wilde/run | ivdgl1 | test | run0001 | wilde | ctime | state | mtime ------------------------+-------+------------------------ 2005-08-20 13:25:27-05 | -2 | 2005-08-20 13:28:09-05 */ /* Instance variables that mirror the database fields */ public String wfid; public String basedir; public String vogroup; public String wfname; public String run; public String creator; public String ctime; public String state; public String exitstatus; public String mtime; /* Instance variables to track workflow state */ public static final int WFMAXJOBS = 20000; /* FIX: can we avoid this hard limit? */ public WorkflowJob[] jobs; public int njobs; public String tmpdir; public String errorMessage; /* Class Methods */ public static Workflow run ( String namespace, String dvName ) { Process p; int rc; Reader is; StringBuffer sb = new StringBuffer(); char [] b = new char[100000]; int n; Workflow wf = new Workflow(); wf.basedir = defaultBaseDir; wf.vogroup = defaultVOGroup; wf.wfname = dvName; try { System.out.println("Running Process " + namespace + " " + dvName); String[] cmd = { runwfCmd, defaultVOGroup, logicalFileNameBase, defaultBaseDir, rlsURL, namespace, dvName }; p = Runtime.getRuntime().exec( cmd ); InputStream out = p.getInputStream(); InputStreamReader r = new InputStreamReader(out); BufferedReader in = new BufferedReader(r); wf.tmpdir = in.readLine(); System.out.println("output from runwf: tmpdir=" + wf.tmpdir); wf.run = in.readLine(); System.out.println("output from runwf: run=" + wf.run); wf.errorMessage = in.readLine(); System.out.println("output from runwf: errorMessage=" + wf.errorMessage); rc = p.waitFor(); System.out.println("Process returned rc=" + rc); return(wf); } catch (Exception e) { System.out.println("Prepare: Exception: " + e.toString() ); return wf; } } public static boolean refresh() { Process p; int rc; Reader is; StringBuffer sb = new StringBuffer(); char [] b = new char[100000]; int n; /* Run status command to get workflow states */ try { p = Runtime.getRuntime().exec(wfstatCmd); InputStream out = p.getInputStream(); InputStreamReader r = new InputStreamReader(out); BufferedReader in = new BufferedReader(r); String line; nworkflows=0; while ( (line = in.readLine()) != null ) { Workflow w = new Workflow(); String[] t = line.split("\\|"); int nt = t.length; if (nt > 1) w.wfid=t[1]; if (nt > 2) w.basedir = t[2]; if (nt > 3) w.vogroup = t[3]; if (nt > 4) w.wfname = t[4]; if (nt > 5) w.run = t[5]; if (nt > 6) w.creator = t[6]; if (nt > 7) w.ctime = t[7]; if (nt > 8) { switch(Integer.parseInt(t[8],10)) { case -2: w.state = "WFSTATE_PLANNED"; w.exitstatus = ""; break; case -1: w.state = "WFSTATE_RUNNING"; w.exitstatus = ""; break; default: w.state = "WFSTATE_FINISHED"; w.exitstatus = t[8]; break; } } if (nt > 9) w.mtime = t[9]; if( nworkflows < (MAXWF) ) { workflows[nworkflows++] = w; } else { return false; } } rc = p.waitFor(); return true; } catch (Exception e) { System.out.println("WorkflowJob.refresh: Exception: " + e.toString() ); return false; } } /* Instance Methods */ /** * Sets the status fields in a Workflow instance. * @return true if status was successfully obtained, false if not. */ public boolean updateStatus() { boolean rc; long now = System.currentTimeMillis(); if ( now > (timeOfLastRefresh + millisecsToRefreshStatus) ) { rc = Workflow.refresh(); rc = WorkflowJob.refresh(); timeOfLastRefresh = now; } for( int i=0; i<nworkflows; i++ ) { if ( workflows[i].basedir.equals(basedir) && workflows[i].vogroup.equals(vogroup) && workflows[i].wfname.equals(wfname) && workflows[i].run.equals(run) ) { wfid = workflows[i].wfid; creator = workflows[i].creator; ctime = workflows[i].ctime; state = workflows[i].state; exitstatus = workflows[i].exitstatus; mtime = workflows[i].mtime; break; } } if(wfid == null ) return false; // System.out.println ("basedir = " + basedir + " vogroup = " + vogroup + " wfname = " + wfname + " run = " + run + " wfid = " + wfid + " creator = " + creator + " ctime = " + ctime + " state = " + state + " exitstatus = " + exitstatus + " mtime = " + mtime); jobs = new WorkflowJob[WFMAXJOBS]; njobs = 0; for( int i=0; i<WorkflowJob.njobs; i++) { if ( WorkflowJob.jobs[i].wfid.equals(wfid) ) if ( njobs < WFMAXJOBS ) jobs[njobs++] = WorkflowJob.jobs[i]; } return true; } public String toWFStatusString() { updateStatus(); return "wfid=" + wfid + " run=" + run + " ctime=" + ctime + " state=" + state + " exitstatus=" + exitstatus + " mtime=" + mtime + " refreshed=" + timeOfLastRefresh; } public String toJobStatusString() { updateStatus(); if (njobs == 0) return ""; String s = jobs[0].asStatusString(); for( int i=1; i<njobs; i++ ) { s += "\n" + jobs[i].asStatusString(); } return(s); } public String toDetailStatusString() { return toWFStatusString() + "\n" + toJobStatusString(); } public int stop() { return 0; } public int cleanup () { return 0; } }