All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tascape.reactor.comm.SshCommunication Maven / Gradle / Ivy

There is a newer version: 1.3.19
Show newest version
/*
 * Copyright (c) 2015 - present Nebula Bay.
 * All rights reserved.
 *
 * Licensed 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 com.tascape.reactor.comm;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.tascape.reactor.SystemConfiguration;
import com.tascape.reactor.exception.EntityCommunicationException;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author linsong wang
 */
public class SshCommunication extends EntityCommunication implements Closeable {
    private static final Logger LOG = LoggerFactory.getLogger(SshCommunication.class);

    public static final String SYSPROP_HOST = "reactor.comm.ssh.HOST";

    public static final String SYSPROP_PORT = "reactor.comm.ssh.PORT";

    public static final String SYSPROP_KEY = "reactor.comm.ssh.KEY";

    public static final String SYSPROP_USER = "reactor.comm.ssh.USER";

    public static final String SYSPROP_PASS = "reactor.comm.ssh.PASS";

    private final JSch jSch;

    private final String host;

    private final int port;

    private Session session;

    private final Set channels = new HashSet<>();

    public static SshCommunication newInstance() throws Exception {
        return newInstance("");
    }

    public static SshCommunication newInstance(String name) throws Exception {
        SystemConfiguration sysConfig = SystemConfiguration.getInstance();
        String h = sysConfig.getProperty(SshCommunication.SYSPROP_HOST + name);
        if (h == null) {
            h = sysConfig.getProperty(SshCommunication.SYSPROP_HOST, "localhost");
        }
        int p = sysConfig.getIntProperty(SshCommunication.SYSPROP_PORT + name);
        if (p == Integer.MIN_VALUE) {
            p = sysConfig.getIntProperty(SshCommunication.SYSPROP_PORT, 22);
        }
        SshCommunication ssh = new SshCommunication(h, p);

        String u = sysConfig.getProperty(SshCommunication.SYSPROP_USER + name);
        if (u == null) {
            u = sysConfig.getProperty(SshCommunication.SYSPROP_USER);
        }
        String k = sysConfig.getProperty(SshCommunication.SYSPROP_KEY + name);
        if (k == null) {
            k = sysConfig.getProperty(SshCommunication.SYSPROP_KEY);
        }
        String pw = sysConfig.getProperty(SshCommunication.SYSPROP_PASS + name);
        if (pw == null) {
            pw = sysConfig.getProperty(SshCommunication.SYSPROP_PASS);
        }
        ssh.setPrivateKey(k, pw);
        ssh.setUsernamePassword(u, pw);
        ssh.connect();
        return ssh;
    }

    /**
     *
     * @param host host DNS name or IP
     * @param port ssh port
     */
    public SshCommunication(String host, int port) {
        this.jSch = new JSch();
        this.host = host;
        this.port = port;
    }

    public void setPrivateKey(String key, String passphrase) throws JSchException {
        if (StringUtils.isNotBlank(key)) {
            this.jSch.addIdentity(key, passphrase);
        }
    }

    public void setUsernamePassword(String username, String password) throws JSchException {
        this.session = this.jSch.getSession(username, host, port);
        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        this.session.setPassword(password);
    }

    public List shell(String command, long timeout) throws JSchException, IOException, Exception {
        Channel shell = this.session.openChannel("shell");
        shell.setInputStream(IOUtils.toInputStream(command + "\nexit\n", Charset.defaultCharset()));
        try (BufferedReader in = new BufferedReader(new InputStreamReader(shell.getInputStream()))) {
            shell.connect();
            channels.add(shell);
            Thread thread = new ChanneOperationTimer(shell, timeout);
            thread.start();
            List lines = in.lines().collect(Collectors.toList());
            thread.interrupt();
            lines.forEach(l -> LOG.debug("{}", l));
            return lines;
        }
    }

    public Channel shell(String command, OutputStream out) throws JSchException {
        Channel shell = this.session.openChannel("shell");
        shell.setInputStream(IOUtils.toInputStream(command + "\nexit\n", Charset.defaultCharset()));
        shell.setOutputStream(out);
        shell.connect(2000);
        channels.add(shell);
        return shell;
    }

    public Channel shell(String command, File out) throws JSchException, IOException {
        Channel shell = this.session.openChannel("shell");
        shell.setInputStream(IOUtils.toInputStream(command + "\nexit\n", Charset.defaultCharset()));
        shell.setOutputStream(FileUtils.openOutputStream(out));
        shell.connect();
        channels.add(shell);
        return shell;
    }

    public void upload(File srcFile, String destFile, long timeout) throws JSchException, SftpException, IOException {
        Channel channel = this.session.openChannel("sftp");
        channel.setInputStream(System.in);
        channel.setOutputStream(System.out);
        channel.connect();
        channels.add(channel);

        new ChanneOperationTimer(channel, timeout).start();
        ChannelSftp sftp = (ChannelSftp) channel;
        sftp.put(FileUtils.openInputStream(srcFile), destFile);
        sftp.exit();
    }

    public void download(String srcFile, File destFile, long timeout) throws JSchException, SftpException, IOException {
        Channel channel = this.session.openChannel("sftp");
        channel.setInputStream(System.in);
        channel.setOutputStream(System.out);
        channel.connect();
        channels.add(channel);
        new ChanneOperationTimer(channel, timeout).start();

        ChannelSftp sftp = (ChannelSftp) channel;
        try (FileOutputStream out = FileUtils.openOutputStream(destFile)) {
            sftp.get(srcFile, out);
        } finally {
            sftp.exit();
        }
    }

    @Override
    public void connect() throws Exception {
        session.connect();
        LOG.debug("connected to {}:{} ({})", session.getHost(), session.getPort(), session.getServerVersion());
    }

    @Override
    public void disconnect() throws Exception {
        try {
            channels.forEach(c -> {
                c.disconnect();
            });
        } finally {
            if (this.session != null) {
                this.session.disconnect();
            }
        }
    }

    @Override
    public void close() throws IOException {
        try {
            this.disconnect();
        } catch (Exception ex) {
            throw new EntityCommunicationException(ex);
        }
    }

    private static class ChanneOperationTimer extends Thread {
        private final Channel channel;

        private final long timeout;

        public ChanneOperationTimer(Channel channel, long timeout) {
            this.channel = channel;
            this.timeout = timeout;
            this.setDaemon(true);
        }

        @Override
        public void run() {
            try {
                Thread.sleep(timeout);
            } catch (InterruptedException ex) {
                LOG.trace("interrupted - {}", ex.getMessage());
            }
            if (channel != null) {
                channel.disconnect();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        {
            SYS_CONFIG.getProperties().setProperty(SYSPROP_HOST + "VAGRANT", "localhost");
            SYS_CONFIG.getProperties().setProperty(SYSPROP_PORT + "VAGRANT", "2222");
            SYS_CONFIG.getProperties().setProperty(SYSPROP_USER + "VAGRANT", "vagrant");
            SYS_CONFIG.getProperties().setProperty(SYSPROP_PASS + "VAGRANT", "vagrant");
            SshCommunication ssh = SshCommunication.newInstance("VAGRANT");
            runSsh(ssh);
            ssh.disconnect();
        }
        {
            SshCommunication ssh = new SshCommunication("localhost", 2222);
            ssh.setUsernamePassword("vagrant", "vagrant");
            ssh.connect();
            runSsh(ssh);
            ssh.disconnect();
        }
        {
            SshCommunication ssh = new SshCommunication("localhost", 2222);
            ssh.setPrivateKey("~/.reactor/.vagrant/machines/default/virtualbox/private_key", "");
            ssh.setUsernamePassword("vagrant", "");
            ssh.connect();
            runSsh(ssh);
            ssh.disconnect();
        }
    }

    private static void runSsh(SshCommunication ssh) throws Exception {
        File out = File.createTempFile("ssh-", ".txt");
        FileUtils.write(out, "ssh test", Charset.defaultCharset());
        ssh.upload(out, "/home/vagrant/ssh.txt", 1000);

        ssh.shell("ls -al && sleep 5", 6000);
        ssh.shell("echo 'test data " + RandomUtils.nextLong() + "' >> /home/vagrant/ssh.txt", 2000);
        try (OutputStream os = FileUtils.openOutputStream(out)) {
            ssh.shell("cat /home/vagrant/ssh.txt", os);
        }
        ssh.download("/home/vagrant/ssh.txt", out, 2000);
        Thread.sleep(1000);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy