mirror of
https://github.com/kemko/nomad.git
synced 2026-01-15 06:45:41 +03:00
Previously used `github.com/shirou/gopsutil`[1], used some GPL code [2]. This was somewhat unintentional, and was addressed later [3]. Due to being late in the cycle of Nomad release when this is noticed, and time elapsed since we updated the dependency, we want to be conservative in our package updates. As such, we opted to go with forking the repo to use the previously used version with the GPL removal code commit, done in [4]. [1]5776ff9c7c[2]5776ff9c7c/host/include/smc.c[3]c95755e4bc[4]62d5761ddb
228 lines
4.7 KiB
Go
228 lines
4.7 KiB
Go
// +build darwin
|
|
|
|
package host
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"sync/atomic"
|
|
"time"
|
|
"unsafe"
|
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
|
"github.com/shirou/gopsutil/process"
|
|
)
|
|
|
|
// from utmpx.h
|
|
const USER_PROCESS = 7
|
|
|
|
func Info() (*InfoStat, error) {
|
|
return InfoWithContext(context.Background())
|
|
}
|
|
|
|
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
|
ret := &InfoStat{
|
|
OS: runtime.GOOS,
|
|
PlatformFamily: "darwin",
|
|
}
|
|
|
|
hostname, err := os.Hostname()
|
|
if err == nil {
|
|
ret.Hostname = hostname
|
|
}
|
|
|
|
uname, err := exec.LookPath("uname")
|
|
if err == nil {
|
|
out, err := invoke.Command(uname, "-r")
|
|
if err == nil {
|
|
ret.KernelVersion = strings.ToLower(strings.TrimSpace(string(out)))
|
|
}
|
|
}
|
|
|
|
platform, family, pver, err := PlatformInformation()
|
|
if err == nil {
|
|
ret.Platform = platform
|
|
ret.PlatformFamily = family
|
|
ret.PlatformVersion = pver
|
|
}
|
|
|
|
system, role, err := Virtualization()
|
|
if err == nil {
|
|
ret.VirtualizationSystem = system
|
|
ret.VirtualizationRole = role
|
|
}
|
|
|
|
boot, err := BootTime()
|
|
if err == nil {
|
|
ret.BootTime = boot
|
|
ret.Uptime = uptime(boot)
|
|
}
|
|
|
|
procs, err := process.Pids()
|
|
if err == nil {
|
|
ret.Procs = uint64(len(procs))
|
|
}
|
|
|
|
values, err := common.DoSysctrl("kern.uuid")
|
|
if err == nil && len(values) == 1 && values[0] != "" {
|
|
ret.HostID = strings.ToLower(values[0])
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
// cachedBootTime must be accessed via atomic.Load/StoreUint64
|
|
var cachedBootTime uint64
|
|
|
|
func BootTime() (uint64, error) {
|
|
return BootTimeWithContext(context.Background())
|
|
}
|
|
|
|
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
|
t := atomic.LoadUint64(&cachedBootTime)
|
|
if t != 0 {
|
|
return t, nil
|
|
}
|
|
values, err := common.DoSysctrl("kern.boottime")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
// ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
|
|
v := strings.Replace(values[2], ",", "", 1)
|
|
boottime, err := strconv.ParseInt(v, 10, 64)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
t = uint64(boottime)
|
|
atomic.StoreUint64(&cachedBootTime, t)
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func uptime(boot uint64) uint64 {
|
|
return uint64(time.Now().Unix()) - boot
|
|
}
|
|
|
|
func Uptime() (uint64, error) {
|
|
return UptimeWithContext(context.Background())
|
|
}
|
|
|
|
func UptimeWithContext(ctx context.Context) (uint64, error) {
|
|
boot, err := BootTime()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return uptime(boot), nil
|
|
}
|
|
|
|
func Users() ([]UserStat, error) {
|
|
return UsersWithContext(context.Background())
|
|
}
|
|
|
|
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
|
utmpfile := "/var/run/utmpx"
|
|
var ret []UserStat
|
|
|
|
file, err := os.Open(utmpfile)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
defer file.Close()
|
|
|
|
buf, err := ioutil.ReadAll(file)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
u := Utmpx{}
|
|
entrySize := int(unsafe.Sizeof(u))
|
|
count := len(buf) / entrySize
|
|
|
|
for i := 0; i < count; i++ {
|
|
b := buf[i*entrySize : i*entrySize+entrySize]
|
|
|
|
var u Utmpx
|
|
br := bytes.NewReader(b)
|
|
err := binary.Read(br, binary.LittleEndian, &u)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if u.Type != USER_PROCESS {
|
|
continue
|
|
}
|
|
user := UserStat{
|
|
User: common.IntToString(u.User[:]),
|
|
Terminal: common.IntToString(u.Line[:]),
|
|
Host: common.IntToString(u.Host[:]),
|
|
Started: int(u.Tv.Sec),
|
|
}
|
|
ret = append(ret, user)
|
|
}
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
func PlatformInformation() (string, string, string, error) {
|
|
return PlatformInformationWithContext(context.Background())
|
|
}
|
|
|
|
func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
|
|
platform := ""
|
|
family := ""
|
|
pver := ""
|
|
|
|
sw_vers, err := exec.LookPath("sw_vers")
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
uname, err := exec.LookPath("uname")
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
|
|
out, err := invoke.Command(uname, "-s")
|
|
if err == nil {
|
|
platform = strings.ToLower(strings.TrimSpace(string(out)))
|
|
}
|
|
|
|
out, err = invoke.Command(sw_vers, "-productVersion")
|
|
if err == nil {
|
|
pver = strings.ToLower(strings.TrimSpace(string(out)))
|
|
}
|
|
|
|
return platform, family, pver, nil
|
|
}
|
|
|
|
func Virtualization() (string, string, error) {
|
|
return VirtualizationWithContext(context.Background())
|
|
}
|
|
|
|
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
|
return "", "", common.ErrNotImplementedError
|
|
}
|
|
|
|
func KernelVersion() (string, error) {
|
|
return KernelVersionWithContext(context.Background())
|
|
}
|
|
|
|
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
|
_, _, version, err := PlatformInformation()
|
|
return version, err
|
|
}
|
|
|
|
func SensorsTemperatures() ([]TemperatureStat, error) {
|
|
return SensorsTemperaturesWithContext(context.Background())
|
|
}
|
|
|
|
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
|
return []TemperatureStat{}, common.ErrNotImplementedError
|
|
}
|