mirror of
https://github.com/fankes/komari-agent.git
synced 2025-10-18 18:49:23 +08:00
feat: 增强虚拟化检测功能,支持Windows和Linux环境
This commit is contained in:
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ require (
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/creack/pty v1.1.24
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/klauspost/cpuid/v2 v2.3.0
|
||||
github.com/prometheus-community/pro-bing v0.7.0
|
||||
github.com/rhysd/go-github-selfupdate v1.2.3
|
||||
github.com/shirou/gopsutil/v4 v4.25.6
|
||||
|
2
go.sum
2
go.sum
@@ -30,6 +30,8 @@ github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf h1:WfD7V
|
||||
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf/go.mod h1:hyb9oH7vZsitZCiBt0ZvifOrB+qc8PS5IiilCIb87rg=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
|
@@ -1,19 +1,134 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
cpuid "github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func Virtualized() string {
|
||||
// Windows: use CPUID to detect hypervisor presence and vendor.
|
||||
if runtime.GOOS == "windows" {
|
||||
return "Unknown"
|
||||
}
|
||||
out, err := exec.Command("systemd-detect-virt").Output()
|
||||
if err != nil {
|
||||
return "Unknown"
|
||||
return detectByCPUID()
|
||||
}
|
||||
|
||||
// Linux/others: prefer systemd-detect-virt if available; fallback to CPUID.
|
||||
if out, err := exec.Command("systemd-detect-virt").Output(); err == nil {
|
||||
virt := strings.TrimSpace(string(out))
|
||||
if virt != "" {
|
||||
return virt
|
||||
}
|
||||
}
|
||||
|
||||
// Non-systemd environments (e.g., Alpine containers): try container heuristics.
|
||||
if ct := detectContainer(); ct != "" {
|
||||
return ct
|
||||
}
|
||||
|
||||
// Fallback (any OS): CPUID hypervisor bit and vendor mapping.
|
||||
return detectByCPUID()
|
||||
}
|
||||
|
||||
// detectByCPUID uses cpuid to check if running under a hypervisor and maps vendor to a common name.
|
||||
func detectByCPUID() string {
|
||||
if !cpuid.CPU.VM() {
|
||||
// Align with systemd-detect-virt for bare metal.
|
||||
return "none"
|
||||
}
|
||||
vendor := strings.ToLower(cpuid.CPU.HypervisorVendorString)
|
||||
switch {
|
||||
case vendor == "kvm" || strings.Contains(vendor, "kvm"):
|
||||
return "kvm"
|
||||
case vendor == "microsoft" || strings.Contains(vendor, "hyper-v") || strings.Contains(vendor, "msvm") || strings.Contains(vendor, "mshyperv"):
|
||||
return "microsoft" // systemd uses "microsoft" for Hyper-V/WSL
|
||||
case strings.Contains(vendor, "vmware"):
|
||||
return "vmware"
|
||||
case strings.Contains(vendor, "xen"):
|
||||
return "xen"
|
||||
case strings.Contains(vendor, "bhyve"):
|
||||
return "bhyve"
|
||||
case strings.Contains(vendor, "qemu"):
|
||||
return "qemu"
|
||||
case strings.Contains(vendor, "parallels"):
|
||||
return "parallels"
|
||||
case strings.Contains(vendor, "oracle") || strings.Contains(vendor, "virtualbox") || strings.Contains(vendor, "vbox"):
|
||||
return "oracle" // systemd reports "oracle" for VirtualBox
|
||||
case strings.Contains(vendor, "acrn"):
|
||||
return "acrn"
|
||||
default:
|
||||
if vendor != "" {
|
||||
return fmt.Sprintf("hypervisor:%s", vendor)
|
||||
}
|
||||
return "virtualized"
|
||||
}
|
||||
}
|
||||
|
||||
// detectContainer attempts to detect common Linux container environments when systemd isn't available.
|
||||
// Returns a systemd-detect-virt-like string such as "docker", "podman", "lxc", "container" or empty if not detected.
|
||||
func detectContainer() string {
|
||||
// Quick file markers used by Docker/Podman/CRI-O
|
||||
if fileExists("/.dockerenv") {
|
||||
return "docker"
|
||||
}
|
||||
if fileExists("/run/.containerenv") {
|
||||
// podman/cri-o often drop this file
|
||||
// Try to refine using cgroup content.
|
||||
if s := parseCgroupForContainer(); s != "" {
|
||||
return s
|
||||
}
|
||||
return "container"
|
||||
}
|
||||
|
||||
// Check cgroup info for container keywords.
|
||||
if s := parseCgroupForContainer(); s != "" {
|
||||
return s
|
||||
}
|
||||
|
||||
// Check mounts for overlay/containers hints.
|
||||
if data, err := os.ReadFile("/proc/self/mountinfo"); err == nil {
|
||||
lower := strings.ToLower(string(data))
|
||||
switch {
|
||||
case strings.Contains(lower, "/docker/"):
|
||||
return "docker"
|
||||
case strings.Contains(lower, "/containers/overlay-containers/") || strings.Contains(lower, "/lib/containers/"):
|
||||
return "podman"
|
||||
case strings.Contains(lower, "/kubelet/"):
|
||||
return "kubernetes"
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func fileExists(p string) bool {
|
||||
if st, err := os.Stat(p); err == nil && !st.IsDir() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseCgroupForContainer() string {
|
||||
// cgroup v1 & v2 paths can contain docker, kubepods, containerd, crio, lxc, podman
|
||||
if data, err := os.ReadFile("/proc/self/cgroup"); err == nil {
|
||||
lower := strings.ToLower(string(data))
|
||||
switch {
|
||||
case strings.Contains(lower, "docker"):
|
||||
return "docker"
|
||||
case strings.Contains(lower, "containerd"):
|
||||
return "container"
|
||||
case strings.Contains(lower, "kubepods") || strings.Contains(lower, "kubelet"):
|
||||
return "kubernetes"
|
||||
case strings.Contains(lower, "crio"):
|
||||
return "container"
|
||||
case strings.Contains(lower, "lxc"):
|
||||
return "lxc"
|
||||
case strings.Contains(lower, "podman"):
|
||||
return "podman"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@@ -6,5 +6,9 @@ import (
|
||||
|
||||
func TestVirtualized(t *testing.T) {
|
||||
virt := Virtualized()
|
||||
cpuid_result := detectByCPUID()
|
||||
container_result := detectContainer()
|
||||
t.Logf("Virtualization type: %s", virt)
|
||||
t.Logf("CPUID result: %s", cpuid_result)
|
||||
t.Logf("Container result: %s", container_result)
|
||||
}
|
||||
|
Reference in New Issue
Block a user