feat: 新增终端顶部实时服务器监控面板
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
package com.sshmanager.controller;
|
||||
|
||||
import com.sshmanager.entity.Connection;
|
||||
import com.sshmanager.entity.User;
|
||||
import com.sshmanager.repository.UserRepository;
|
||||
import com.sshmanager.service.ConnectionService;
|
||||
import com.sshmanager.service.SshService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/monitor")
|
||||
public class MonitorController {
|
||||
|
||||
private final ConnectionService connectionService;
|
||||
private final SshService sshService;
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public MonitorController(ConnectionService connectionService, SshService sshService, UserRepository userRepository) {
|
||||
this.connectionService = connectionService;
|
||||
this.sshService = sshService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
private Long getCurrentUserId(Authentication auth) {
|
||||
User user = userRepository.findByUsername(auth.getName()).orElseThrow(() -> new IllegalStateException("User not found"));
|
||||
return user.getId();
|
||||
}
|
||||
|
||||
@GetMapping("/{connectionId}")
|
||||
public ResponseEntity<Map<String, Object>> getServerMetrics(@PathVariable Long connectionId, Authentication authentication) {
|
||||
try {
|
||||
Long userId = getCurrentUserId(authentication);
|
||||
Connection conn = connectionService.getConnectionForSsh(connectionId, userId);
|
||||
if (conn == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
String password = connectionService.getDecryptedPassword(conn);
|
||||
String privateKey = connectionService.getDecryptedPrivateKey(conn);
|
||||
String passphrase = connectionService.getDecryptedPassphrase(conn);
|
||||
|
||||
Map<String, Object> metrics = new HashMap<>();
|
||||
|
||||
// 获取CPU使用率
|
||||
try {
|
||||
String cpuOutput = sshService.executeCommand(conn, password, privateKey, passphrase,
|
||||
"top -bn1 | grep 'Cpu(s)' | sed 's/.*, *\\([0-9.]*\\)%* id.*/\\1/' | awk '{print 100 - $1}'");
|
||||
double cpuUsage = Double.parseDouble(cpuOutput.trim());
|
||||
metrics.put("cpuUsage", Math.round(cpuUsage * 10.0) / 10.0);
|
||||
} catch (Exception e) {
|
||||
metrics.put("cpuUsage", null);
|
||||
}
|
||||
|
||||
// 获取内存信息
|
||||
try {
|
||||
String memOutput = sshService.executeCommand(conn, password, privateKey, passphrase,
|
||||
"free -b | grep Mem");
|
||||
String[] memParts = memOutput.trim().split("\\s+");
|
||||
long totalMem = Long.parseLong(memParts[1]);
|
||||
long usedMem = Long.parseLong(memParts[2]);
|
||||
double memUsage = (double) usedMem / totalMem * 100;
|
||||
metrics.put("memTotal", totalMem);
|
||||
metrics.put("memUsed", usedMem);
|
||||
metrics.put("memUsage", Math.round(memUsage * 10.0) / 10.0);
|
||||
} catch (Exception e) {
|
||||
metrics.put("memTotal", null);
|
||||
metrics.put("memUsed", null);
|
||||
metrics.put("memUsage", null);
|
||||
}
|
||||
|
||||
// 获取磁盘使用率
|
||||
try {
|
||||
String diskOutput = sshService.executeCommand(conn, password, privateKey, passphrase,
|
||||
"df -P / | tail -1");
|
||||
String[] diskParts = diskOutput.trim().split("\\s+");
|
||||
int diskUsage = Integer.parseInt(diskParts[4].replace("%", ""));
|
||||
metrics.put("diskUsage", diskUsage);
|
||||
} catch (Exception e) {
|
||||
metrics.put("diskUsage", null);
|
||||
}
|
||||
|
||||
// 获取系统负载
|
||||
try {
|
||||
String loadOutput = sshService.executeCommand(conn, password, privateKey, passphrase,
|
||||
"cat /proc/loadavg");
|
||||
String[] loadParts = loadOutput.trim().split("\\s+");
|
||||
double load1 = Double.parseDouble(loadParts[0]);
|
||||
metrics.put("load1", load1);
|
||||
} catch (Exception e) {
|
||||
metrics.put("load1", null);
|
||||
}
|
||||
|
||||
// 获取CPU核数
|
||||
try {
|
||||
String cpuCountOutput = sshService.executeCommand(conn, password, privateKey, passphrase,
|
||||
"grep -c ^processor /proc/cpuinfo");
|
||||
int cpuCores = Integer.parseInt(cpuCountOutput.trim());
|
||||
metrics.put("cpuCores", cpuCores);
|
||||
} catch (Exception e) {
|
||||
metrics.put("cpuCores", null);
|
||||
}
|
||||
|
||||
// 获取系统运行时间
|
||||
try {
|
||||
String uptimeOutput = sshService.executeCommand(conn, password, privateKey, passphrase,
|
||||
"uptime -p");
|
||||
metrics.put("uptime", uptimeOutput.trim().replace("up ", ""));
|
||||
} catch (Exception e) {
|
||||
// 尝试另一种uptime格式
|
||||
try {
|
||||
String uptimeOutput = sshService.executeCommand(conn, password, privateKey, passphrase,
|
||||
"cat /proc/uptime | awk '{print $1}'");
|
||||
double uptimeSeconds = Double.parseDouble(uptimeOutput.trim());
|
||||
long days = (long) (uptimeSeconds / 86400);
|
||||
long hours = (long) ((uptimeSeconds % 86400) / 3600);
|
||||
long minutes = (long) ((uptimeSeconds % 3600) / 60);
|
||||
StringBuilder uptimeStr = new StringBuilder();
|
||||
if (days > 0) uptimeStr.append(days).append("d ");
|
||||
if (hours > 0) uptimeStr.append(hours).append("h ");
|
||||
uptimeStr.append(minutes).append("m");
|
||||
metrics.put("uptime", uptimeStr.toString().trim());
|
||||
} catch (Exception e2) {
|
||||
metrics.put("uptime", null);
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(metrics);
|
||||
} catch (Exception e) {
|
||||
Map<String, Object> error = new HashMap<>();
|
||||
error.put("error", e.getMessage());
|
||||
return ResponseEntity.badRequest().body(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,25 @@
|
||||
package com.sshmanager.service;
|
||||
|
||||
import com.jcraft.jsch.ChannelShell;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.sshmanager.entity.Connection;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.ChannelShell;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.sshmanager.entity.Connection;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
|
||||
@Service
|
||||
public class SshService {
|
||||
|
||||
public SshSession createShellSession(Connection conn, String password, String privateKey, String passphrase)
|
||||
throws Exception {
|
||||
public SshSession createShellSession(Connection conn, String password, String privateKey, String passphrase)
|
||||
throws Exception {
|
||||
JSch jsch = new JSch();
|
||||
|
||||
if (conn.getAuthType() == Connection.AuthType.PRIVATE_KEY && privateKey != null && !privateKey.isEmpty()) {
|
||||
@@ -65,7 +68,49 @@ public class SshService {
|
||||
}
|
||||
}).start();
|
||||
|
||||
return new SshSession(session, channel, channelOut, pipeToChannel);
|
||||
return new SshSession(session, channel, channelOut, pipeToChannel);
|
||||
}
|
||||
|
||||
// 执行单次命令并返回输出
|
||||
public String executeCommand(Connection conn, String password, String privateKey, String passphrase, String command) throws Exception {
|
||||
JSch jsch = new JSch();
|
||||
|
||||
if (conn.getAuthType() == Connection.AuthType.PRIVATE_KEY && privateKey != null && !privateKey.isEmpty()) {
|
||||
byte[] keyBytes = privateKey.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] passphraseBytes = (passphrase != null && !passphrase.isEmpty())
|
||||
? passphrase.getBytes(StandardCharsets.UTF_8) : null;
|
||||
jsch.addIdentity("key", keyBytes, null, passphraseBytes);
|
||||
}
|
||||
|
||||
Session session = jsch.getSession(conn.getUsername(), conn.getHost(), conn.getPort());
|
||||
session.setConfig("StrictHostKeyChecking", "no");
|
||||
session.setConfig("kex", "diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1");
|
||||
session.setConfig("PreferredAuthentications", conn.getAuthType() == Connection.AuthType.PASSWORD ? "password" : "publickey");
|
||||
|
||||
if (conn.getAuthType() == Connection.AuthType.PASSWORD) {
|
||||
session.setPassword(password);
|
||||
}
|
||||
|
||||
session.connect(8000);
|
||||
|
||||
ChannelExec channel = (ChannelExec) session.openChannel("exec");
|
||||
channel.setCommand(command);
|
||||
channel.setErrStream(System.err);
|
||||
|
||||
InputStream in = channel.getInputStream();
|
||||
channel.connect(3000);
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
|
||||
StringBuilder result = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
result.append(line).append("\n");
|
||||
}
|
||||
|
||||
channel.disconnect();
|
||||
session.disconnect();
|
||||
|
||||
return result.toString().trim();
|
||||
}
|
||||
|
||||
public static class SshSession {
|
||||
|
||||
Reference in New Issue
Block a user