Merge of new rebased code
[appc.git] / appc-adapters / appc-ssh-adapter / appc-ssh-adapter-sshd / src / main / java / org / openecomp / appc / adapter / ssh / sshd / SshConnectionSshd.java
index 4d8b83b..e87bfa2 100644 (file)
 
 package org.openecomp.appc.adapter.ssh.sshd;
 
+import org.openecomp.appc.adapter.ssh.Constants;
+import org.openecomp.appc.adapter.ssh.SshConnection;
+import org.openecomp.appc.adapter.ssh.SshException;
+import org.openecomp.appc.encryption.EncryptionTool;
+import org.openecomp.appc.configuration.Configuration;
+import org.openecomp.appc.configuration.ConfigurationFactory;
 import org.apache.sshd.ClientChannel;
 import org.apache.sshd.ClientSession;
 import org.apache.sshd.SshClient;
@@ -29,9 +35,7 @@ import org.apache.sshd.client.future.AuthFuture;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
-import org.openecomp.appc.adapter.ssh.SshConnection;
-import org.openecomp.appc.adapter.ssh.SshException;
-import org.openecomp.appc.encryption.EncryptionTool;
+
 import com.att.eelf.configuration.EELFLogger;
 import com.att.eelf.configuration.EELFManager;
 
@@ -43,130 +47,187 @@ import java.security.KeyPair;
  */
 class SshConnectionSshd implements SshConnection {
 
-       private static final EELFLogger logger = EELFManager.getInstance().getApplicationLogger();
-
-       private static final long AUTH_TIMEOUT = 60000;
-       private static final long EXEC_TIMEOUT = 120000;
-
-       private String host;
-       private int port;
-       private String username;
-       private String password;
-       private long timeout = EXEC_TIMEOUT;
-       private String keyFile;
-       private SshClient sshClient;
-       private ClientSession clientSession;
-
-       public SshConnectionSshd(String host, int port, String username, String password, String keyFile) {
-               this.host = host;
-               this.port = port;
-               this.username = username;
-               this.password = password;
-               this.keyFile = keyFile;
-       }
-
-       public SshConnectionSshd(String host, int port, String username, String password) {
-               this(host, port, username, password, null);
-       }
-
-       public SshConnectionSshd(String host, int port, String keyFile) {
-               this(host, port, null, null, keyFile);
-       }
-
-       @Override
-       public void connect() {
-               sshClient = SshClient.setUpDefaultClient();
-               sshClient.start();
-               try {
-                       clientSession = sshClient.connect(EncryptionTool.getInstance().decrypt(username), host, port).await().getSession();
-                       if(password != null) {
-                               clientSession.addPasswordIdentity(EncryptionTool.getInstance().decrypt(password));
-                       }
-                       if(keyFile != null) {
-                               KeyPairProvider keyPairProvider = new FileKeyPairProvider(new String[]{keyFile});
-                               KeyPair keyPair = keyPairProvider.loadKeys().iterator().next();
-                               clientSession.addPublicKeyIdentity(keyPair);
-                       }
-                       AuthFuture authFuture = clientSession.auth();
-                       authFuture.await(AUTH_TIMEOUT);
-                       if(!authFuture.isSuccess()) {
-                               throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]. Authentication failed.");
-                       }
-               } catch(RuntimeException e) {
-                       throw e;
-               } catch(Exception e) {
-                       throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + "].", e);
-               }
-               if(logger.isDebugEnabled()) {
-                       logger.debug("SSH: connected to [" + toString() + "]");
-               }
-       }
-
-       @Override
-       public void disconnect() {
-               try {
-                       if(logger.isDebugEnabled()) {
-                               logger.debug("SSH: disconnecting from [" + toString() + "]");
-                       }
-                       clientSession.close(false);
-               } finally {
-                       if(sshClient != null) {
-                               sshClient.stop();
-                       }
-               }
-       }
-
-       @Override
-       public void setExecTimeout(long timeout) {
-               this.timeout = timeout;
-       }
-
-       @Override
-       public int execCommand(String cmd, OutputStream out, OutputStream err) {
-               return execCommand(cmd, out, err, false);
-       }
-
-       @Override
-       public int execCommandWithPty(String cmd, OutputStream out) {
-               return execCommand(cmd, out, out, true);
-       }
-
-       private int execCommand(String cmd, OutputStream out, OutputStream err, boolean usePty) {
-               try {
-                       if(logger.isDebugEnabled()) {
-                               logger.debug("SSH: executing command");
-                       }
-                       ChannelExec client = clientSession.createExecChannel(cmd);
+    private static final EELFLogger logger = EELFManager.getInstance().getApplicationLogger();
+
+    private static final long AUTH_TIMEOUT = 60000;
+    private static final long EXEC_TIMEOUT = 120000;
+
+    private String host;
+    private int port;
+    private String username;
+    private String password;
+    private long timeout = EXEC_TIMEOUT;
+    private String keyFile;
+    private SshClient sshClient;
+    private ClientSession clientSession;
+    private static final Configuration configuration = ConfigurationFactory.getConfiguration();
+
+    public SshConnectionSshd(String host, int port, String username, String password, String keyFile) {
+        this.host = host;
+        this.port = port;
+        this.username = username;
+        this.password = password;
+        this.keyFile = keyFile;
+    }
+
+    public SshConnectionSshd(String host, int port, String username, String password) {
+        this(host, port, username, password, null);
+    }
+
+    public SshConnectionSshd(String host, int port, String keyFile) {
+        this(host, port, null, null, keyFile);
+    }
+
+    @Override
+    public void connect() {
+        sshClient = SshClient.setUpDefaultClient();
+        sshClient.start();
+        try {
+            clientSession =
+                sshClient.connect(EncryptionTool.getInstance().decrypt(username), host, port).await().getSession();
+            if (password != null) {
+                clientSession.addPasswordIdentity(EncryptionTool.getInstance().decrypt(password));
+            }
+            if (keyFile != null) {
+                KeyPairProvider keyPairProvider = new FileKeyPairProvider(new String[] {
+                    keyFile
+                });
+                KeyPair keyPair = keyPairProvider.loadKeys().iterator().next();
+                clientSession.addPublicKeyIdentity(keyPair);
+            }
+            AuthFuture authFuture = clientSession.auth();
+            authFuture.await(AUTH_TIMEOUT);
+            if (!authFuture.isSuccess()) {
+                throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port
+                    + "]. Authentication failed.");
+            }
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + "].",
+                e);
+        }
+        if (logger.isDebugEnabled()) {
+            logger.debug("SSH: connected to [" + toString() + "]");
+        }
+    }
+
+    @Override
+    public void connectWithRetry() {
+        int retryCount = 0;
+        int retryDelay = 0;
+        int retriesLeft = 0;
+        retryCount = configuration.getIntegerProperty(Constants.CONNECTION_RETRY_COUNT,
+            Constants.DEFAULT_CONNECTION_RETRY_COUNT);
+        retryDelay = configuration.getIntegerProperty(Constants.CONNECTION_RETRY_DELAY,
+            Constants.DEFAULT_CONNECTION_RETRY_DELAY);
+        retriesLeft = retryCount + 1;
+        do {
+            try {
+                this.connect();
+                break;
+            } catch (RuntimeException e) {
+                if (retriesLeft > 1) {
+                    logger.debug("SSH Connection failed. Waiting for change in server's state.");
+                    waitForConnection(retryDelay);
+                    retriesLeft--;
+                    logger.debug("Retrying SSH connection. Attempt [" + Integer.toString(retryCount - retriesLeft + 1)
+                        + "] out of [" + retryCount + "]");
+                } else {
+                    throw e;
+                }
+            } catch (Exception e) {
+                throw e;
+            }
+        } while (retriesLeft > 0);
+    }
+
+    @Override
+    public void disconnect() {
+        try {
+            if (logger.isDebugEnabled()) {
+                logger.debug("SSH: disconnecting from [" + toString() + "]");
+            }
+            clientSession.close(false);
+        } finally {
+            if (sshClient != null) {
+                sshClient.stop();
+            }
+        }
+    }
+
+    @Override
+    public void setExecTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+
+    @Override
+    public int execCommand(String cmd, OutputStream out, OutputStream err) {
+        return execCommand(cmd, out, err, false);
+    }
+
+    @Override
+    public int execCommandWithPty(String cmd, OutputStream out) {
+        return execCommand(cmd, out, out, true);
+    }
+
+    private int execCommand(String cmd, OutputStream out, OutputStream err, boolean usePty) {
+        try {
+            if (logger.isDebugEnabled()) {
+                logger.debug("SSH: executing command");
+            }
+            ChannelExec client = clientSession.createExecChannel(cmd);
             client.setUsePty(usePty); // use pseudo-tty?
-                       client.setOut(out);
-                       client.setErr(err);
-                       OpenFuture openFuture = client.open();
-                       int exitStatus = 0;
-                       try {
-                               client.waitFor(ClientChannel.CLOSED, timeout);
-                               openFuture.verify();
-                               Integer exitStatusI = client.getExitStatus();
-                               if(exitStatusI == null) {
-                                       throw new SshException("Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + port + "]. Operation timed out.");
-                               }
-                               exitStatus = exitStatusI;
-                       } finally {
-                               client.close(false);
-                       }
-                       return exitStatus;
-               } catch(RuntimeException e) {
-                       throw e;
-               } catch(Exception t) {
-                       throw new SshException("Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + port + "]", t);
-               }
-       }
-
-       @Override
-       public String toString() {
-               String address = host;
-               if(username != null) {
-                       address = username + '@' +address;
-               }
-               return address;
-       }
+            client.setOut(out);
+            client.setErr(err);
+            OpenFuture openFuture = client.open();
+            int exitStatus = 0;
+            try {
+                client.waitFor(ClientChannel.CLOSED, timeout);
+                openFuture.verify();
+                Integer exitStatusI = client.getExitStatus();
+                if (exitStatusI == null) {
+                    throw new SshException("Error executing command [" + cmd + "] over SSH [" + username + "@" + host
+                        + ":" + port + "]. Operation timed out.");
+                }
+                exitStatus = exitStatusI;
+            } finally {
+                client.close(false);
+            }
+            return exitStatus;
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception t) {
+            throw new SshException(
+                "Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + port + "]", t);
+        }
+    }
+
+    private void waitForConnection(int retryDelay) {
+        long time = retryDelay * 1000L;
+        long future = System.currentTimeMillis() + time;
+        if (time != 0) {
+            while (System.currentTimeMillis() < future && time > 0) {
+                try {
+                    Thread.sleep(time);
+                } catch (InterruptedException e) {
+                    /*
+                     * This is rare, but it can happen if another thread interrupts us while we are sleeping. In that
+                     * case, the thread is resumed before the delay time has actually expired, so re-calculate the
+                     * amount of delay time needed and reenter the sleep until we get to the future time.
+                     */
+                    time = future - System.currentTimeMillis();
+                }
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        String address = host;
+        if (username != null) {
+            address = username + '@' + address;
+        }
+        return address;
+    }
 }