feat: Fleet Forge UEM - device management, agent, remote desktop (VNC), TLS reverse proxy
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
package inventory
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/fleetforge/forge-agent/internal/pkgmanager"
|
||||
"github.com/fleetforge/forge-agent/internal/svcmgr"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v3/net"
|
||||
)
|
||||
|
||||
func execCmd(name string, args ...string) (string, error) {
|
||||
cmd := exec.Command(name, args...)
|
||||
out, err := cmd.Output()
|
||||
return string(out), err
|
||||
}
|
||||
|
||||
type NetworkInterface struct {
|
||||
Name string `json:"name"`
|
||||
Addresses []string `json:"addresses"`
|
||||
MAC string `json:"mac_address,omitempty"`
|
||||
}
|
||||
|
||||
type SystemInfo struct {
|
||||
Hostname string
|
||||
Platform string
|
||||
OSName string
|
||||
OSVersion string
|
||||
Architecture string
|
||||
KernelVersion string
|
||||
CPUModel string
|
||||
CPUCores int
|
||||
TotalMemory uint64
|
||||
TotalDisk uint64
|
||||
IPAddress string
|
||||
NetworkInterfaces []NetworkInterface
|
||||
Packages []pkgmanager.PackageInfo
|
||||
Services []svcmgr.ServiceInfo
|
||||
}
|
||||
|
||||
func CollectSystemInfo() (*SystemInfo, error) {
|
||||
hostname, _ := os.Hostname()
|
||||
|
||||
info := &SystemInfo{
|
||||
Hostname: hostname,
|
||||
Platform: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
}
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
info.OSName = "Linux"
|
||||
if data, err := os.ReadFile("/etc/os-release"); err == nil {
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "PRETTY_NAME=") {
|
||||
info.OSName = strings.Trim(strings.TrimPrefix(line, "PRETTY_NAME="), "\"")
|
||||
}
|
||||
if strings.HasPrefix(line, "VERSION_ID=") {
|
||||
info.OSVersion = strings.Trim(strings.TrimPrefix(line, "VERSION_ID="), "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
if data, err := os.ReadFile("/proc/version"); err == nil {
|
||||
parts := strings.Fields(string(data))
|
||||
if len(parts) >= 3 {
|
||||
info.KernelVersion = parts[2]
|
||||
}
|
||||
}
|
||||
case "darwin":
|
||||
info.OSName = "macOS"
|
||||
if out, err := execCmd("sw_vers", "-productVersion"); err == nil {
|
||||
info.OSVersion = strings.TrimSpace(out)
|
||||
}
|
||||
if out, err := execCmd("uname", "-r"); err == nil {
|
||||
info.KernelVersion = strings.TrimSpace(out)
|
||||
}
|
||||
case "windows":
|
||||
info.OSName = "Windows"
|
||||
if out, err := execCmd("cmd", "/c", "ver"); err == nil {
|
||||
out = strings.TrimSpace(out)
|
||||
if start := strings.Index(out, "[Version "); start != -1 {
|
||||
ver := out[start+len("[Version "):]
|
||||
if end := strings.Index(ver, "]"); end != -1 {
|
||||
info.OSVersion = ver[:end]
|
||||
}
|
||||
}
|
||||
if info.OSVersion == "" {
|
||||
info.OSVersion = out
|
||||
}
|
||||
}
|
||||
if out, err := execCmd("cmd", "/c", "ver"); err == nil {
|
||||
_ = out
|
||||
}
|
||||
if out, err := execCmd("powershell", "-NoProfile", "-NonInteractive", "-Command",
|
||||
"(Get-CimInstance Win32_OperatingSystem).Caption"); err == nil {
|
||||
caption := strings.TrimSpace(out)
|
||||
if caption != "" {
|
||||
info.OSName = caption
|
||||
}
|
||||
}
|
||||
if out, err := execCmd("powershell", "-NoProfile", "-NonInteractive", "-Command",
|
||||
"$k = (Get-CimInstance Win32_OperatingSystem).Version; $b = (Get-CimInstance Win32_ComputerSystem).BuildNumber; $k"); err == nil {
|
||||
if kb := strings.TrimSpace(out); kb != "" {
|
||||
info.KernelVersion = kb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cpuInfo, err := cpu.Info(); err == nil && len(cpuInfo) > 0 {
|
||||
info.CPUModel = cpuInfo[0].ModelName
|
||||
info.CPUCores = len(cpuInfo)
|
||||
}
|
||||
|
||||
if v, err := mem.VirtualMemory(); err == nil {
|
||||
info.TotalMemory = v.Total
|
||||
}
|
||||
|
||||
if d, err := disk.Usage("/"); err == nil {
|
||||
info.TotalDisk = d.Total
|
||||
}
|
||||
|
||||
populateNetwork(info)
|
||||
|
||||
if info.OSVersion == "" {
|
||||
info.OSVersion = "unknown"
|
||||
}
|
||||
|
||||
if pkgs, err := pkgmanager.ListPackages(); err == nil {
|
||||
info.Packages = pkgs
|
||||
}
|
||||
|
||||
if svcs, err := svcmgr.ListServices(); err == nil {
|
||||
info.Services = svcs
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func populateNetwork(info *SystemInfo) {
|
||||
ifs, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var primaryIP string
|
||||
for _, ifc := range ifs {
|
||||
if !containsFlag(ifc.Flags, "up") || containsFlag(ifc.Flags, "loopback") {
|
||||
continue
|
||||
}
|
||||
ni := NetworkInterface{
|
||||
Name: ifc.Name,
|
||||
Addresses: []string{},
|
||||
MAC: ifc.HardwareAddr,
|
||||
}
|
||||
for _, addr := range ifc.Addrs {
|
||||
if addr.Addr == "" {
|
||||
continue
|
||||
}
|
||||
ip := strings.TrimSpace(addr.Addr)
|
||||
ni.Addresses = append(ni.Addresses, ip)
|
||||
if primaryIP == "" && !strings.Contains(ip, ":") {
|
||||
primaryIP = strings.Split(ip, "/")[0]
|
||||
}
|
||||
}
|
||||
if len(ni.Addresses) > 0 {
|
||||
info.NetworkInterfaces = append(info.NetworkInterfaces, ni)
|
||||
}
|
||||
}
|
||||
|
||||
if primaryIP != "" {
|
||||
info.IPAddress = primaryIP
|
||||
}
|
||||
}
|
||||
|
||||
func containsFlag(flags []string, flag string) bool {
|
||||
for _, f := range flags {
|
||||
if strings.EqualFold(f, flag) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user