From: <st...@us...> - 2008-01-31 23:00:03
|
Revision: 5840 http://smartfrog.svn.sourceforge.net/smartfrog/?rev=5840&view=rev Author: steve_l Date: 2008-01-31 14:59:57 -0800 (Thu, 31 Jan 2008) Log Message: ----------- SFOS 634 remove failonerror attribute from Ssh components SFOS-615 SSH errors aren't that helpful SFOS-641 add ability to specify connect timeout for an ssh connection with the connectTimeout attribute SFOS-641 add ability to specify connect timeout for an ssh connection with the connectTimeout attribute SFOS-635 SshExec operations should be asynchronous SFOS-642 Hook jsch logging up to SmartFrog logger Modified Paths: -------------- trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractSSHComponent.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractScpOperation.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHComponent.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExec.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExecImpl.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponent.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponentImpl.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpFrom.java trunk/core/components/ssh/src/org/smartfrog/services/ssh/scp.sf trunk/core/components/ssh/src/org/smartfrog/services/ssh/sshexecute.sf Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractSSHComponent.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractSSHComponent.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractSSHComponent.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -51,19 +51,26 @@ protected UserInfoImpl userInfo; private static final Reference pwdProviderRef = new Reference(SSHComponent.ATTR_PASSWORD_PROVIDER); protected boolean trustAllCerts = true; - protected static final String TIMEOUT_MESSAGE = "Connection timed out connecting to "; private static final int SSH_PORT = 22; protected int timeout = 0; + protected int connectTimeout = 0; protected String host; protected int port = SSH_PORT; - - protected boolean shouldTerminate = true; protected String userName; protected Vector knownHosts; + private volatile Session session = null; + + protected static final String TIMEOUT_MESSAGE = "Connection timed out connecting to "; protected static final String SESSION_IS_DOWN = "session is down"; + private static final String AUTH_FAIL = "Auth fail"; + private static final String AUTH_CANCEL = "Auth cancel"; + /** + * Only subclasses can instantiate this + * @throws RemoteException if the superclass constructor raises it + */ protected AbstractSSHComponent() throws RemoteException { } @@ -95,7 +102,8 @@ } else if (AUTHENTICATION_PASSWORD.equals(policy)) { usePublicKey = false; } else { - throw new SmartFrogResolutionException("Unsupported value for attribute " + ATTR_AUTHENTICATION + ": " + policy); + throw new SmartFrogResolutionException("Unsupported value for attribute " + + ATTR_AUTHENTICATION + ": " + policy); } // Mandatory attributes @@ -118,11 +126,10 @@ userInfo.setName(userName); host = sfResolve(ATTR_HOST, host, true); - shouldTerminate = sfResolve(ATTR_SHOULD_TERMINATE, shouldTerminate, false); port = sfResolve(ATTR_PORT, port, true); - //optional attributes - timeout = sfResolve(ATTR_TIMEOUT, timeout, false); + timeout = sfResolve(ATTR_TIMEOUT, timeout, true); + connectTimeout = sfResolve(ATTR_CONNECT_TIMEOUT, connectTimeout, true); knownHosts = sfResolve(ATTR_KNOWN_HOSTS,knownHosts,false); } @@ -140,15 +147,6 @@ } /** - * Logs ignored exception - * - * @param e debug message - */ - private void ignore(Exception e) { - log.ignore("Ignoring Exception", e); - } - - /** * Create a JSch connection using the current security policies. * * @return a jsch instance which will have any keyfile settings applied @@ -159,6 +157,8 @@ if (usePublicKey) { jsch.addIdentity(keyFile); } + //set the logger up to our logging. + JSch.setLogger(new JschLogger(log)); return jsch; } @@ -172,10 +172,10 @@ */ protected Session openSession() throws JSchException { JSch jsch = createJschInstance(); - Session session = createSession(jsch); - session.setTimeout(timeout); - session.connect(); - return session; + Session newSession = createSession(jsch); + newSession.setTimeout(timeout); + newSession.connect(connectTimeout); + return newSession; } /** @@ -186,14 +186,14 @@ * @throws JSchException if things go wrong */ protected Session createSession(JSch jsch) throws JSchException { - Session session; - session = jsch.getSession(userInfo.getName(), host, port); - session.setUserInfo(userInfo); + Session newSession; + newSession = jsch.getSession(userInfo.getName(), host, port); + newSession.setUserInfo(userInfo); if(!usePublicKey) { - session.setPassword(userInfo.getPassword()); + newSession.setPassword(userInfo.getPassword()); } log.info("Connecting to " + getConnectionDetails()); - return session; + return newSession; } /** @@ -201,7 +201,7 @@ * @return the connection info */ public String getConnectionDetails() { - return host + ":" + port + " as " + userInfo; + return host + ':' + port + " as " + userInfo; } /** @@ -237,17 +237,47 @@ } /** - * Translate + * Translate an exception into a SmartFrogLifecycle one. + * IF the exception is a JSchException, it is left to + * {@link #translateStartupException(JSchException)} to handle + * @param thrown incoming exception + * @return a lifecycle exception + */ + protected SmartFrogLifecycleException forward(Throwable thrown) { + if(thrown instanceof JSchException) { + return translateStartupException((JSchException) thrown); + } else { + return (SmartFrogLifecycleException) SmartFrogLifecycleException.forward(thrown); + } + } + + + /** + * Translate a jsch exception into a SmartFrog one, including better diagnostics. + * This is brittle as it searches for specific error text in the exception. * @param ex incoming exception * @return a new lifecycle exception that includes connection details */ - public SmartFrogLifecycleException translateStartupException(JSchException ex) { - log.error("When connecting to " + getConnectionDetails(), ex); - if (ex.getMessage().indexOf(SESSION_IS_DOWN) >= 0) { - String message = TIMEOUT_MESSAGE + getConnectionDetails(); - return new SmartFrogLifecycleException(message, ex); + protected SmartFrogLifecycleException translateStartupException(JSchException ex) { + String message; + String faulttext = ex.getMessage(); + if (faulttext.contains(SESSION_IS_DOWN)) { + message = TIMEOUT_MESSAGE + getConnectionDetails(); + } else if (faulttext.contains(AUTH_FAIL) || faulttext.contains(AUTH_CANCEL)) { + message = "Unable to authenticate with the far end" + getConnectionDetails() + + "\nThis can be caused by: " + + "\n -Unknown username "+userName + + "\n -wrong password" + + (usePublicKey? + "\n -key-based authentication failure": + "\n -server not supporting password authentication") + + (trustAllCerts? + "\n -server not trusted": + "") + + "\n -server not supporting login by that user"; } else { - return new SmartFrogLifecycleException(getConnectionDetails()+" -"+ex.getMessage(),ex); + message=getConnectionDetails()+" -"+ faulttext; } + return new SmartFrogLifecycleException(message, ex); } } Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractScpOperation.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractScpOperation.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/AbstractScpOperation.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -37,6 +37,9 @@ protected final int BUFFER_SIZE = 1024; protected LogSF log; + /** + * This flag is set to halt a child thread at work + */ protected volatile boolean haltOperation=false; /** Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHComponent.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHComponent.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHComponent.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -63,6 +63,11 @@ */ String ATTR_TIMEOUT = "timeout"; /** + * Waits at most millis milliseconds for this operation to finish. A timeout + * of 0 means to wait forever. {@value} + */ + String ATTR_CONNECT_TIMEOUT = "connectTimeout"; + /** * {@value} */ String ATTR_TRUST_ALL_CERTIFICATES = "trustAllCertificates"; @@ -89,11 +94,6 @@ * {@value} */ - String ATTR_SHOULD_TERMINATE = ShouldDetachOrTerminate.ATTR_SHOULD_TERMINATE; - /** - * {@value} - */ - String ATTR_LOG_FILE = "logFile"; /** Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExec.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExec.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExec.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -28,10 +28,14 @@ /** * {@value} */ - public static String ATTR_COMMANDS = "commands"; + String ATTR_COMMANDS = "commands"; /** * {@value} */ - String ATTR_RESULT_RANGE = "resultRange"; + String ATTR_EXIT_CODE_MIN = "exitCodeMin"; + /** + * {@value} + */ + String ATTR_EXIT_CODE_MAX = "exitCodeMax"; } Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExecImpl.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExecImpl.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/SSHExecImpl.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -1,3 +1,43 @@ +/** (C) Copyright 2007 Hewlett-Packard Development Company, LP + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For more information: www.smartfrog.org + + */ + +//some of this code looks just like the apache Ant sshexec task +//unless/until it gets reworked, they need credit too. +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package org.smartfrog.services.ssh; import com.jcraft.jsch.ChannelShell; @@ -5,7 +45,9 @@ import com.jcraft.jsch.Session; import org.smartfrog.sfcore.common.SmartFrogException; import org.smartfrog.sfcore.common.SmartFrogLifecycleException; +import org.smartfrog.sfcore.common.SmartFrogLivenessException; import org.smartfrog.sfcore.prim.TerminationRecord; +import org.smartfrog.sfcore.prim.Liveness; import org.smartfrog.sfcore.utils.SmartFrogThread; import org.smartfrog.sfcore.utils.ComponentHelper; import org.smartfrog.sfcore.utils.ListUtils; @@ -15,23 +57,27 @@ import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.rmi.RemoteException; import java.util.Vector; /** - * SmartFrog component to executes a command on a remote machine via ssh. It is a wrapper around jsch + * SmartFrog component to executes a command on a remote machine via ssh. It is + * a wrapper around jsch + * <p/> + * Super class for SSH component implementaion for user/password and + * public/private key authentication mechanisms. * - * Super class for SSH component implementaion for user/password and public/private key authentication mechanisms. - * * @author Ritu Sabharwal * @see <a href="http://www.jcraft.com/jsch/">jsch</a> */ public class SSHExecImpl extends AbstractSSHComponent implements SSHExec { - private FileOutputStream fout = null; - protected Vector<String> commandsList; - private SmartFrogThread waitThread = null; - protected File logFile = null; + private Vector<String> commandsList; + private File logFile = null; + private int exitCodeMax, exitCodeMin; + private CommandExecutor executorThread; + private static final int THREAD_SHUTDOWN_TIME = 1000; /** * Create an instance @@ -44,7 +90,8 @@ /** * Reads SmartFrog attributes and deploys SSHExecImpl component. * - * @throws SmartFrogException in case of error in deploying or reading the attributes + * @throws SmartFrogException in case of error in deploying or reading the + * attributes * @throws RemoteException in case of network/emi error */ public synchronized void sfDeploy() throws SmartFrogException, @@ -54,97 +101,48 @@ } - /** * Connects to remote host over SSH and executes commands. * - * @throws SmartFrogException in case of error while connecting to remote host or executing commands + * @throws SmartFrogException in case of error while connecting to remote + * host or executing commands * @throws RemoteException in case of network/emi error */ public synchronized void sfStart() throws SmartFrogException, RemoteException { super.sfStart(); - ChannelShell channel = null; - try { - // open ssh session - logDebugMsg("Getting SSH Session"); - Session newsession = openSession(); - setSession(newsession); + executorThread = new CommandExecutor(); + executorThread.start(); + } - if (logFile != null) { - fout = new FileOutputStream(logFile, false); - } - // Execute commands + /** + * {@inheritDoc} + * + * @param source source of call + * + * @throws SmartFrogLivenessException component is terminated + * @throws RemoteException for consistency with the {@link Liveness} + * interface + */ + public void sfPing(Object source) + throws SmartFrogLivenessException, RemoteException { + super.sfPing(source); + SmartFrogThread.ping(executorThread); + } - StringBuilder buffer = new StringBuilder(); - for (Object aCommandsList : commandsList) { - String cmd = aCommandsList.toString(); - buffer.append(cmd); - buffer.append("\n"); - } - - byte[] bytes = buffer.toString().getBytes(); - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - - channel = (ChannelShell) getSession().openChannel("shell"); - channel.setOutputStream(fout); - channel.setExtOutputStream(fout); - channel.setInputStream(bais); - channel.connect(); - - log.info("Executing commands:" + buffer.toString()); - - // wait for it to finish - waitThread = new WaitForEndOfChannel(channel); - - waitThread.start(); - waitThread.join(timeout); - - if (waitThread.isAlive()) { - // ran out of time - waitThread = null; - String message = TIMEOUT_MESSAGE + getConnectionDetails(); - log.error(message); - throw new SmartFrogLifecycleException(message); - } else { - int exitStat = channel.getExitStatus(); - if (exitStat != 0) { - String msg = "Remote commands to " + getConnectionDetails() + - " failed with exit status " + exitStat; - throw new SmartFrogLifecycleException(msg); - } - } - waitThread = null; - - // check if it should terminate by itself - log.info("Normal termination :" + sfCompleteNameSafe()); - TerminationRecord termR = TerminationRecord.normal( - "SSH Session to "+getConnectionDetails()+" finished: ", - sfCompleteName()); - new ComponentHelper(this).sfSelfDetachAndOrTerminate(termR); - } catch (SmartFrogException sfe) { - throw sfe; - } catch (JSchException e) { - log.error("When connecting to " + getConnectionDetails(),e); - throw translateStartupException(e); - } catch (Exception e) { - if (log.isTraceEnabled()) { - log.trace(e); - } - throw SmartFrogLifecycleException.sfStart("When connecting to " + getConnectionDetails(),e,this); - } finally { - //clean up time - if(channel!=null) { - channel.disconnect(); - } else { - //if there's no channel, we may not have closed the output stream - FileSystem.close(fout); - } - } + /** + * Terminate any worker thread during shutdown + * + * @param tr Termination record + */ + public synchronized void sfTerminateWith(TerminationRecord tr) { + SmartFrogThread.requestAndWaitForThreadTermination(executorThread, + THREAD_SHUTDOWN_TIME); + //this will close the session, so we hope that the thread has finished. + super.sfTerminateWith(tr); } - /** * Reads SmartFrog attributes. * @@ -152,32 +150,128 @@ * attribute is not defined. * @throws RemoteException in case of network/rmi error */ - protected void readSFAttributes() throws SmartFrogException, RemoteException { + protected void readSFAttributes() + throws SmartFrogException, RemoteException { // Mandatory attributes - commandsList = ListUtils.resolveStringList(this,new Reference(ATTR_COMMANDS),true); + commandsList = ListUtils.resolveStringList(this, + new Reference(ATTR_COMMANDS), + true); //optional attributes - logFile = FileSystem.lookupAbsoluteFile(this,ATTR_LOG_FILE,logFile,null,false,null); + logFile = FileSystem.lookupAbsoluteFile(this, + ATTR_LOG_FILE, + logFile, + null, + false, + null); + + exitCodeMax = sfResolve(ATTR_EXIT_CODE_MAX, exitCodeMax, true); + exitCodeMin = sfResolve(ATTR_EXIT_CODE_MIN, exitCodeMin, true); } /** - * Thread to wait for the end of the channel. + * This thread executes commands down an SSH channel */ - private class WaitForEndOfChannel extends SmartFrogThread { - private final ChannelShell channel; + private class CommandExecutor extends SmartFrogThread { - private WaitForEndOfChannel(ChannelShell channel) { - this.channel = channel; - } + private static final int SPIN_DELAY_MILLIS = 500; + @Override public void execute() throws Throwable { - while (!channel.isEOF()) { - if (waitThread == null) { + ChannelShell channel = null; + FileOutputStream fout=null; + ComponentHelper helper = new ComponentHelper(SSHExecImpl.this); + String sessionInfo = "SSH Session to " + getConnectionDetails(); + try { + //start the logging + if (logFile != null) { + try { + fout = new FileOutputStream(logFile, false); + } catch (FileNotFoundException e) { + throw new SmartFrogLifecycleException( + sessionInfo + " failed to create log file " + + logFile, + e); + } + } + // open ssh session + logDebugMsg(sessionInfo); + Session newsession = openSession(); + setSession(newsession); + + // Execute commands + + StringBuilder buffer = new StringBuilder(); + for (Object aCommandsList : commandsList) { + String cmd = aCommandsList.toString(); + buffer.append(cmd); + buffer.append('\n'); + } + + byte[] bytes = buffer.toString().getBytes(); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + + channel = (ChannelShell) getSession().openChannel("shell"); + channel.setOutputStream(fout); + channel.setExtOutputStream(fout); + channel.setInputStream(bais); + channel.connect(); + + log.info("Executing commands:" + buffer.toString()); + + // wait for it to finish. This is pretty ugly + long timeLimit=System.currentTimeMillis()+timeout; + while (!channel.isEOF() && !isTerminationRequested()) { + long now= System.currentTimeMillis(); + if(timeout>0 && now>timeLimit) { + //we have a timeout + String message = TIMEOUT_MESSAGE + getConnectionDetails(); + log.error(message); + throw new SmartFrogLifecycleException(message); + } + sleep(SPIN_DELAY_MILLIS); + } + + if(isTerminationRequested()) { + //we've been asked to die return; } - sleep(500); + + int exitCode = channel.getExitStatus(); + if (exitCode < exitCodeMin || exitCode > exitCodeMax) { + String msg = sessionInfo + + " failed with exit status " + exitCode + + " out of the range [" + + exitCodeMin + + ',' + exitCodeMax + ']'; + throw new SmartFrogLifecycleException(msg); + } + + // check if it should terminate by itself + if (!isTerminationRequested()) { + log.info("Normal termination :" + sfCompleteNameSafe()); + TerminationRecord termR = TerminationRecord.normal( + sessionInfo + " finished: ", + sfCompleteName()); + helper.sfSelfDetachAndOrTerminate(termR); + } + } catch (Throwable ex) { + SmartFrogLifecycleException lifecycleException = forward(ex); + log.error(sessionInfo, lifecycleException); + TerminationRecord tr = helper.createTerminationRecord(null, + sessionInfo,sfCompleteName(), lifecycleException); + helper.targetForWorkflowTermination(tr); + throw lifecycleException; + } finally { + //clean up time + if (channel != null) { + channel.disconnect(); + } else { + //if there's no channel, we may not have closed the output stream + FileSystem.close(fout); + } } } } Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponent.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponent.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponent.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -39,9 +39,6 @@ * {@value} */ String TRANSFER_TYPE = "transferType"; - /** - * {@value} - */ - String RECURSIVE = "recursive"; + } Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponentImpl.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponentImpl.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpComponentImpl.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -1,4 +1,4 @@ -/** (C) Copyright 1998-2004 Hewlett-Packard Development Company, LP +/* (C) Copyright 1998-2008 Hewlett-Packard Development Company, LP This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,6 +17,8 @@ For more information: www.smartfrog.org */ + + package org.smartfrog.services.ssh; import com.jcraft.jsch.JSchException; @@ -45,7 +47,6 @@ */ public class ScpComponentImpl extends AbstractSSHComponent implements ScpComponent { - private static final boolean DIRECTORIES_SUPPORTED=false; private static final String GET = "get"; private static final String PUT = "put"; /** @@ -114,7 +115,7 @@ if (getFiles) { //verify that the remote file list is not empty for (File file : localFiles) { - if (!DIRECTORIES_SUPPORTED && file.exists() && file.isDirectory()) { + if (file.exists() && file.isDirectory()) { throw new SmartFrogLifecycleException(ERROR_OUTPUT_IS_A_DIRECTORY + file); } } @@ -123,7 +124,7 @@ if (!file.exists()) { throw new SmartFrogLifecycleException(ERROR_MISSING_FILE_TO_UPLOAD + file); } - if (!DIRECTORIES_SUPPORTED && !file.isFile()) { + if (!file.isFile()) { throw new SmartFrogLifecycleException(ERROR_NOT_A_NORMAL_FILE + file); } } @@ -143,11 +144,7 @@ */ public void sfPing(Object source) throws SmartFrogLivenessException, RemoteException { super.sfPing(source); - synchronized(this) { - if(worker!=null) { - worker.ping(true); - } - } + SmartFrogThread.ping(worker); } /** @@ -224,6 +221,8 @@ } } + + /** * If this thread was constructed using a separate {@link Runnable} run object, then that <code>Runnable</code> * object's <code>run</code> method is called; otherwise, this method does nothing and returns. <p> Subclasses @@ -231,8 +230,7 @@ * * @throws Throwable if anything went wrong */ - public void run() { - try { + public void execute() throws Throwable { try { if (localFiles.size() > 0) { // open ssh session @@ -261,14 +259,26 @@ } finally { operation = null; } - } catch (Throwable thrown) { - setThrown(thrown); - TerminationRecord record = TerminationRecord.abnormal("SCP failed to connect to " - + getConnectionDetails(),sfCompleteNameSafe(),thrown); + } + + /** + * Runs the {@link #execute()} method, catching any exception it throws and + * storing it away for safe keeping. + * After the run, the notify object is notified and the component + * then gets to terminated if there was an error. + */ + public void run() { + super.run(); + if(getThrown()!=null) { + TerminationRecord record = TerminationRecord.abnormal( + "SCP failed to connect to " + + getConnectionDetails(), + sfCompleteNameSafe(), + getThrown()); sfTerminate(record); } + } - } } } Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpFrom.java =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpFrom.java 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/ScpFrom.java 2008-01-31 22:59:57 UTC (rev 5840) @@ -153,9 +153,10 @@ OutputStream out, InputStream in) throws IOException { byte[] buf = new byte[BUFFER_SIZE]; - FileOutputStream fos = new FileOutputStream(localFile); + FileOutputStream fos=null; int bytesRead; try { + fos = new FileOutputStream(localFile); while (true) { // read file in the chunk of 1 kb bytesRead = in.read(buf, 0, Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/scp.sf =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/scp.sf 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/scp.sf 2008-01-31 22:59:57 UTC (rev 5840) @@ -37,7 +37,7 @@ */ ScpOperation extends SSHComponent { sfClass "org.smartfrog.services.ssh.ScpComponentImpl"; - sshSchema extends ScpSchema; + //sshSchema extends ScpSchema; //get files from the remote server get_files "GET"; @@ -84,7 +84,6 @@ transferType PARENT:ATTRIB transferType; localFiles PARENT:ATTRIB localFiles; remoteFiles PARENT:ATTRIB remoteFiles; - resultRange PARENT:ATTRIB:resultRange; } } @@ -97,7 +96,7 @@ passwordFile TBD; passwordProvider extends FilePassword { - passwordFile LAZY PARENT:passwordFile; + passwordFile LAZY PARENT:ATTRIB passwordFile; } } @@ -107,7 +106,7 @@ ScpSessionInlinePassword extends ScpSessionAuthPass { password TBD; passwordProvider extends InlinePassword { - password LAZY PARENT:ATTRIB password; + password PARENT:ATTRIB password; } } @@ -129,7 +128,7 @@ passwordFile TBD; passwordProvider extends FilePassword { - passwordFile LAZY PARENT:passwordFile; + passwordFile LAZY PARENT:ATTRIB passwordFile; } } @@ -141,7 +140,7 @@ ScpSessionPublicKeyInlinePassword extends ScpSessionPublicKey { password TBD; passwordProvider extends InlinePassword { - password LAZY PARENT:ATTRIB password; + password PARENT:ATTRIB password; } } Modified: trunk/core/components/ssh/src/org/smartfrog/services/ssh/sshexecute.sf =================================================================== --- trunk/core/components/ssh/src/org/smartfrog/services/ssh/sshexecute.sf 2008-01-31 22:55:05 UTC (rev 5839) +++ trunk/core/components/ssh/src/org/smartfrog/services/ssh/sshexecute.sf 2008-01-31 22:59:57 UTC (rev 5840) @@ -32,12 +32,15 @@ sshSchema extends SSHComponentSchema { commands extends OptionalVector; logFile extends OptionalFilenameType; - //a tuple of min-max values - resultRange extends Vector; + //min-max values for the response + exitCodeMin extends Integer; + exitCodeMax extends Integer; } authentication SSHComponent:authenticate_password; - resultRange [0,0]; - + exitCodeMax 0; + exitCodeMin 0; + //the component terminates at the end of deployment, by default + sfShouldTerminate true; } @@ -55,7 +58,8 @@ port SSHExec:port; timeout SSHExec:timeout; commands []; - resultRange SSHExec:resultRange; + exitCodeMax 0; + exitCodeMin 0; SSHCmdExec extends SSHExec { @@ -71,7 +75,8 @@ port PARENT:ATTRIB port; // terminate if any command fails - resultRange PARENT:ATTRIB:resultRange; + exitCodeMax PARENT:ATTRIB exitCodeMax; + exitCodeMin PARENT:ATTRIB exitCodeMin; //the commands commands PARENT:ATTRIB commands ; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |