extensions/net.sf.basedb.opengrid/trunk/src/net/sf/basedb/opengrid/AbstractHost.java

Code
Comments
Other
Rev Date Author Line
4278 20 Dec 16 nicklas 1 package net.sf.basedb.opengrid;
4278 20 Dec 16 nicklas 2
4278 20 Dec 16 nicklas 3 import java.io.IOException;
4278 20 Dec 16 nicklas 4
4278 20 Dec 16 nicklas 5 import org.slf4j.LoggerFactory;
4278 20 Dec 16 nicklas 6
4742 09 Apr 18 nicklas 7 import net.schmizz.sshj.Config;
4278 20 Dec 16 nicklas 8 import net.schmizz.sshj.SSHClient;
4742 09 Apr 18 nicklas 9 import net.schmizz.sshj.common.Factory;
4742 09 Apr 18 nicklas 10 import net.schmizz.sshj.common.SSHException;
4278 20 Dec 16 nicklas 11 import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
4742 09 Apr 18 nicklas 12 import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
4742 09 Apr 18 nicklas 13 import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
4742 09 Apr 18 nicklas 14 import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
4742 09 Apr 18 nicklas 15 import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil;
4742 09 Apr 18 nicklas 16 import net.schmizz.sshj.userauth.password.PasswordFinder;
4742 09 Apr 18 nicklas 17 import net.schmizz.sshj.userauth.password.PasswordUtils;
4450 10 Apr 17 nicklas 18 import net.sf.basedb.core.FileServer;
4278 20 Dec 16 nicklas 19 import net.sf.basedb.opengrid.config.ConnectionInfo;
7075 27 Mar 23 nicklas 20 import net.sf.basedb.opengrid.service.OpenGridService;
7075 27 Mar 23 nicklas 21 import net.sf.basedb.util.extensions.logging.ExtensionsLog;
7075 27 Mar 23 nicklas 22 import net.sf.basedb.util.extensions.logging.ExtensionsLogger;
4278 20 Dec 16 nicklas 23
4278 20 Dec 16 nicklas 24 /**
4278 20 Dec 16 nicklas 25   An abstract host that can be reached via SSH.
4278 20 Dec 16 nicklas 26   
4278 20 Dec 16 nicklas 27   @author nicklas
4278 20 Dec 16 nicklas 28   @since 1.0
4278 20 Dec 16 nicklas 29   @param <T> The type of sessions that are created when connecting to the host
4278 20 Dec 16 nicklas 30 */
4278 20 Dec 16 nicklas 31 public abstract class AbstractHost<T extends AbstractSession<?>>
4278 20 Dec 16 nicklas 32 {
4278 20 Dec 16 nicklas 33
7075 27 Mar 23 nicklas 34   private static final ExtensionsLogger logger = 
7075 27 Mar 23 nicklas 35     ExtensionsLog.getLogger(OpenGridService.ID, true).wrap(LoggerFactory.getLogger(AbstractHost.class));
4278 20 Dec 16 nicklas 36   
4278 20 Dec 16 nicklas 37   private final ConnectionInfo ci;
4278 20 Dec 16 nicklas 38   
4278 20 Dec 16 nicklas 39   protected AbstractHost(ConnectionInfo ci)
4278 20 Dec 16 nicklas 40   {
4278 20 Dec 16 nicklas 41     this.ci = ci.lock();
4278 20 Dec 16 nicklas 42   }
4278 20 Dec 16 nicklas 43   
4278 20 Dec 16 nicklas 44   /**
4278 20 Dec 16 nicklas 45     Get the connection information for this host.
4278 20 Dec 16 nicklas 46   */
4278 20 Dec 16 nicklas 47   public ConnectionInfo getConnectionInfo()
4278 20 Dec 16 nicklas 48   {
4278 20 Dec 16 nicklas 49     return ci;
4278 20 Dec 16 nicklas 50   }
4278 20 Dec 16 nicklas 51
4278 20 Dec 16 nicklas 52   /**
4278 20 Dec 16 nicklas 53     Connect to the cluster. The returned session can
4278 20 Dec 16 nicklas 54     be used to send commands or transfer files to/from
4278 20 Dec 16 nicklas 55     the cluster. Do not forget to {@link AbstractSession#close()}
4278 20 Dec 16 nicklas 56     the session after use.
4278 20 Dec 16 nicklas 57     
4278 20 Dec 16 nicklas 58     @param timeout Timeout in seconds for the connection to be established
4278 20 Dec 16 nicklas 59   */
4278 20 Dec 16 nicklas 60   public abstract T connect(int timeout);
4278 20 Dec 16 nicklas 61   
4278 20 Dec 16 nicklas 62   
4278 20 Dec 16 nicklas 63   protected SSHClient internalConnect(int timeout)
4278 20 Dec 16 nicklas 64   {
4278 20 Dec 16 nicklas 65     if (logger.isDebugEnabled())
4278 20 Dec 16 nicklas 66     {
4278 20 Dec 16 nicklas 67       logger.debug("Connecting to " + ci);
4278 20 Dec 16 nicklas 68     }
4278 20 Dec 16 nicklas 69     SSHClient ssh = null;
4278 20 Dec 16 nicklas 70     try
4278 20 Dec 16 nicklas 71     {
4278 20 Dec 16 nicklas 72       ssh = new SSHClient(SshUtil.SSH_CONFIG);
4278 20 Dec 16 nicklas 73       if (ci.getFingerPrint() == null)
4278 20 Dec 16 nicklas 74       {
4278 20 Dec 16 nicklas 75         ssh.addHostKeyVerifier(new PromiscuousVerifier());
4278 20 Dec 16 nicklas 76       }
4450 10 Apr 17 nicklas 77       else if (FileServer.FINGERPRINT_TYPE_MD5.equals(ci.getFingerPrintType()))
4278 20 Dec 16 nicklas 78       {
4278 20 Dec 16 nicklas 79         ssh.addHostKeyVerifier(ci.getFingerPrint());
4278 20 Dec 16 nicklas 80       }
4450 10 Apr 17 nicklas 81       else if (FileServer.FINGERPRINT_TYPE_SHA256.equals(ci.getFingerPrintType()))
4450 10 Apr 17 nicklas 82       {
4450 10 Apr 17 nicklas 83         ssh.addHostKeyVerifier(new Sha256Verifier(ci.getFingerPrint()));
4450 10 Apr 17 nicklas 84       }
4742 09 Apr 18 nicklas 85
4278 20 Dec 16 nicklas 86       ssh.setConnectTimeout(timeout * 1000);
4278 20 Dec 16 nicklas 87       ssh.connect(ci.getAddress(), ci.getPort());
4742 09 Apr 18 nicklas 88       
4742 09 Apr 18 nicklas 89       if (ci.getPrivateKey() != null)
4742 09 Apr 18 nicklas 90       {
4742 09 Apr 18 nicklas 91         if (logger.isDebugEnabled()) 
4742 09 Apr 18 nicklas 92         {
4742 09 Apr 18 nicklas 93           logger.debug("Using private key authentication");
4742 09 Apr 18 nicklas 94         }
4742 09 Apr 18 nicklas 95         KeyProvider kp = createFileKeyProvider(ssh.getTransport().getConfig(), 
4742 09 Apr 18 nicklas 96           ci.getPrivateKey(), ci.getPrivateKeyPassword(), ci.getPrivateKeyFormat());
4742 09 Apr 18 nicklas 97         ssh.authPublickey(ci.getUser(), kp);
4742 09 Apr 18 nicklas 98       }
4742 09 Apr 18 nicklas 99       else if (ci.getPassword() != null)
4742 09 Apr 18 nicklas 100       {
4742 09 Apr 18 nicklas 101         if (logger.isDebugEnabled()) 
4742 09 Apr 18 nicklas 102         {
4742 09 Apr 18 nicklas 103           logger.debug("Using password authentication");
4742 09 Apr 18 nicklas 104         }
4742 09 Apr 18 nicklas 105         ssh.authPassword(ci.getUser(), ci.getPassword());
4742 09 Apr 18 nicklas 106       }
4742 09 Apr 18 nicklas 107       
4278 20 Dec 16 nicklas 108       if (logger.isDebugEnabled())
4278 20 Dec 16 nicklas 109       {
4278 20 Dec 16 nicklas 110         logger.debug("Connected to " + ci);
4278 20 Dec 16 nicklas 111       }
4278 20 Dec 16 nicklas 112     }
4278 20 Dec 16 nicklas 113     catch (IOException ex)
4278 20 Dec 16 nicklas 114     {
4278 20 Dec 16 nicklas 115       logger.error("Connection to " + ci + " failed", ex);
4278 20 Dec 16 nicklas 116       OpenGrid.close(ssh);
7075 27 Mar 23 nicklas 117       throw new RuntimeException("Connection to " + ci + " failed", ex);
4278 20 Dec 16 nicklas 118     }
4278 20 Dec 16 nicklas 119     catch (RuntimeException ex)
4278 20 Dec 16 nicklas 120     {
4278 20 Dec 16 nicklas 121       logger.error("Connection to " + ci + " failed", ex);
4278 20 Dec 16 nicklas 122       OpenGrid.close(ssh);
4278 20 Dec 16 nicklas 123       throw ex;
4278 20 Dec 16 nicklas 124     }
4278 20 Dec 16 nicklas 125     return ssh;
4278 20 Dec 16 nicklas 126   }
4278 20 Dec 16 nicklas 127   
4278 20 Dec 16 nicklas 128   @Override
4278 20 Dec 16 nicklas 129   public String toString() 
4278 20 Dec 16 nicklas 130   {
4278 20 Dec 16 nicklas 131     return getClass().getSimpleName()+"["+getConnectionInfo().toString()+"]";
4278 20 Dec 16 nicklas 132   }
4278 20 Dec 16 nicklas 133
4742 09 Apr 18 nicklas 134   
4742 09 Apr 18 nicklas 135   /**
4742 09 Apr 18 nicklas 136     Create and initialize a private key provider. 
4742 09 Apr 18 nicklas 137     @param config Required since we get supported key file formats from this
4742 09 Apr 18 nicklas 138     @param privateKey The private key file as a string (required)
4742 09 Apr 18 nicklas 139     @param password Optional
4742 09 Apr 18 nicklas 140     @param format Optional (if not specified, auto-detection will be attempted)
4742 09 Apr 18 nicklas 141   */
4742 09 Apr 18 nicklas 142   private KeyProvider createFileKeyProvider(Config config, String privateKey, String password, String format)
4742 09 Apr 18 nicklas 143     throws SSHException, IOException
4742 09 Apr 18 nicklas 144   {
4742 09 Apr 18 nicklas 145     if (format == null)
4742 09 Apr 18 nicklas 146     {
4742 09 Apr 18 nicklas 147       if (logger.isDebugEnabled()) logger.debug("Auto-detecting private key format");
4742 09 Apr 18 nicklas 148       // No format specified, try auto-detecting which is supported for PuTTY and OpenSSH
4742 09 Apr 18 nicklas 149       KeyFormat kf = KeyProviderUtil.detectKeyFileFormat(privateKey, true);
4742 09 Apr 18 nicklas 150       if (kf == null || kf == KeyFormat.Unknown) 
4742 09 Apr 18 nicklas 151       {
4742 09 Apr 18 nicklas 152         throw new SSHException("Could not detect format of private key");
4742 09 Apr 18 nicklas 153       }
4742 09 Apr 18 nicklas 154       format = kf.toString();
4742 09 Apr 18 nicklas 155       if (logger.isDebugEnabled()) logger.debug("Auto-detecting private key format: " + format);
4742 09 Apr 18 nicklas 156     }
4742 09 Apr 18 nicklas 157     
4742 09 Apr 18 nicklas 158     FileKeyProvider provider = Factory.Named.Util.create(config.getFileKeyProviderFactories(), format);
4742 09 Apr 18 nicklas 159     if (provider == null)
4742 09 Apr 18 nicklas 160     {
4742 09 Apr 18 nicklas 161       throw new SSHException("No provider available for '" + format + "' key file format");
4742 09 Apr 18 nicklas 162     }
4742 09 Apr 18 nicklas 163
4742 09 Apr 18 nicklas 164     PasswordFinder pwd = password == null ? null : PasswordUtils.createOneOff(password.toCharArray());
4742 09 Apr 18 nicklas 165     provider.init(privateKey, null, pwd);
4742 09 Apr 18 nicklas 166     try
4742 09 Apr 18 nicklas 167     {
4742 09 Apr 18 nicklas 168       // Try to get the private key here to catch problems early and get better error messages for the user
4742 09 Apr 18 nicklas 169       provider.getPrivate();
4742 09 Apr 18 nicklas 170     }
4742 09 Apr 18 nicklas 171     catch (RuntimeException ex)
4742 09 Apr 18 nicklas 172     {
4742 09 Apr 18 nicklas 173       String msg = "Invalid '" + format + "' private key";
4742 09 Apr 18 nicklas 174       if (ex.getMessage() != null) msg += " (" + ex.getMessage() + ")";
4742 09 Apr 18 nicklas 175       throw new SSHException(msg, ex);
4742 09 Apr 18 nicklas 176     }
4742 09 Apr 18 nicklas 177     
4742 09 Apr 18 nicklas 178     return provider;
4742 09 Apr 18 nicklas 179   }
4742 09 Apr 18 nicklas 180   
4278 20 Dec 16 nicklas 181 }