From 54832ef8c386c4d3fa7ba9c92af9626c5c52091e Mon Sep 17 00:00:00 2001 From: penguinc Date: Mon, 27 Jun 2005 06:48:59 +0000 Subject: [PATCH] Initial revision --- build.xml | 29 ++ mass.jar | Bin 0 -> 5983 bytes src/org/penguincoder/mass/CMD.java | 20 ++ src/org/penguincoder/mass/CMDcopy.java | 62 ++++ src/org/penguincoder/mass/CMDrun.java | 57 ++++ src/org/penguincoder/mass/Manager.java | 285 ++++++++++++++++++ .../penguincoder/mass/MassiveException.java | 15 + 7 files changed, 468 insertions(+) create mode 100644 build.xml create mode 100644 mass.jar create mode 100644 src/org/penguincoder/mass/CMD.java create mode 100644 src/org/penguincoder/mass/CMDcopy.java create mode 100644 src/org/penguincoder/mass/CMDrun.java create mode 100644 src/org/penguincoder/mass/Manager.java create mode 100644 src/org/penguincoder/mass/MassiveException.java 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 0000000000000000000000000000000000000000..75c2c6af4cf797355d9478f648a0168e1d57b72b GIT binary patch literal 5983 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 W4EHi63=D$HU(aQ=0>6WCjQ<0S-%N}E literal 0 HcmV?d00001 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