providers/windows/host_windows.go (178 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package windows import ( "context" "errors" "fmt" "os" "strings" "syscall" "time" stdwindows "golang.org/x/sys/windows" windows "github.com/elastic/go-windows" "github.com/elastic/go-sysinfo/internal/registry" "github.com/elastic/go-sysinfo/providers/shared" "github.com/elastic/go-sysinfo/types" ) func init() { registry.Register(windowsSystem{}) } type windowsSystem struct{} func (s windowsSystem) Host() (types.Host, error) { return newHost() } type host struct { info types.HostInfo } func (h *host) Info() types.HostInfo { return h.info } func (h *host) CPUTime() (types.CPUTimes, error) { idle, kernel, user, err := windows.GetSystemTimes() if err != nil { return types.CPUTimes{}, err } return types.CPUTimes{ System: kernel, User: user, Idle: idle, }, nil } func (h *host) Memory() (*types.HostMemoryInfo, error) { mem, err := windows.GlobalMemoryStatusEx() if err != nil { return nil, err } return &types.HostMemoryInfo{ Total: mem.TotalPhys, Used: mem.TotalPhys - mem.AvailPhys, Free: mem.AvailPhys, Available: mem.AvailPhys, VirtualTotal: mem.TotalPageFile, VirtualUsed: mem.TotalPageFile - mem.AvailPageFile, VirtualFree: mem.AvailPageFile, }, nil } func (h *host) FQDNWithContext(_ context.Context) (string, error) { fqdn, err := getComputerNameEx(stdwindows.ComputerNamePhysicalDnsFullyQualified) if err != nil { return "", fmt.Errorf("could not get windows FQDN: %s", err) } return strings.TrimSuffix(fqdn, "."), nil } func (h *host) FQDN() (string, error) { return h.FQDNWithContext(context.Background()) } func newHost() (*host, error) { h := &host{} r := &reader{} r.architecture(h) r.nativeArchitecture(h) r.bootTime(h) r.hostname(h) r.network(h) r.kernelVersion(h) r.os(h) r.time(h) r.uniqueID(h) return h, r.Err() } type reader struct { errs []error } func (r *reader) addErr(err error) bool { if err != nil { if !errors.Is(err, types.ErrNotImplemented) { r.errs = append(r.errs, err) } return true } return false } func (r *reader) Err() error { if len(r.errs) > 0 { return errors.Join(r.errs...) } return nil } func (r *reader) architecture(h *host) { v, err := Architecture() if r.addErr(err) { return } h.info.Architecture = v } func (r *reader) nativeArchitecture(h *host) { v, err := NativeArchitecture() if r.addErr(err) { return } h.info.NativeArchitecture = v } func (r *reader) bootTime(h *host) { v, err := BootTime() if r.addErr(err) { return } h.info.BootTime = v } func (r *reader) hostname(h *host) { v, err := os.Hostname() if r.addErr(err) { return } h.info.Hostname = v } func getComputerNameEx(name uint32) (string, error) { size := uint32(64) for { buff := make([]uint16, size) err := stdwindows.GetComputerNameEx( name, &buff[0], &size) if err == nil { return syscall.UTF16ToString(buff[:size]), nil } // ERROR_MORE_DATA means buff is too small and size is set to the // number of bytes needed to store the FQDN. For details, see // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getcomputernameexw#return-value if errors.Is(err, syscall.ERROR_MORE_DATA) { // Safeguard to avoid an infinite loop. if size <= uint32(len(buff)) { return "", fmt.Errorf( "windows.GetComputerNameEx returned ERROR_MORE_DATA, " + "but data size should fit into buffer") } else { // Grow the buffer and try again. buff = make([]uint16, size) continue } } return "", fmt.Errorf("could not get windows FQDN: could not get windows.ComputerNamePhysicalDnsFullyQualified: %w", err) } } func (r *reader) network(h *host) { ips, macs, err := shared.Network() if r.addErr(err) { return } h.info.IPs = ips h.info.MACs = macs } func (r *reader) kernelVersion(h *host) { v, err := KernelVersion() if r.addErr(err) { return } h.info.KernelVersion = v } func (r *reader) os(h *host) { v, err := OperatingSystem() if r.addErr(err) { return } h.info.OS = v } func (r *reader) time(h *host) { h.info.Timezone, h.info.TimezoneOffsetSec = time.Now().Zone() } func (r *reader) uniqueID(h *host) { v, err := MachineID() if r.addErr(err) { return } h.info.UniqueID = v }