From b7760bb5a6e166b42135a9dd61aadbb603011638 Mon Sep 17 00:00:00 2001 From: James Nugent Date: Tue, 14 Mar 2017 14:40:30 -0500 Subject: [PATCH] memory: Add basic Solaris VirtualMemory() support This commit adds support for VirtualMemory() in package mem. The support only extends to total memory capcity, since that is all that is required in Nomad. It does take into account global versus non-global zones, and does not use cgo. This has been tested inside a zone in the Joyent public cloud for a non-global zone, and in the global zone of a SmartOS virtual machine. --- mem/mem_fallback.go | 2 +- mem/mem_solaris.go | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 mem/mem_solaris.go diff --git a/mem/mem_fallback.go b/mem/mem_fallback.go index b7284b2..e61fe4b 100644 --- a/mem/mem_fallback.go +++ b/mem/mem_fallback.go @@ -1,4 +1,4 @@ -// +build !darwin,!linux,!freebsd,!openbsd,!windows +// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows package mem diff --git a/mem/mem_solaris.go b/mem/mem_solaris.go new file mode 100644 index 0000000..9c5111b --- /dev/null +++ b/mem/mem_solaris.go @@ -0,0 +1,109 @@ +package mem + +import ( + "errors" + "fmt" + "os/exec" + "regexp" + "strconv" + "strings" + + "github.com/shirou/gopsutil/internal/common" +) + +// VirtualMemory for Solaris is a minimal implementation which only returns +// what Nomad needs. It does take into account global vs zone, however. +func VirtualMemory() (*VirtualMemoryStat, error) { + result := &VirtualMemoryStat{} + + zoneName, err := zoneName() + if err != nil { + return nil, err + } + + if zoneName == "global" { + cap, err := globalZoneMemoryCapacity() + if err != nil { + return nil, err + } + result.Total = cap + } else { + cap, err := nonGlobalZoneMemoryCapacity() + if err != nil { + return nil, err + } + result.Total = cap + } + + return result, nil +} + +func SwapMemory() (*SwapMemoryStat, error) { + return nil, common.ErrNotImplementedError +} + +func zoneName() (string, error) { + zonename, err := exec.LookPath("/usr/bin/zonename") + if err != nil { + return "", err + } + + out, err := invoke.Command(zonename) + if err != nil { + return "", err + } + + return strings.TrimSpace(string(out)), nil +} + +var globalZoneMemoryCapacityMatch = regexp.MustCompile(`Memory size: ([\d]+) Megabytes`) + +func globalZoneMemoryCapacity() (uint64, error) { + prtconf, err := exec.LookPath("/usr/sbin/prtconf") + if err != nil { + return 0, err + } + + out, err := invoke.Command(prtconf) + if err != nil { + return 0, err + } + + match := globalZoneMemoryCapacityMatch.FindAllStringSubmatch(string(out), -1) + if len(match) != 1 { + return 0, errors.New("Memory size not contained in output of /usr/sbin/prtconf") + } + + totalMB, err := strconv.ParseUint(match[0][1], 10, 64) + if err != nil { + return 0, err + } + + return totalMB * 1024 * 1024, nil +} + +var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`) + +func nonGlobalZoneMemoryCapacity() (uint64, error) { + kstat, err := exec.LookPath("/usr/bin/kstat") + if err != nil { + return 0, err + } + + out, err := invoke.Command(kstat, "-p", "-c", "zone_memory_cap", "memory_cap:*:*:physcap") + if err != nil { + return 0, err + } + + kstats := kstatMatch.FindAllStringSubmatch(string(out), -1) + if len(kstats) != 1 { + return 0, fmt.Errorf("Expected 1 kstat, found %d", len(kstats)) + } + + memSizeBytes, err := strconv.ParseUint(kstats[0][2], 10, 64) + if err != nil { + return 0, err + } + + return memSizeBytes, nil +}