package com.genpt.impl; import com.genpt.CommandExecutionException; import com.genpt.TriggerSshService; import com.genpt.config.ServerConfiguration; import com.genpt.model.TriggerSshRequest; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import lombok.SneakyThrows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.io.InputStream; import java.util.Arrays; import java.util.List; @Service public class TriggerSshImpl implements TriggerSshService { long time = System.currentTimeMillis(); @Autowired ServerConfiguration serverConfiguration; private static final Logger LOGGER = LoggerFactory.getLogger(TriggerSshImpl.class); @Override @Async public void triggerSshConnection(TriggerSshRequest triggerSshRequest) { boolean success = false; String username = serverConfiguration.getUsername(); String password = serverConfiguration.getPassword(); List hosts = Arrays.asList(serverConfiguration.getHost().split(",")); Integer port = serverConfiguration.getPort(); String command = generateCommandToRun(triggerSshRequest); LOGGER.info("\n"); LOGGER.info("#######################################################"); for (String host : hosts) { try { runCommandOnServer(host, port, username, password, command); LOGGER.info("Successfully triggered the ssh command, Time Taken: {} ms ", (System.currentTimeMillis() - time)); success = true; break; } catch (Exception e) { LOGGER.error("Process Errored while running the command: '{}' on {} server, Please verify", command, host); LOGGER.info(e.getMessage()); } } logEndMessage(success); } @SneakyThrows private void runCommandOnServer(String host, int port, String user, String password, String command){ Session session = getSession(host, port, user, password, command); ChannelExec channelExec = getChannelExec(command, session); InputStream in = channelExec.getInputStream(); InputStream errStream = channelExec.getErrStream(); channelExec.connect(); // read the output of the command byte[] successbuffer = new byte[1024]; while (true) { readOutputFromInputStream(in, successbuffer); if (channelExec.isClosed()) { checkExistStatus(channelExec, errStream); break; } try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new CommandExecutionException(e.getMessage()); } } channelExec.disconnect(); session.disconnect(); } @SneakyThrows private Session getSession(String host, int port, String user, String password, String command){ try { JSch jsch = new JSch(); Session session = jsch.getSession(user, host, port); session.setPassword(password); LOGGER.info("Running the command: '{}' on {} server", command, host); session.setConfig("StrictHostKeyChecking", "no"); session.setConfig("PreferredAuthentications", "publickey,keyboard-interactive,password"); session.connect(); return session; }catch (Exception e){ throw new CommandExecutionException(e.getMessage()); } } private String generateCommandToRun(TriggerSshRequest triggerSshRequest) { String script = triggerSshRequest.getRequest().getScript(); String classname = triggerSshRequest.getRequest().getClassname(); String jarpath = triggerSshRequest.getRequest().getJarpath(); String parameters = triggerSshRequest.getRequest().getParameters(); return String.format("%s --class %s %s %s", script, classname, jarpath, parameters); } private void logEndMessage(boolean success) { if (success) { LOGGER.info("Process completed successfully."); } else { LOGGER.info("Process exited with an error"); } } @SneakyThrows private ChannelExec getChannelExec(String command, Session session){ ChannelExec channelExec = (ChannelExec) session.openChannel("exec"); channelExec.setCommand(command); channelExec.setInputStream(null); channelExec.setErrStream(null); channelExec.setPty(true); return channelExec; } @SneakyThrows private void checkExistStatus(ChannelExec channelExec, InputStream errStream){ int exitStatus = channelExec.getExitStatus(); if (exitStatus != 0) { readErrorMsg(errStream); } } @SneakyThrows private void readOutputFromInputStream(InputStream in, byte[] successbuffer) { while (in.available() > 0) { int numBytes = in.read(successbuffer, 0, 1024); if (numBytes < 0) break; String logmessage = new String(successbuffer, 0, numBytes); LOGGER.info(logmessage); } } @SneakyThrows private void readErrorMsg(InputStream errStream) { byte[] errorbuffer = new byte[1024]; StringBuilder errorMessage = new StringBuilder(); while (errStream.available() > 0) { int len = errStream.read(errorbuffer); errorMessage.append(new String(errorbuffer, 0, len)); } throw new CommandExecutionException(errorMessage.toString()); } }