From 1464099024cc194e0f7c2b766055e556293e9249 Mon Sep 17 00:00:00 2001 From: Shirou WAKAYAMA Date: Tue, 20 May 2014 19:36:19 +0900 Subject: [PATCH] add detecting virtualization system on Linux. --- host.go | 17 +++++----- host_freebsd.go | 37 +++++++++++++++++++--- host_linux.go | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- test/host_test.go | 2 +- 4 files changed, 135 insertions(+), 15 deletions(-) diff --git a/host.go b/host.go index ae3b327..a204231 100644 --- a/host.go +++ b/host.go @@ -7,13 +7,16 @@ import ( // A HostInfoStat describes the host status. // This is not in the psutil but it useful. type HostInfoStat struct { - Hostname string `json:"hostname"` - Uptime uint64 `json:"uptime"` - Procs uint64 `json:"procs"` // number of processes - OS string `json:"os"` // ex: freebsd, linux - Platform string `json:"platform"` // ex: ubuntu, linuxmint - PlatformFamily string `json:"platformFamily"` // ex: debian, rhel - PlatformVersion string `json:"platformVersion"` + Hostname string `json:"hostname"` + Uptime uint64 `json:"uptime"` + Procs uint64 `json:"procs"` // number of processes + OS string `json:"os"` // ex: freebsd, linux + Platform string `json:"platform"` // ex: ubuntu, linuxmint + PlatformFamily string `json:"platformFamily"` // ex: debian, rhel + PlatformVersion string `json:"platformVersion"` + VirtualizationSystem string `json:"virtualizationSystem"` + VirtualizationRole string `json:"virtualizationRole"` // guest or host + } type UserStat struct { diff --git a/host_freebsd.go b/host_freebsd.go index 71f05f8..bb8bdb7 100644 --- a/host_freebsd.go +++ b/host_freebsd.go @@ -26,14 +26,16 @@ func HostInfo() (*HostInfoStat, error) { } ret.Hostname = hostname - out, err := exec.Command("uname", "-s").Output() + platform, family, version, err := GetPlatformInformation() if err == nil { - ret.Platform = strings.ToLower(strings.TrimSpace(string(out))) + ret.Platform = platform + ret.PlatformFamily = family + ret.PlatformVersion = version } - - out, err = exec.Command("uname", "-r").Output() + system, role, err := GetVirtualization() if err == nil { - ret.PlatformVersion = strings.ToLower(strings.TrimSpace(string(out))) + ret.VirtualizationSystem = system + ret.VirtualizationRole = role } values, err := doSysctrl("kern.boottime") @@ -101,3 +103,28 @@ func Users() ([]UserStat, error) { return ret, nil } + +func GetPlatformInformation() (string, string, string, error) { + platform := "" + family := "" + version := "" + + out, err := exec.Command("uname", "-s").Output() + if err == nil { + platform = strings.ToLower(strings.TrimSpace(string(out))) + } + + out, err = exec.Command("uname", "-r").Output() + if err == nil { + version = strings.ToLower(strings.TrimSpace(string(out))) + } + + return platform, family, version, nil +} + +func GetVirtualization() (string, string, error) { + system := "" + role := "" + + return system, role, nil +} diff --git a/host_linux.go b/host_linux.go index 6733d39..4960b0d 100644 --- a/host_linux.go +++ b/host_linux.go @@ -32,12 +32,17 @@ func HostInfo() (*HostInfoStat, error) { OS: runtime.GOOS, } - platform, family, version, err := getPlatformInformation() + platform, family, version, err := GetPlatformInformation() if err == nil { ret.Platform = platform ret.PlatformFamily = family ret.PlatformVersion = version } + system, role, err := GetVirtualization() + if err == nil { + ret.VirtualizationSystem = system + ret.VirtualizationRole = role + } uptime, err := BootTime() if err == nil { ret.Uptime = uptime @@ -145,7 +150,7 @@ func getLSB() (*LSB, error) { return ret, nil } -func getPlatformInformation() (string, string, string, error) { +func GetPlatformInformation() (string, string, string, error) { platform := "" family := "" version := "" @@ -252,3 +257,88 @@ func getRedhatishVersion(contents []string) (string, error) { func getRedhatishPlatform(contents []string) (string, error) { return "", nil } + +func GetVirtualization() (string, string, error) { + var system string + var role string + + if pathExists("/proc/xen") { + system = "xen" + role = "guest" // assume guest + + if pathExists("/proc/xen/capabilities") { + contents, err := readLines("/proc/xen/capabilities") + if err == nil { + if stringContains(contents, "control_d") { + role = "host" + } + } + } + } + if pathExists("/proc/modules") { + contents, err := readLines("/proc/modules") + if err == nil { + if stringContains(contents, "kvm") { + system = "kvm" + role = "host" + } else if stringContains(contents, "vboxdrv") { + system = "vbox" + role = "host" + } else if stringContains(contents, "vboxguest") { + system = "vbox" + role = "guest" + } + } + } + + if pathExists("/proc/cpuinfo") { + contents, err := readLines("/proc/cpuinfo") + if err == nil { + if stringContains(contents, "QEMU Virtual CPU") || + stringContains(contents, "Common KVM processor") || + stringContains(contents, "Common 32-bit KVM processor") { + system = "kvm" + role = "guest" + } + } + } + + if pathExists("/proc/bc/0") { + system = "openvz" + role = "host" + } else if pathExists("/proc/vz") { + system = "openvz" + role = "guest" + } + + // not use dmidecode because it requires root + + if pathExists("/proc/self/status") { + contents, err := readLines("/proc/self/status") + if err == nil { + + if stringContains(contents, "s_context:") || + stringContains(contents, "VxID:") { + system = "linux-vserver" + } + // TODO: guest or host + } + } + + if pathExists("/proc/self/cgroup") { + contents, err := readLines("/proc/self/cgroup") + if err == nil { + + if stringContains(contents, "lxc") || + stringContains(contents, "docker") { + system = "lxc" + role = "guest" + } else if pathExists("/usr/bin/lxc-version") { // TODO: which + system = "lxc" + role = "host" + } + } + } + + return system, role, nil +} diff --git a/test/host_test.go b/test/host_test.go index 3c16631..5724b15 100644 --- a/test/host_test.go +++ b/test/host_test.go @@ -49,7 +49,7 @@ func TestHostInfoStat_String(t *testing.T) { OS: "linux", Platform: "ubuntu", } - e := `{"hostname":"test","uptime":3000,"procs":100,"os":"linux","platform":"ubuntu","platformFamily":"","platformVersion":""}` + e := `{"hostname":"test","uptime":3000,"procs":100,"os":"linux","platform":"ubuntu","platformFamily":"","platformVersion":"","virtualizationSystem":"","virtualizationRole":""}` if e != fmt.Sprintf("%v", v) { t.Errorf("HostInfoStat string is invalid: %v", v) }