126 lines
3.9 KiB
Java
126 lines
3.9 KiB
Java
package com.litoralregas.vpnprovisioner.vps;
|
|
|
|
import com.jcraft.jsch.ChannelExec;
|
|
import com.jcraft.jsch.JSch;
|
|
import com.jcraft.jsch.Session;
|
|
import com.litoralregas.vpnprovisioner.config.VpsSshProperties;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.util.StringUtils;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Properties;
|
|
|
|
@Service
|
|
public class SshService {
|
|
|
|
private final VpsSshProperties properties;
|
|
|
|
public SshService(VpsSshProperties properties) {
|
|
this.properties = properties;
|
|
}
|
|
|
|
public SshCommandResult executeOnConfiguredVps(String command) {
|
|
validateConfiguredVps();
|
|
return execute(
|
|
properties.getHost(),
|
|
properties.getPort(),
|
|
properties.getUsername(),
|
|
properties.getPassword(),
|
|
properties.getPrivateKeyPath(),
|
|
command,
|
|
properties.getConnectTimeoutMs(),
|
|
properties.getCommandTimeoutMs()
|
|
);
|
|
}
|
|
|
|
public SshCommandResult execute(
|
|
String host,
|
|
int port,
|
|
String username,
|
|
String password,
|
|
String privateKeyPath,
|
|
String command,
|
|
int connectTimeoutMs,
|
|
int commandTimeoutMs
|
|
) {
|
|
Session session = null;
|
|
ChannelExec channel = null;
|
|
|
|
try {
|
|
JSch jsch = new JSch();
|
|
|
|
if (StringUtils.hasText(privateKeyPath)) {
|
|
jsch.addIdentity(privateKeyPath);
|
|
}
|
|
|
|
session = jsch.getSession(username, host, port);
|
|
|
|
if (StringUtils.hasText(password)) {
|
|
session.setPassword(password);
|
|
}
|
|
|
|
Properties config = new Properties();
|
|
config.put("StrictHostKeyChecking", "no");
|
|
session.setConfig(config);
|
|
|
|
session.connect(connectTimeoutMs);
|
|
|
|
channel = (ChannelExec) session.openChannel("exec");
|
|
channel.setCommand(command);
|
|
channel.setInputStream(null);
|
|
|
|
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
|
|
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
|
|
|
|
channel.setOutputStream(stdout);
|
|
channel.setErrStream(stderr);
|
|
|
|
channel.connect(connectTimeoutMs);
|
|
|
|
long deadline = System.currentTimeMillis() + commandTimeoutMs;
|
|
|
|
while (!channel.isClosed()) {
|
|
if (System.currentTimeMillis() > deadline) {
|
|
throw new SshCommandException("SSH command timed out: " + command);
|
|
}
|
|
|
|
Thread.sleep(100);
|
|
}
|
|
|
|
return new SshCommandResult(
|
|
channel.getExitStatus(),
|
|
stdout.toString(StandardCharsets.UTF_8),
|
|
stderr.toString(StandardCharsets.UTF_8)
|
|
);
|
|
|
|
} catch (SshCommandException exception) {
|
|
throw exception;
|
|
} catch (Exception exception) {
|
|
throw new SshCommandException("SSH command failed: " + command, exception);
|
|
} finally {
|
|
if (channel != null) {
|
|
channel.disconnect();
|
|
}
|
|
|
|
if (session != null) {
|
|
session.disconnect();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void validateConfiguredVps() {
|
|
if (!StringUtils.hasText(properties.getHost())) {
|
|
throw new SshCommandException("VPS SSH host is not configured");
|
|
}
|
|
|
|
if (!StringUtils.hasText(properties.getUsername())) {
|
|
throw new SshCommandException("VPS SSH username is not configured");
|
|
}
|
|
|
|
if (!StringUtils.hasText(properties.getPassword())
|
|
&& !StringUtils.hasText(properties.getPrivateKeyPath())) {
|
|
throw new SshCommandException("Either VPS SSH password or private key path must be configured");
|
|
}
|
|
}
|
|
} |