 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			399 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2012 VMware, Inc.
 | |
| 
 | |
| package gosigar
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"syscall"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/elastic/gosigar/sys/windows"
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// version is Windows version of the host OS.
 | |
| 	version = windows.GetWindowsVersion()
 | |
| 
 | |
| 	// processQueryLimitedInfoAccess is set to PROCESS_QUERY_INFORMATION for Windows
 | |
| 	// 2003 and XP where PROCESS_QUERY_LIMITED_INFORMATION is unknown. For all newer
 | |
| 	// OS versions it is set to PROCESS_QUERY_LIMITED_INFORMATION.
 | |
| 	processQueryLimitedInfoAccess = windows.PROCESS_QUERY_LIMITED_INFORMATION
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	if !version.IsWindowsVistaOrGreater() {
 | |
| 		// PROCESS_QUERY_LIMITED_INFORMATION cannot be used on 2003 or XP.
 | |
| 		processQueryLimitedInfoAccess = syscall.PROCESS_QUERY_INFORMATION
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (self *LoadAverage) Get() error {
 | |
| 	return ErrNotImplemented{runtime.GOOS}
 | |
| }
 | |
| 
 | |
| func (self *FDUsage) Get() error {
 | |
| 	return ErrNotImplemented{runtime.GOOS}
 | |
| }
 | |
| 
 | |
| func (self *ProcEnv) Get(pid int) error {
 | |
| 	return ErrNotImplemented{runtime.GOOS}
 | |
| }
 | |
| 
 | |
| func (self *ProcExe) Get(pid int) error {
 | |
| 	return ErrNotImplemented{runtime.GOOS}
 | |
| }
 | |
| 
 | |
| func (self *ProcFDUsage) Get(pid int) error {
 | |
| 	return ErrNotImplemented{runtime.GOOS}
 | |
| }
 | |
| 
 | |
| func (self *Uptime) Get() error {
 | |
| 	// Minimum supported OS is Windows Vista.
 | |
| 	if !version.IsWindowsVistaOrGreater() {
 | |
| 		return ErrNotImplemented{runtime.GOOS}
 | |
| 	}
 | |
| 	uptimeMs, err := windows.GetTickCount64()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "failed to get boot time using GetTickCount64 api")
 | |
| 	}
 | |
| 	self.Length = float64(time.Duration(uptimeMs)*time.Millisecond) / float64(time.Second)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *Mem) Get() error {
 | |
| 	memoryStatusEx, err := windows.GlobalMemoryStatusEx()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "GlobalMemoryStatusEx failed")
 | |
| 	}
 | |
| 
 | |
| 	self.Total = memoryStatusEx.TotalPhys
 | |
| 	self.Free = memoryStatusEx.AvailPhys
 | |
| 	self.Used = self.Total - self.Free
 | |
| 	self.ActualFree = self.Free
 | |
| 	self.ActualUsed = self.Used
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *Swap) Get() error {
 | |
| 	memoryStatusEx, err := windows.GlobalMemoryStatusEx()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "GlobalMemoryStatusEx failed")
 | |
| 	}
 | |
| 
 | |
| 	self.Total = memoryStatusEx.TotalPageFile
 | |
| 	self.Free = memoryStatusEx.AvailPageFile
 | |
| 	self.Used = self.Total - self.Free
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *HugeTLBPages) Get() error {
 | |
| 	return ErrNotImplemented{runtime.GOOS}
 | |
| }
 | |
| 
 | |
| func (self *Cpu) Get() error {
 | |
| 	idle, kernel, user, err := windows.GetSystemTimes()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "GetSystemTimes failed")
 | |
| 	}
 | |
| 
 | |
| 	// CPU times are reported in milliseconds by gosigar.
 | |
| 	self.Idle = uint64(idle / time.Millisecond)
 | |
| 	self.Sys = uint64(kernel / time.Millisecond)
 | |
| 	self.User = uint64(user / time.Millisecond)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *CpuList) Get() error {
 | |
| 	cpus, err := windows.NtQuerySystemProcessorPerformanceInformation()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "NtQuerySystemProcessorPerformanceInformation failed")
 | |
| 	}
 | |
| 
 | |
| 	self.List = make([]Cpu, 0, len(cpus))
 | |
| 	for _, cpu := range cpus {
 | |
| 		self.List = append(self.List, Cpu{
 | |
| 			Idle: uint64(cpu.IdleTime / time.Millisecond),
 | |
| 			Sys:  uint64(cpu.KernelTime / time.Millisecond),
 | |
| 			User: uint64(cpu.UserTime / time.Millisecond),
 | |
| 		})
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *FileSystemList) Get() error {
 | |
| 	drives, err := windows.GetAccessPaths()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "GetAccessPaths failed")
 | |
| 	}
 | |
| 	for _, drive := range drives {
 | |
| 		dt, err := windows.GetDriveType(drive)
 | |
| 		if err != nil {
 | |
| 			return errors.Wrapf(err, "GetDriveType failed")
 | |
| 		}
 | |
| 		fsType, err := windows.GetFilesystemType(drive)
 | |
| 		if err != nil {
 | |
| 			return errors.Wrapf(err, "GetFilesystemType failed")
 | |
| 		}
 | |
| 		self.List = append(self.List, FileSystem{
 | |
| 			DirName:     drive,
 | |
| 			DevName:     drive,
 | |
| 			TypeName:    dt.String(),
 | |
| 			SysTypeName: fsType,
 | |
| 		})
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Get retrieves a list of all process identifiers (PIDs) in the system.
 | |
| func (self *ProcList) Get() error {
 | |
| 	pids, err := windows.EnumProcesses()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "EnumProcesses failed")
 | |
| 	}
 | |
| 
 | |
| 	// Convert uint32 PIDs to int.
 | |
| 	self.List = make([]int, 0, len(pids))
 | |
| 	for _, pid := range pids {
 | |
| 		self.List = append(self.List, int(pid))
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *ProcState) Get(pid int) error {
 | |
| 	var errs []error
 | |
| 
 | |
| 	var err error
 | |
| 	self.Name, err = getProcName(pid)
 | |
| 	if err != nil {
 | |
| 		errs = append(errs, errors.Wrap(err, "getProcName failed"))
 | |
| 	}
 | |
| 
 | |
| 	self.State, err = getProcStatus(pid)
 | |
| 	if err != nil {
 | |
| 		errs = append(errs, errors.Wrap(err, "getProcStatus failed"))
 | |
| 	}
 | |
| 
 | |
| 	self.Ppid, err = getParentPid(pid)
 | |
| 	if err != nil {
 | |
| 		errs = append(errs, errors.Wrap(err, "getParentPid failed"))
 | |
| 	}
 | |
| 
 | |
| 	// getProcCredName will often fail when run as a non-admin user. This is
 | |
| 	// caused by strict ACL of the process token belonging to other users.
 | |
| 	// Instead of failing completely, ignore this error and still return most
 | |
| 	// data with an empty Username.
 | |
| 	self.Username, _ = getProcCredName(pid)
 | |
| 
 | |
| 	if len(errs) > 0 {
 | |
| 		errStrs := make([]string, 0, len(errs))
 | |
| 		for _, e := range errs {
 | |
| 			errStrs = append(errStrs, e.Error())
 | |
| 		}
 | |
| 		return errors.New(strings.Join(errStrs, "; "))
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // getProcName returns the process name associated with the PID.
 | |
| func getProcName(pid int) (string, error) {
 | |
| 	handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess, false, uint32(pid))
 | |
| 	if err != nil {
 | |
| 		return "", errors.Wrapf(err, "OpenProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(handle)
 | |
| 
 | |
| 	filename, err := windows.GetProcessImageFileName(handle)
 | |
| 	if err != nil {
 | |
| 		return "", errors.Wrapf(err, "GetProcessImageFileName failed for pid=%v", pid)
 | |
| 	}
 | |
| 
 | |
| 	return filepath.Base(filename), nil
 | |
| }
 | |
| 
 | |
| // getProcStatus returns the status of a process.
 | |
| func getProcStatus(pid int) (RunState, error) {
 | |
| 	handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess, false, uint32(pid))
 | |
| 	if err != nil {
 | |
| 		return RunStateUnknown, errors.Wrapf(err, "OpenProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(handle)
 | |
| 
 | |
| 	var exitCode uint32
 | |
| 	err = syscall.GetExitCodeProcess(handle, &exitCode)
 | |
| 	if err != nil {
 | |
| 		return RunStateUnknown, errors.Wrapf(err, "GetExitCodeProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 
 | |
| 	if exitCode == 259 { //still active
 | |
| 		return RunStateRun, nil
 | |
| 	}
 | |
| 	return RunStateSleep, nil
 | |
| }
 | |
| 
 | |
| // getParentPid returns the parent process ID of a process.
 | |
| func getParentPid(pid int) (int, error) {
 | |
| 	handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess, false, uint32(pid))
 | |
| 	if err != nil {
 | |
| 		return RunStateUnknown, errors.Wrapf(err, "OpenProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(handle)
 | |
| 
 | |
| 	procInfo, err := windows.NtQueryProcessBasicInformation(handle)
 | |
| 	if err != nil {
 | |
| 		return 0, errors.Wrapf(err, "NtQueryProcessBasicInformation failed for pid=%v", pid)
 | |
| 	}
 | |
| 
 | |
| 	return int(procInfo.InheritedFromUniqueProcessID), nil
 | |
| }
 | |
| 
 | |
| func getProcCredName(pid int) (string, error) {
 | |
| 	handle, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid))
 | |
| 	if err != nil {
 | |
| 		return "", errors.Wrapf(err, "OpenProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(handle)
 | |
| 
 | |
| 	// Find process token via win32.
 | |
| 	var token syscall.Token
 | |
| 	err = syscall.OpenProcessToken(handle, syscall.TOKEN_QUERY, &token)
 | |
| 	if err != nil {
 | |
| 		return "", errors.Wrapf(err, "OpenProcessToken failed for pid=%v", pid)
 | |
| 	}
 | |
| 	// Close token to prevent handle leaks.
 | |
| 	defer token.Close()
 | |
| 
 | |
| 	// Find the token user.
 | |
| 	tokenUser, err := token.GetTokenUser()
 | |
| 	if err != nil {
 | |
| 		return "", errors.Wrapf(err, "GetTokenInformation failed for pid=%v", pid)
 | |
| 	}
 | |
| 
 | |
| 	// Look up domain account by SID.
 | |
| 	account, domain, _, err := tokenUser.User.Sid.LookupAccount("")
 | |
| 	if err != nil {
 | |
| 		sid, sidErr := tokenUser.User.Sid.String()
 | |
| 		if sidErr != nil {
 | |
| 			return "", errors.Wrapf(err, "failed while looking up account name for pid=%v", pid)
 | |
| 		}
 | |
| 		return "", errors.Wrapf(err, "failed while looking up account name for SID=%v of pid=%v", sid, pid)
 | |
| 	}
 | |
| 
 | |
| 	return fmt.Sprintf(`%s\%s`, domain, account), nil
 | |
| }
 | |
| 
 | |
| func (self *ProcMem) Get(pid int) error {
 | |
| 	handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess|windows.PROCESS_VM_READ, false, uint32(pid))
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "OpenProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(handle)
 | |
| 
 | |
| 	counters, err := windows.GetProcessMemoryInfo(handle)
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "GetProcessMemoryInfo failed for pid=%v", pid)
 | |
| 	}
 | |
| 
 | |
| 	self.Resident = uint64(counters.WorkingSetSize)
 | |
| 	self.Size = uint64(counters.PrivateUsage)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *ProcTime) Get(pid int) error {
 | |
| 	cpu, err := getProcTimes(pid)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Windows epoch times are expressed as time elapsed since midnight on
 | |
| 	// January 1, 1601 at Greenwich, England. This converts the Filetime to
 | |
| 	// unix epoch in milliseconds.
 | |
| 	self.StartTime = uint64(cpu.CreationTime.Nanoseconds() / 1e6)
 | |
| 
 | |
| 	// Convert to millis.
 | |
| 	self.User = uint64(windows.FiletimeToDuration(&cpu.UserTime).Nanoseconds() / 1e6)
 | |
| 	self.Sys = uint64(windows.FiletimeToDuration(&cpu.KernelTime).Nanoseconds() / 1e6)
 | |
| 	self.Total = self.User + self.Sys
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func getProcTimes(pid int) (*syscall.Rusage, error) {
 | |
| 	handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess, false, uint32(pid))
 | |
| 	if err != nil {
 | |
| 		return nil, errors.Wrapf(err, "OpenProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(handle)
 | |
| 
 | |
| 	var cpu syscall.Rusage
 | |
| 	if err := syscall.GetProcessTimes(handle, &cpu.CreationTime, &cpu.ExitTime, &cpu.KernelTime, &cpu.UserTime); err != nil {
 | |
| 		return nil, errors.Wrapf(err, "GetProcessTimes failed for pid=%v", pid)
 | |
| 	}
 | |
| 
 | |
| 	return &cpu, nil
 | |
| }
 | |
| 
 | |
| func (self *ProcArgs) Get(pid int) error {
 | |
| 	// The minimum supported client for Win32_Process is Windows Vista.
 | |
| 	if !version.IsWindowsVistaOrGreater() {
 | |
| 		return ErrNotImplemented{runtime.GOOS}
 | |
| 	}
 | |
| 	handle, err := syscall.OpenProcess(processQueryLimitedInfoAccess|windows.PROCESS_VM_READ, false, uint32(pid))
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "OpenProcess failed for pid=%v", pid)
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(handle)
 | |
| 	pbi, err := windows.NtQueryProcessBasicInformation(handle)
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "NtQueryProcessBasicInformation failed for pid=%v", pid)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	userProcParams, err := windows.GetUserProcessParams(handle, pbi)
 | |
| 	if err != nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	if argsW, err := windows.ReadProcessUnicodeString(handle, &userProcParams.CommandLine); err == nil {
 | |
| 		self.List, err = windows.ByteSliceToStringSlice(argsW)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *FileSystemUsage) Get(path string) error {
 | |
| 	freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes, err := windows.GetDiskFreeSpaceEx(path)
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "GetDiskFreeSpaceEx failed")
 | |
| 	}
 | |
| 
 | |
| 	self.Total = totalNumberOfBytes
 | |
| 	self.Free = totalNumberOfFreeBytes
 | |
| 	self.Used = self.Total - self.Free
 | |
| 	self.Avail = freeBytesAvailable
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (self *Rusage) Get(who int) error {
 | |
| 	if who != 0 {
 | |
| 		return ErrNotImplemented{runtime.GOOS}
 | |
| 	}
 | |
| 
 | |
| 	pid := os.Getpid()
 | |
| 	cpu, err := getProcTimes(pid)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	self.Utime = windows.FiletimeToDuration(&cpu.UserTime)
 | |
| 	self.Stime = windows.FiletimeToDuration(&cpu.KernelTime)
 | |
| 
 | |
| 	return nil
 | |
| }
 |