// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 //go:build !openbsd package hostutil import ( "context" "fmt" "time" "github.com/hashicorp/go-multierror" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/mem" ) // HostInfo holds all the information that gets captured on the host. The // set of information captured depends on the host operating system. For more // information, refer to: https://github.com/shirou/gopsutil#current-status type HostInfo struct { // Timestamp returns the timestamp in UTC on the collection time. Timestamp time.Time `json:"timestamp"` // CPU returns information about the CPU such as family, model, cores, etc. CPU []cpu.InfoStat `json:"cpu"` // CPUTimes returns statistics on CPU usage represented in Jiffies. CPUTimes []cpu.TimesStat `json:"cpu_times"` // Disk returns statitics on disk usage for all accessible partitions. Disk []*disk.UsageStat `json:"disk"` // Host returns general host information such as hostname, platform, uptime, // kernel version, etc. Host *HostInfoStat `json:"host"` // Memory contains statistics about the memory such as total, available, and // used memory in number of bytes. Memory *VirtualMemoryStat `json:"memory"` } // CollectHostInfo returns information on the host, which includes general // host status, CPU, memory, and disk utilization. // // The function does a best-effort capture on the most information possible, // continuing on capture errors encountered and appending them to a resulting // multierror.Error that gets returned at the end. func CollectHostInfo(ctx context.Context) (*HostInfo, error) { var retErr *multierror.Error info := &HostInfo{Timestamp: time.Now().UTC()} if h, err := CollectHostInfoStat(ctx); err != nil { retErr = multierror.Append(retErr, &HostInfoError{"host", err}) } else { info.Host = h } if v, err := CollectHostMemory(ctx); err != nil { retErr = multierror.Append(retErr, &HostInfoError{"memory", err}) } else { info.Memory = v } parts, err := disk.PartitionsWithContext(ctx, false) if err != nil { retErr = multierror.Append(retErr, &HostInfoError{"disk", err}) } else { var usage []*disk.UsageStat for i, part := range parts { u, err := disk.UsageWithContext(ctx, part.Mountpoint) if err != nil { retErr = multierror.Append(retErr, &HostInfoError{fmt.Sprintf("disk.%d", i), err}) continue } usage = append(usage, u) } info.Disk = usage } if c, err := cpu.InfoWithContext(ctx); err != nil { retErr = multierror.Append(retErr, &HostInfoError{"cpu", err}) } else { info.CPU = c } t, err := cpu.TimesWithContext(ctx, true) if err != nil { retErr = multierror.Append(retErr, &HostInfoError{"cpu_times", err}) } else { info.CPUTimes = t } return info, retErr.ErrorOrNil() } func CollectHostMemory(ctx context.Context) (*VirtualMemoryStat, error) { m, err := mem.VirtualMemoryWithContext(ctx) if err != nil { return nil, err } return &VirtualMemoryStat{ Total: m.Total, Available: m.Available, Used: m.Used, UsedPercent: m.UsedPercent, Free: m.Free, Active: m.Active, Inactive: m.Inactive, Wired: m.Wired, Laundry: m.Laundry, Buffers: m.Buffers, Cached: m.Cached, Writeback: m.WriteBack, Dirty: m.Dirty, WritebackTmp: m.WriteBackTmp, Shared: m.Shared, Slab: m.Slab, SReclaimable: m.Sreclaimable, SUnreclaim: m.Sunreclaim, PageTables: m.PageTables, SwapCached: m.SwapCached, CommitLimit: m.CommitLimit, CommittedAS: m.CommittedAS, HighTotal: m.HighTotal, HighFree: m.HighFree, LowTotal: m.LowTotal, LowFree: m.LowFree, SwapTotal: m.SwapTotal, SwapFree: m.SwapFree, Mapped: m.Mapped, VMallocTotal: m.VmallocTotal, VMallocUsed: m.VmallocUsed, VMallocChunk: m.VmallocChunk, HugePagesTotal: m.HugePagesTotal, HugePagesFree: m.HugePagesFree, HugePageSize: m.HugePageSize, }, nil } func CollectHostInfoStat(ctx context.Context) (*HostInfoStat, error) { h, err := host.InfoWithContext(ctx) if err != nil { return nil, err } return &HostInfoStat{ Hostname: h.Hostname, Uptime: h.Uptime, BootTime: h.BootTime, Procs: h.Procs, OS: h.OS, Platform: h.Platform, PlatformFamily: h.PlatformFamily, PlatformVersion: h.PlatformVersion, KernelVersion: h.KernelVersion, KernelArch: h.KernelArch, VirtualizationSystem: h.VirtualizationSystem, VirtualizationRole: h.VirtualizationRole, HostID: h.HostID, }, nil }