Rev 6914 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/** This class handles remote execution of programs* It is only used by the build daemons* It is not used in Escrow** It is used by the master build thread as well as the ABT instance created* by the master build thread.**/package com.erggroup.buildtool.abt;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.Properties;import com.sshtools.net.SocketTransport;import com.sshtools.ssh.PasswordAuthentication;import com.sshtools.ssh.SshAuthentication;import com.sshtools.ssh.SshClient;import com.sshtools.ssh.SshConnector;import com.sshtools.ssh.SshSession;import com.sshtools.ssh2.Ssh2Context;public class RemoteExecution {/*** Interface to assist in logging the output of the remote executor* Required as the class is called in two contexts* 1) By the build daemon - where logging is to an mLogger* 2) Within ABT - where logging is via ant*/public interface LogOutput{void data(String message); // Log data from the commandvoid info(String message); // Log Info from the classvoid fatal(String message); // Log fatal messages}/*** Name or Address of the target machine**/private String mTargetMachine;/*** User name*/private String mUserName;/*** Password*/private String mPassword;/** Logger**/LogOutput mLogger;/*** Constructor* @param logger*/public RemoteExecution(LogOutput logger){mLogger = logger;}/**Determine the connection credentials* These are held in a properties file** @return true - we have credentials*/public boolean getCredentials(){InputStream input;Properties prop;String credentialsFile = System.getenv("GBE_DPKG_SSH_PROPERTIES");if (credentialsFile == null){mLogger.fatal("Packager Server SSH credendials. Location Not specified");return false;}File propFile = new File(credentialsFile);if (!propFile.isFile()){mLogger.fatal("Packager Server SSH credendials. Is not a file: " + credentialsFile);return false;}try {input = new FileInputStream(propFile);prop = new Properties();prop.load(input);} catch (IOException e) {mLogger.fatal("Packager Server SSH credendials. Cannot open: " + credentialsFile + ". Error: " + e.getMessage());return false;}mTargetMachine = prop.getProperty("ssh_server");mUserName = prop.getProperty("ssh_user");mPassword = prop.getProperty("ssh_password");if ( mTargetMachine == null || mUserName == null || mPassword == null ){mLogger.fatal("Packager Server SSH credendials. Not all properties found");return false;}return true;}/*** Test the connection to the target machine* Used each build cycle to report if the target machine is not* available.* @param mLogger - Logger to use for notification of errors** @return true - if the connection was successfully established*/public boolean testConnection(){int exitCode = -1;mLogger.info("Test remote execution authentication");exitCode = execute(null);mLogger.info("Test remote execution authentication complete");return exitCode == 0;}/*** Execute command* @param command - Command string to be processed. May be null or of zero length** @return command exit code if positive* <br>internal exist code if negative* <br>zero - command executed correctly**/public int execute(final String command){int exitCode = -1;if (getCredentials()){try {/*** Create an SshConnector instance*/SshConnector con = SshConnector.createInstance();con.getContext().setPreferredPublicKey(Ssh2Context.PUBLIC_KEY_SSHDSS);/*** Connect to the host*/final SshClient ssh = con.connect(new SocketTransport(mTargetMachine, 22), mUserName, true);/*** Authenticate the user using password authentication*/PasswordAuthentication pwd = new PasswordAuthentication();pwd.setPassword(mPassword);if( ssh.authenticate(pwd) != SshAuthentication.COMPLETE && ssh.isConnected()){mLogger.fatal("Connection to \"" + mTargetMachine + "\" not authenticated");return -1;}/*** Start a session send a command and read the commands output*/if (ssh.isAuthenticated()) {exitCode = 0;if ( command != null && command.length() > 0){final SshSession session = ssh.openSessionChannel();session.executeCommand(command);// Create two thread// One to read stdout and one to read stderr//Thread t1 = new Thread(new Runnable(){public void run(){try {BufferedReader in = new BufferedReader(new InputStreamReader(session.getInputStream()));String line = null;while((line = in.readLine()) != null) {mLogger.data(line);}} catch (IOException e) {}}});Thread t2 = new Thread(new Runnable(){public void run(){try {BufferedReader in = new BufferedReader(new InputStreamReader(session.getStderrInputStream()));String line = null;while((line = in.readLine()) != null) {mLogger.data("[ERR]" + line);}} catch (IOException e) {}}});// Start both threads// Then wait for them to complete// They will complete when the input is exhaustedt1.start();t2.start();t1.join();t2.join();session.close();exitCode = session.exitCode();if (exitCode == SshSession.EXITCODE_NOT_RECEIVED ){mLogger.info("Exit Code not received. Force zero");exitCode = 0;}mLogger.info("Exit Code:" + exitCode);}}ssh.disconnect();} catch (Throwable t) {t.printStackTrace();mLogger.info("Remote connection exception: " + t.getMessage());return -2;}}return exitCode;}}