commit 54832ef8c386c4d3fa7ba9c92af9626c5c52091e Author: penguinc Date: Mon Jun 27 06:48:59 2005 +0000 Initial revision diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..ae470e8 --- /dev/null +++ b/build.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mass.jar b/mass.jar new file mode 100644 index 0000000..75c2c6a Binary files /dev/null and b/mass.jar differ diff --git a/src/org/penguincoder/mass/CMD.java b/src/org/penguincoder/mass/CMD.java new file mode 100644 index 0000000..770be11 --- /dev/null +++ b/src/org/penguincoder/mass/CMD.java @@ -0,0 +1,20 @@ +package org.penguincoder.mass; + +/* + * Created on Jan 2, 2005 + * + */ +/** + * @author Andrew Coleman + * + */ +public class CMD extends Thread { + + public CMD () { + super (); + } + + public CMD ( ThreadGroup tg, String name ) { + super ( tg, name ); + } +} \ No newline at end of file diff --git a/src/org/penguincoder/mass/CMDcopy.java b/src/org/penguincoder/mass/CMDcopy.java new file mode 100644 index 0000000..ca241c3 --- /dev/null +++ b/src/org/penguincoder/mass/CMDcopy.java @@ -0,0 +1,62 @@ +/* + * Created on Jun 23, 2005 + * + */ +package org.penguincoder.mass; + +import java.util.ArrayList; + +/** + * @author Andrew Coleman + * + */ +public class CMDcopy extends CMD { + + private String hostname; + + private ArrayList fileset; + + private String remoteDir; + + private StringBuffer result; + + private final static String lineSeparator = System + .getProperty ( "line.separator" ); + + public CMDcopy ( ArrayList fileset, String remoteDir, String hostname, + ThreadGroup tg, String threadName ) { + super ( tg, threadName ); + this.hostname = hostname; + if ( remoteDir.equals ( "''" ) ) { + this.remoteDir = ""; + } else { + this.remoteDir = remoteDir; + } + this.fileset = fileset; + this.result = null; + } + + public void run () { + ArrayList toRun = new ArrayList ( 10 ); + if ( System.getProperty ( "os.name" ).toLowerCase ().startsWith ( + "windows" ) ) { + toRun.add ( "pscp" ); + } else { + toRun.add ( "scp" ); + } + toRun.addAll ( this.fileset ); + toRun.add ( this.hostname + ":" + this.remoteDir ); + result = Manager.getCommandOutput ( (String[]) toRun + .toArray ( new String[0] ) ); + } + + public String toString () { + if ( result == null ) + return ""; + StringBuffer out = new StringBuffer ( 2048 ); + out.append ( "Secure copy results from '" + this.hostname + "'" + + lineSeparator ); + out.append ( result.toString () ); + return out.toString () + lineSeparator; + } +} \ No newline at end of file diff --git a/src/org/penguincoder/mass/CMDrun.java b/src/org/penguincoder/mass/CMDrun.java new file mode 100644 index 0000000..190ef20 --- /dev/null +++ b/src/org/penguincoder/mass/CMDrun.java @@ -0,0 +1,57 @@ +/* + * Created on Jun 23, 2005 + * + */ +package org.penguincoder.mass; + +/** + * @author Andrew Coleman + * + */ +public class CMDrun extends CMD { + + private String hostname; + + private String command; + + private StringBuffer result; + + private final static String lineSeparator = System + .getProperty ( "line.separator" ); + + public CMDrun ( String command, String hostname, ThreadGroup tg, + String threadName ) { + super ( tg, threadName ); + this.hostname = hostname; + this.command = command; + result = null; + } + + public void run () { + String[] toRun; + if ( System.getProperty ( "os.name" ).toLowerCase ().startsWith ( + "windows" ) ) { + toRun = new String[4]; + toRun[0] = "plink"; + toRun[1] = "-ssh"; + toRun[2] = this.hostname; + toRun[3] = this.command; + } else { + toRun = new String[3]; + toRun[0] = "ssh"; + toRun[1] = this.hostname; + toRun[2] = this.command; + } + result = Manager.getCommandOutput ( toRun ); + } + + public String toString () { + if ( result == null ) + return ""; + StringBuffer out = new StringBuffer ( 2048 ); + out.append ( "Command results from '" + this.hostname + "'" + + lineSeparator ); + out.append ( result.toString () ); + return out.toString () + lineSeparator; + } +} \ No newline at end of file diff --git a/src/org/penguincoder/mass/Manager.java b/src/org/penguincoder/mass/Manager.java new file mode 100644 index 0000000..4a84fde --- /dev/null +++ b/src/org/penguincoder/mass/Manager.java @@ -0,0 +1,285 @@ +/* + * Created on Dec 21, 2004 + */ +package org.penguincoder.mass; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; + +/** + * @author Andrew Coleman + * + */ +public class Manager { + + private static ArrayList serverlist; + + protected final static double currentVersion = .01; + + private static String hostname, fqdnhostname; + + private static void parseServerList ( String inputfile ) { + /* the result arraylist, useful for unknown array sizes */ + if ( serverlist == null ) { + serverlist = new ArrayList ( 64 ); + } + /* + * either fill from the file if the file exists, if the file does not + * exist, assume that you mean a hostname + */ + try { + /* nice buffered reader for input */ + BufferedReader inReader = new BufferedReader ( new FileReader ( + inputfile ) ); + /* read until the file is done */ + while ( inReader.ready () ) { + /* the most effective, not efficient, way to do this is by line */ + String line = inReader.readLine ().trim (); + if ( !line.startsWith ( "#" ) && !line.equals ( hostname ) && !line.equals ( fqdnhostname ) ) { + serverlist.add ( line ); + } + } + /* finished with the file */ + inReader.close (); + } catch ( FileNotFoundException e ) { + serverlist.add ( inputfile ); + } catch ( IOException e ) { + System.err.println ( "There was a problem reading the file: " + + e.getLocalizedMessage () ); + System.exit ( 1 ); + } + } + + public static StringBuffer getCommandOutput ( String[] command ) { + StringBuffer resultBuffer = new StringBuffer ( 2048 ); + + try { + Process process = Runtime.getRuntime ().exec ( command ); + + /* get the regular output */ + BufferedReader reader = new BufferedReader ( new InputStreamReader ( + process.getInputStream () ) ); + int bytesRead = 0; + char[] buf = new char[2048]; + do { + bytesRead = reader.read ( buf ); + if ( bytesRead > 0 ) { + resultBuffer.append ( buf, 0, bytesRead ); + } + } while ( bytesRead > 0 ); + /* sometimes this can be null, unknown as to the reason */ + if ( reader != null ) { + reader.close (); + } + + /* get the error stream */ + BufferedReader ereader = new BufferedReader ( + new InputStreamReader ( process.getErrorStream () ) ); + do { + bytesRead = ereader.read ( buf ); + if ( bytesRead > 0 ) { + resultBuffer.append ( buf, 0, bytesRead ); + } + } while ( bytesRead > 0 ); + /* sometimes this can be null, unknown as to the reason */ + if ( ereader != null ) { + ereader.close (); + } + } catch ( IOException e ) { + /* report IO errors */ + resultBuffer.append ( "IOException caught!" + + System.getProperty ( "line.separator" ) ); + resultBuffer.append ( e.toString () + + System.getProperty ( "line.separator" ) ); + } + return resultBuffer; + } + + private static void usage () { + String lineSeparator = System.getProperty ( "line.separator" ); + System.out.println ( "This is the Massive Cluster Utility" ); + System.out + .println ( "General Usage: java -jar mass.jar -- " ); + System.out.println ( "Current Version: " + currentVersion + + lineSeparator ); + System.out + .println ( "The serverfile is a line delimited list of machines." ); + System.out.println ( "Supported Commands: (case-insensitive)" ); + System.out.println ( "\trun" + lineSeparator + "\tcopy" ); + } + + public static void main ( String[] args2 ) { + /* sigh, this is a dirty hack to make + * Eclipse run this program, remove the block + * and change the main arguments to args from + * args2 to remove the hack. + */ + String[] args = null; + if ( args2[0].indexOf ( "Manager" ) > 0 ) { + args = new String[args2.length - 1]; + for ( int i = 1; i < args2.length; i++ ) { + args[i - 1] = args2[i]; + } + } else { + args = args2; + } + /* end hacky block */ + + /* see if the gui needs to be started */ + if ( args.length < 4 ) { + usage (); + System.exit ( 1 ); + } + + /* basic sanity check on the command, there are only two */ + String command = args[0].toLowerCase (); + if ( !command.equals ( "copy" ) && !command.equals ( "run" ) ) { + usage (); + System.exit ( 1 ); + } + + /* determine the hostname of the current box, must skip current box */ + hostname = ""; + try { + java.net.InetAddress localMachine = java.net.InetAddress + .getLocalHost (); + fqdnhostname = localMachine.getHostName ().toLowerCase (); + hostname = fqdnhostname.replaceFirst("[.].*", ""); + } catch ( java.net.UnknownHostException uhe ) { + hostname = "localhost"; + fqdnhostname = "localhost.localdomain"; + } + /* populate the list of servers */ + int j = 1; + for ( ; j < args.length && !args[j].equals ( "--" ); j++ ) { + /* either fill from the file or from the listing */ + parseServerList ( args[j] ); + } + /* found the double dash, so populate the argument array */ + j++; + String[] commandArgs = new String[args.length - j]; + for ( int i = 0; j < args.length; j++, i++ ) { + commandArgs[i] = args[j]; + } + + /* start the textual report */ + generateTextReport ( command, commandArgs ); + } + + private static void generateTextReport ( String command, + String[] commandArgs ) { + int serverCount = serverlist.size (); + + /* the ThreadGroup that will house all of the commands */ + ThreadGroup threadGroup = new ThreadGroup ( "MassiveClusterUtility" ); + + /* the array of Commands that will eventually be run */ + CMD[] commands = new CMD[serverCount]; + + /* create the command for each site */ + int threadCount = 0; + System.out.println ( "Creating threads:" ); + + /* + * simple command check, there are only two. more would require the use + * of a factory for simplicity + * + * I'm going to go ahead and do all of the processing required to get + * the object moving here. This is better done once than done + * serverCount times :P + */ + if ( command.equals ( "run" ) ) { + String commandToRun = ""; + for ( int i = 0; i < commandArgs.length; i++ ) { + commandToRun += commandArgs[i] + " "; + } + commandToRun.trim (); + System.out.println ( "Going to run the command: " + commandToRun ); + for ( int serverNum = 0; serverNum < serverCount; serverNum++ ) { + String server = (String) serverlist.get ( serverNum ); + System.out.print ( server + " " ); + commands[serverNum] = new CMDrun ( commandToRun, server, + threadGroup, "mass-run-" + server ); + commands[serverNum].setPriority ( Thread.MIN_PRIORITY ); + commands[serverNum].start (); + if ( threadCount == 5 ) { + System.out.println (); + threadCount = 0; + } else { + threadCount++; + } + } + } else { + String remotePath = "", fileString = ""; + ArrayList files = new ArrayList ( 10 ); + remotePath = commandArgs[commandArgs.length - 1]; + int top = commandArgs.length - 2; + for ( int i = 0; i <= top; i++ ) { + files.add ( commandArgs[i].trim () ); + fileString += commandArgs[i].trim () + " "; + } + fileString.trim (); + System.out.println ( "Going to copy the fileset: " + files ); + System.out.println ( "Remote path will be: " + remotePath ); + for ( int serverNum = 0; serverNum < serverCount; serverNum++ ) { + String server = (String) serverlist.get ( serverNum ); + System.out.print ( server + " " ); + commands[serverNum] = new CMDcopy ( files, remotePath, server, + threadGroup, "mass-copy-" + server ); + commands[serverNum].setPriority ( Thread.MIN_PRIORITY ); + commands[serverNum].start (); + if ( threadCount == 5 ) { + System.out.println (); + threadCount = 0; + } else { + threadCount++; + } + } + } + System.out.println ( "Done" ); + + /* wait on all of the threads to start */ + do { + threadCount = threadGroup.activeCount (); + try { + Thread.sleep ( 100 ); + } catch ( InterruptedException e1 ) { + } + } while ( threadCount != threadGroup.activeCount () ); + + /* wait on all the threads to finish */ + int dotNumber = 0; + while ( (threadCount = threadGroup.activeCount ()) > 0 ) { + /* + * this will print out 12 dots in one line, with one dot every 5 + * seconds. each line is a minute of processing, makes it very easy + * to figure out how long it ran. + */ + System.out.print ( "." ); + try { + Thread.sleep ( 5000 ); + } catch ( InterruptedException e1 ) { + } + if ( dotNumber >= 11 ) { + System.out.println (); + dotNumber = 0; + } else { + dotNumber++; + } + } + + /* print out the report */ + System.out.println ( System.getProperty ( "line.separator" ) ); + System.out.println ( "===== Begin Report =====" ); + for ( int thread = 0; thread < commands.length; thread++ ) { + System.out.print ( commands[thread].toString () ); + } + + /* finished */ + System.out.println ( "Fin" ); + } +} \ No newline at end of file diff --git a/src/org/penguincoder/mass/MassiveException.java b/src/org/penguincoder/mass/MassiveException.java new file mode 100644 index 0000000..59f588f --- /dev/null +++ b/src/org/penguincoder/mass/MassiveException.java @@ -0,0 +1,15 @@ +package org.penguincoder.mass; + +/* + * Created on Dec 21, 2004 + * + */ +/** + * @author Andrew Coleman + * + */ +public class MassiveException extends Exception { + public MassiveException ( String message ) { + super ( message ); + } +} \ No newline at end of file