Subversion Repositories DevTools

Rev

Rev 6914 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6914 dpurdie 1
/**	This class handles remote execution of programs
2
 *  It is only used by the build daemons
3
 *  It is not used in Escrow
4
 *  
5
 *  It is used by the master build thread as well as the ABT instance created
6
 *  by the master build thread.
7
 * 
8
 */
9
 
10
package com.erggroup.buildtool.abt;
11
 
12
import java.io.BufferedReader;
13
import java.io.File;
14
import java.io.FileInputStream;
15
import java.io.IOException;
16
import java.io.InputStream;
17
import java.io.InputStreamReader;
18
import java.util.Properties;
19
 
20
import com.sshtools.net.SocketTransport;
21
import com.sshtools.ssh.PasswordAuthentication;
22
import com.sshtools.ssh.SshAuthentication;
23
import com.sshtools.ssh.SshClient;
24
import com.sshtools.ssh.SshConnector;
25
import com.sshtools.ssh.SshSession;
26
import com.sshtools.ssh2.Ssh2Context;
27
 
28
public class RemoteExecution {
29
 
30
	/**
31
	 * 	Interface to assist in logging the output of the remote executor
32
	 * 	Required as the class is called in two contexts
33
	 * 		1) By the build daemon - where logging is to an mLogger
34
	 * 		2) Within ABT - where logging is via ant
35
	 */
36
	public interface LogOutput{
37
	    void data(String message);		// Log data from the command
38
	    void info(String message);		// Log Info from the class
39
	    void fatal(String message);		// Log fatal messages
40
	}
41
 
42
	/**
43
	 * Name or Address of the target machine
44
	 * 
45
	 */
46
	private String mTargetMachine;
47
 
48
	/**
49
	 * User name
50
	 */
51
	private String mUserName;
52
 
53
	/**
54
	 * Password
55
	 */
56
	private String mPassword;
57
 
58
	/** Logger
59
	 * 
60
	 */
61
	LogOutput mLogger;
62
 
63
	/**
64
	 * Constructor
65
	 * @param logger 
66
	 */
67
	public RemoteExecution(LogOutput logger)
68
	{
69
		mLogger = logger;
70
	}
71
 
72
	/**Determine the connection credentials
73
	 * These are held in a properties file
74
	 * 
75
	 * @return true - we have credentials
76
	 */
77
	public boolean getCredentials()
78
	{
79
		InputStream input;
80
		Properties prop;
81
		String credentialsFile = System.getenv("GBE_DPKG_SSH_PROPERTIES");
82
		if (credentialsFile == null)
83
		{
84
			mLogger.fatal("Packager Server SSH credendials. Location Not specified");
85
			return false;
86
		}
87
 
88
		File propFile = new File(credentialsFile);
89
		if (!propFile.isFile())
90
		{
91
			mLogger.fatal("Packager Server SSH credendials. Is not a file: " + credentialsFile);
92
			return false;
93
		}
94
 
95
		try {
96
			input = new FileInputStream(propFile);
97
 
98
			prop = new Properties();
99
			prop.load(input);
100
 
101
		} catch (IOException e) {
102
			mLogger.fatal("Packager Server SSH credendials. Cannot open: " + credentialsFile + ". Error: " + e.getMessage());
103
			return false;
104
		}
105
 
106
		mTargetMachine = prop.getProperty("ssh_server");
107
		mUserName = prop.getProperty("ssh_user");
108
		mPassword = prop.getProperty("ssh_password");
109
 
110
		if ( mTargetMachine == null || mUserName == null || mPassword == null )
111
		{
112
			mLogger.fatal("Packager Server SSH credendials. Not all properties found");
113
			return false;
114
		}
115
 
116
		return true;
117
	}
118
 
119
 
120
	/**
121
	 * Test the connection to the target machine
122
	 * Used each build cycle to report if the target machine is not
123
	 * available.
124
	 * @param mLogger 		- Logger to use for notification of errors
125
	 * 
126
	 *  @return	true - if the connection was successfully established
127
	 */
128
	public boolean testConnection()
129
	{
130
		int	exitCode = -1;
131
 
132
		mLogger.info("Test remote execution authentication");
133
		exitCode = execute(null);
134
		mLogger.info("Test remote execution authentication complete");
135
		return exitCode == 0;
136
	}
137
 
138
	/**
139
	 * Execute command
140
	 * @param   command	- Command string to be processed. May be null or of zero length
141
	 * 
142
	 * @return  command exit code if positive
143
	 *          <br>internal exist code if negative
144
	 *          <br>zero - command executed correctly
145
	 * 
146
	 */
147
	public int execute(final String command)
148
	{
149
		int	exitCode = -1;
150
		if (getCredentials())
151
		{
152
			try {
153
 
154
				/**
155
				 * Create an SshConnector instance
156
				 */
157
				SshConnector con = SshConnector.createInstance();
158
				con.getContext().setPreferredPublicKey(Ssh2Context.PUBLIC_KEY_SSHDSS);
159
 
160
				/**
161
				 * Connect to the host
162
				 */
163
				final SshClient ssh = con.connect(new SocketTransport(mTargetMachine, 22), mUserName, true);
164
 
165
				/**
166
				 * Authenticate the user using password authentication
167
				 */
168
				PasswordAuthentication pwd = new PasswordAuthentication();
169
				pwd.setPassword(mPassword);
170
 
171
				if( ssh.authenticate(pwd) != SshAuthentication.COMPLETE && ssh.isConnected())
172
				{
173
					mLogger.fatal("Connection to \"" + mTargetMachine + "\" not authenticated");
174
					return -1;
175
				}
176
 
177
				/**
178
				 * Start a session send a command and read the commands output
179
				 */
180
				if (ssh.isAuthenticated()) {
181
 
182
					exitCode = 0;
183
					if ( command != null && command.length() > 0)
184
					{
185
						final SshSession session = ssh.openSessionChannel();
186
						session.executeCommand(command);
187
 
188
						//	Create two thread
189
						//	One to read stdout and one to read stderr
190
						//
191
						Thread t1 = new Thread(new Runnable(){
192
							public void run(){
193
								try {
194
									BufferedReader in = new BufferedReader(new InputStreamReader(session.getInputStream()));
195
									String line = null;
196
									while((line = in.readLine()) != null) {
197
										mLogger.data(line);
198
									}
199
								} catch (IOException e) {
200
								}
201
							}
202
						});
203
						Thread t2 = new Thread(new Runnable(){
204
							public void run(){
205
								try {
206
									BufferedReader in = new BufferedReader(new InputStreamReader(session.getStderrInputStream()));
207
									String line = null;
208
									while((line = in.readLine()) != null) {
209
										mLogger.data("[ERR]" + line);
210
									}
211
								} catch (IOException e) {
212
								}
213
							}
214
						});
215
 
216
						//	Start both threads
217
						//	Then wait for them to complete
218
						//	They will complete when the input is exhausted
219
						t1.start();
220
						t2.start();
221
 
222
						t1.join();
223
						t2.join();
224
 
225
		                session.close();
226
		                exitCode = session.exitCode();
227
		                if (exitCode ==  SshSession.EXITCODE_NOT_RECEIVED )
228
		                {
229
		                    mLogger.info("Exit Code not received. Force zero");
230
		                    exitCode = 0;
231
		                }
232
						mLogger.info("Exit Code:" + exitCode);
233
					}
234
				}
235
 
236
				ssh.disconnect();
237
			} catch (Throwable t) {
238
				t.printStackTrace();
239
				mLogger.info("Remote connection exception: " + t.getMessage());
240
				return -2;
241
			}
242
		}
243
 
244
		return exitCode;
245
	}
246
 
247
}