feat: SSH 成功获取系统信息时视为机器在线
在连通性检测逻辑中,当 network ping / ICMP / TCP 三层探测均失败后, 若机器配置了 SSH 凭据,则同步尝试调用 GetSSHInfo 进行 SSH 信息采集: - 若 SSH 采集成功,则将该机器判定为在线,并保存获取到的系统信息; - 若 SSH 采集也失败,则保持离线状态,按原逻辑记录离线日志。 此改进可避免以下场景导致的误判: - 机器禁 ping 或 ICMP 被防火墙拦截; - SSH 端口未被网络层探测正确识别; - 只要 SSH 服务正常且能正确登录并获取系统信息,即认为机器处于可用状态。 其他改动: - 提取 saveSSHResult 辅助函数,统一保存 SSH 采集结果,避免重复代码。 - 同步更新了本地与 Linux 部署二进制文件。
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"lan-manager/server/db"
|
"lan-manager/server/db"
|
||||||
|
"lan-manager/server/models"
|
||||||
"lan-manager/server/utils"
|
"lan-manager/server/utils"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -146,9 +147,43 @@ type machinePing struct {
|
|||||||
wasOnline bool
|
wasOnline bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func saveSSHResult(mid int64, mip string, mport int, result *models.SSHInfoResult) {
|
||||||
|
portsStr := ""
|
||||||
|
if len(result.ListenPorts) > 0 {
|
||||||
|
b, _ := json.Marshal(result.ListenPorts)
|
||||||
|
portsStr = string(b)
|
||||||
|
if len(portsStr) > 2 {
|
||||||
|
portsStr = portsStr[1 : len(portsStr)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, dbErr := db.DB.Exec(`UPDATE machines SET cpu_info=?, memory_info=?, disk_info=?, uptime=?, listen_ports=?, ssh_synced_at=CURRENT_TIMESTAMP, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
||||||
|
result.RawCPUInfo, result.RawMemoryInfo, result.RawDiskInfo, result.Uptime, portsStr, mid)
|
||||||
|
if dbErr != nil {
|
||||||
|
fmt.Printf("[SSH] auto-fetch db error for %s:%d: %v\n", mip, mport, dbErr)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("[SSH] auto-fetch success for %s:%d\n", mip, mport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handlePingResult(m *machinePing, res PingResult) {
|
func handlePingResult(m *machinePing, res PingResult) {
|
||||||
online := res.Online
|
online := res.Online
|
||||||
reason := res.Reason
|
reason := res.Reason
|
||||||
|
var sshResult *models.SSHInfoResult
|
||||||
|
|
||||||
|
// 如果网络层检测失败,尝试通过 SSH 获取系统信息来判定在线
|
||||||
|
if !online && m.sshUsername != "" && m.sshPassword != "" {
|
||||||
|
plainPass, decryptErr := utils.Decrypt(m.sshPassword)
|
||||||
|
if decryptErr == nil {
|
||||||
|
result, err := GetSSHInfo(m.ip, m.sshPort, m.sshUsername, plainPass)
|
||||||
|
if err == nil {
|
||||||
|
online = true
|
||||||
|
reason = ""
|
||||||
|
sshResult = result
|
||||||
|
fmt.Printf("[Ping] %s -> network unreachable, but SSH info fetched successfully, treating as online\n", m.ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var onlineInt int
|
var onlineInt int
|
||||||
if online {
|
if online {
|
||||||
onlineInt = 1
|
onlineInt = 1
|
||||||
@@ -185,6 +220,9 @@ func handlePingResult(m *machinePing, res PingResult) {
|
|||||||
_, _ = db.DB.Exec(`UPDATE machines SET total_offline_seconds=total_offline_seconds+? WHERE id=?`, duration, m.id)
|
_, _ = db.DB.Exec(`UPDATE machines SET total_offline_seconds=total_offline_seconds+? WHERE id=?`, duration, m.id)
|
||||||
}
|
}
|
||||||
m.wasOnline = true
|
m.wasOnline = true
|
||||||
|
if sshResult != nil {
|
||||||
|
saveSSHResult(m.id, m.ip, m.sshPort, sshResult)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,33 +235,23 @@ func handlePingResult(m *machinePing, res PingResult) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if online && m.sshUsername != "" && m.sshPassword != "" {
|
if online && m.sshUsername != "" && m.sshPassword != "" {
|
||||||
go func(mid int64, mip string, mport int, muser, mpass string) {
|
if sshResult != nil {
|
||||||
plainPass, decryptErr := utils.Decrypt(mpass)
|
saveSSHResult(m.id, m.ip, m.sshPort, sshResult)
|
||||||
if decryptErr != nil {
|
} else {
|
||||||
fmt.Printf("[SSH] decrypt failed for %s:%d: %v\n", mip, mport, decryptErr)
|
go func(mid int64, mip string, mport int, muser, mpass string) {
|
||||||
return
|
plainPass, decryptErr := utils.Decrypt(mpass)
|
||||||
}
|
if decryptErr != nil {
|
||||||
result, err := GetSSHInfo(mip, mport, muser, plainPass)
|
fmt.Printf("[SSH] decrypt failed for %s:%d: %v\n", mip, mport, decryptErr)
|
||||||
if err != nil {
|
return
|
||||||
fmt.Printf("[SSH] auto-fetch failed for %s:%d: %v\n", mip, mport, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
portsStr := ""
|
|
||||||
if len(result.ListenPorts) > 0 {
|
|
||||||
b, _ := json.Marshal(result.ListenPorts)
|
|
||||||
portsStr = string(b)
|
|
||||||
if len(portsStr) > 2 {
|
|
||||||
portsStr = portsStr[1 : len(portsStr)-1]
|
|
||||||
}
|
}
|
||||||
}
|
result, err := GetSSHInfo(mip, mport, muser, plainPass)
|
||||||
_, dbErr := db.DB.Exec(`UPDATE machines SET cpu_info=?, memory_info=?, disk_info=?, uptime=?, listen_ports=?, ssh_synced_at=CURRENT_TIMESTAMP, updated_at=CURRENT_TIMESTAMP WHERE id=?`,
|
if err != nil {
|
||||||
result.RawCPUInfo, result.RawMemoryInfo, result.RawDiskInfo, result.Uptime, portsStr, mid)
|
fmt.Printf("[SSH] auto-fetch failed for %s:%d: %v\n", mip, mport, err)
|
||||||
if dbErr != nil {
|
return
|
||||||
fmt.Printf("[SSH] auto-fetch db error for %s:%d: %v\n", mip, mport, dbErr)
|
}
|
||||||
} else {
|
saveSSHResult(mid, mip, mport, result)
|
||||||
fmt.Printf("[SSH] auto-fetch success for %s:%d\n", mip, mport)
|
}(m.id, m.ip, m.sshPort, m.sshUsername, m.sshPassword)
|
||||||
}
|
}
|
||||||
}(m.id, m.ip, m.sshPort, m.sshUsername, m.sshPassword)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user