feat(telemetry): add hostnamectl system details, df -h device partition filtering, who logged-in users fallback, robust desktop controls, multiarch build (#7)

This commit is contained in:
2026-08-08 19:35:43 -04:00
committed by GitHub
parent 57d5dfc174
commit efae05686e
9 changed files with 161 additions and 36 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+152 -33
View File
@@ -55,6 +55,21 @@ type LoggedUser struct {
Started int64 `json:"started"` Started int64 `json:"started"`
} }
type HostDetails struct {
StaticHostname string `json:"static_hostname"`
IconName string `json:"icon_name"`
Chassis string `json:"chassis"`
MachineID string `json:"machine_id"`
BootID string `json:"boot_id"`
OS string `json:"os"`
Kernel string `json:"kernel"`
Arch string `json:"arch"`
HardwareVendor string `json:"hardware_vendor"`
HardwareModel string `json:"hardware_model"`
FirmwareVersion string `json:"firmware_version"`
FirmwareDate string `json:"firmware_date"`
}
type DiscoveryData struct { type DiscoveryData struct {
Hostname string `json:"hostname"` Hostname string `json:"hostname"`
IPs []string `json:"ip_addresses"` IPs []string `json:"ip_addresses"`
@@ -68,6 +83,7 @@ type DiscoveryData struct {
DiskTotalGB float64 `json:"disk_total_gb"` DiskTotalGB float64 `json:"disk_total_gb"`
Disks []DiskItem `json:"disks"` Disks []DiskItem `json:"disks"`
LoggedUsers []LoggedUser `json:"logged_users"` LoggedUsers []LoggedUser `json:"logged_users"`
HostDetails HostDetails `json:"host_details"`
Version string `json:"version"` Version string `json:"version"`
Location string `json:"location"` Location string `json:"location"`
Capabilities map[string]interface{} `json:"capabilities"` Capabilities map[string]interface{} `json:"capabilities"`
@@ -81,6 +97,7 @@ type TelemetryData struct {
DiskUsagePercent float64 `json:"disk_usage_percent"` DiskUsagePercent float64 `json:"disk_usage_percent"`
Disks []DiskItem `json:"disks"` Disks []DiskItem `json:"disks"`
LoggedUsers []LoggedUser `json:"logged_users"` LoggedUsers []LoggedUser `json:"logged_users"`
HostDetails HostDetails `json:"host_details"`
Version string `json:"version"` Version string `json:"version"`
ZFSHealth string `json:"zfs_health,omitempty"` ZFSHealth string `json:"zfs_health,omitempty"`
GPUUsage float64 `json:"gpu_usage_percent,omitempty"` GPUUsage float64 `json:"gpu_usage_percent,omitempty"`
@@ -117,6 +134,19 @@ func collectCPUDetails() CPUDetails {
mhz := 0.0 mhz := 0.0
if len(cpuInfo) > 0 { if len(cpuInfo) > 0 {
model = cpuInfo[0].ModelName model = cpuInfo[0].ModelName
if model == "" || strings.TrimSpace(model) == "154" || len(model) < 4 {
if data, err := os.ReadFile("/proc/cpuinfo"); err == nil {
for _, line := range strings.Split(string(data), "\n") {
if strings.HasPrefix(line, "model name") {
parts := strings.Split(line, ":")
if len(parts) > 1 {
model = strings.TrimSpace(parts[1])
break
}
}
}
}
}
if model == "" { if model == "" {
model = cpuInfo[0].Model model = cpuInfo[0].Model
} }
@@ -189,23 +219,51 @@ func getDriveType(device string) string {
func collectLoggedUsers() []LoggedUser { func collectLoggedUsers() []LoggedUser {
var list []LoggedUser var list []LoggedUser
users, err := host.Users()
if err != nil || len(users) == 0 {
return list
}
seen := make(map[string]bool) seen := make(map[string]bool)
for _, u := range users { users, err := host.Users()
key := fmt.Sprintf("%s@%s:%s", u.User, u.Terminal, u.Host) if err == nil {
if seen[key] { for _, u := range users {
continue key := fmt.Sprintf("%s@%s:%s", u.User, u.Terminal, u.Host)
if seen[key] {
continue
}
seen[key] = true
list = append(list, LoggedUser{
User: u.User,
Terminal: u.Terminal,
Host: u.Host,
Started: int64(u.Started),
})
}
}
if len(list) == 0 {
exec := SystemExecutor{}
out, err := exec.Execute("who")
if err == nil && len(out) > 0 {
lines := strings.Split(string(out), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) >= 2 {
user := fields[0]
term := fields[1]
hostStr := ""
if len(fields) >= 5 {
hostStr = strings.Trim(fields[4], "()")
}
key := fmt.Sprintf("%s@%s:%s", user, term, hostStr)
if !seen[key] {
seen[key] = true
list = append(list, LoggedUser{
User: user,
Terminal: term,
Host: hostStr,
Started: time.Now().Unix(),
})
}
}
}
} }
seen[key] = true
list = append(list, LoggedUser{
User: u.User,
Terminal: u.Terminal,
Host: u.Host,
Started: int64(u.Started),
})
} }
return list return list
} }
@@ -218,6 +276,7 @@ func collectDiskItems() []DiskItem {
if err2 == nil { if err2 == nil {
items = append(items, DiskItem{ items = append(items, DiskItem{
Mountpoint: "/", Mountpoint: "/",
Device: d.Path,
FSType: d.Fstype, FSType: d.Fstype,
DriveType: getDriveType(d.Path), DriveType: getDriveType(d.Path),
TotalBytes: d.Total, TotalBytes: d.Total,
@@ -229,17 +288,9 @@ func collectDiskItems() []DiskItem {
return items return items
} }
seen := make(map[string]bool) seen := make(map[string]bool)
ignoredFSTypes := map[string]bool{
"tmpfs": true, "devtmpfs": true, "proc": true, "sysfs": true,
"cgroup": true, "cgroup2": true, "overlay": true, "squashfs": true,
"autofs": true, "devpts": true, "mqueue": true,
}
for _, p := range partitions { for _, p := range partitions {
if strings.HasPrefix(p.Mountpoint, "/proc") || strings.HasPrefix(p.Mountpoint, "/sys") || strings.HasPrefix(p.Mountpoint, "/dev") { if !strings.HasPrefix(p.Device, "/dev/") || strings.HasPrefix(p.Device, "/dev/loop") {
continue
}
if ignoredFSTypes[strings.ToLower(p.Fstype)] {
continue continue
} }
if seen[p.Mountpoint] { if seen[p.Mountpoint] {
@@ -270,6 +321,7 @@ func collectDiskItems() []DiskItem {
if err2 == nil { if err2 == nil {
items = append(items, DiskItem{ items = append(items, DiskItem{
Mountpoint: "/", Mountpoint: "/",
Device: d.Path,
FSType: d.Fstype, FSType: d.Fstype,
DriveType: getDriveType(d.Path), DriveType: getDriveType(d.Path),
TotalBytes: d.Total, TotalBytes: d.Total,
@@ -282,6 +334,68 @@ func collectDiskItems() []DiskItem {
return items return items
} }
func collectHostDetails() HostDetails {
details := HostDetails{}
exec := SystemExecutor{}
out, err := exec.Execute("hostnamectl")
if err == nil {
for _, line := range strings.Split(string(out), "\n") {
parts := strings.SplitN(line, ":", 2)
if len(parts) == 2 {
key := strings.TrimSpace(parts[0])
val := strings.TrimSpace(parts[1])
switch key {
case "Static hostname":
details.StaticHostname = val
case "Icon name":
details.IconName = val
case "Chassis":
details.Chassis = val
case "Machine ID":
details.MachineID = val
case "Boot ID":
details.BootID = val
case "Operating System":
details.OS = val
case "Kernel":
details.Kernel = val
case "Architecture":
details.Arch = val
case "Hardware Vendor":
details.HardwareVendor = val
case "Hardware Model":
details.HardwareModel = val
case "Firmware Version":
details.FirmwareVersion = val
case "Firmware Date":
details.FirmwareDate = val
}
}
}
}
if details.HardwareVendor == "" {
if d, err := os.ReadFile("/sys/class/dmi/id/sys_vendor"); err == nil {
details.HardwareVendor = strings.TrimSpace(string(d))
}
}
if details.HardwareModel == "" {
if d, err := os.ReadFile("/sys/class/dmi/id/product_name"); err == nil {
details.HardwareModel = strings.TrimSpace(string(d))
}
}
if details.FirmwareVersion == "" {
if d, err := os.ReadFile("/sys/class/dmi/id/bios_version"); err == nil {
details.FirmwareVersion = strings.TrimSpace(string(d))
}
}
if details.FirmwareDate == "" {
if d, err := os.ReadFile("/sys/class/dmi/id/bios_date"); err == nil {
details.FirmwareDate = strings.TrimSpace(string(d))
}
}
return details
}
const AgentVersion = "v1.7.0" const AgentVersion = "v1.7.0"
// CollectDiscoveryData gathers static host information. // CollectDiscoveryData gathers static host information.
@@ -316,6 +430,8 @@ func CollectDiscoveryData(cfg *Config) DiscoveryData {
diskTotalGB = float64(disks[0].TotalBytes) / (1024 * 1024 * 1024) diskTotalGB = float64(disks[0].TotalBytes) / (1024 * 1024 * 1024)
} }
hostDet := collectHostDetails()
return DiscoveryData{ return DiscoveryData{
Hostname: h.Hostname, Hostname: h.Hostname,
IPs: ips, IPs: ips,
@@ -329,19 +445,20 @@ func CollectDiscoveryData(cfg *Config) DiscoveryData {
DiskTotalGB: diskTotalGB, DiskTotalGB: diskTotalGB,
Disks: disks, Disks: disks,
LoggedUsers: loggedUsers, LoggedUsers: loggedUsers,
HostDetails: hostDet,
Version: AgentVersion, Version: AgentVersion,
Location: cfg.Location, Location: cfg.Location,
Capabilities: map[string]interface{}{ Capabilities: map[string]interface{}{
"telemetry": cfg.Capabilities.Telemetry, "telemetry": cfg.Capabilities.Telemetry,
"configure_ldap": cfg.Capabilities.ConfigureLDAP, "configure_ldap": cfg.Capabilities.ConfigureLDAP,
"ldap_tunnel": cfg.Capabilities.LdapTunnel, "ldap_tunnel": cfg.Capabilities.LdapTunnel,
"secrets": cfg.Capabilities.Secrets, "secrets": cfg.Capabilities.Secrets,
"iam": cfg.Capabilities.IAM, "iam": cfg.Capabilities.IAM,
"reboot": cfg.Capabilities.Reboot, "reboot": cfg.Capabilities.Reboot,
"shutdown": true, "shutdown": true,
"desktop_controls": true, "desktop_controls": true,
"service_control": cfg.Capabilities.ServiceControl, "service_control": cfg.Capabilities.ServiceControl,
"arbitrary_bash": cfg.Capabilities.ArbitraryBash, "arbitrary_bash": cfg.Capabilities.ArbitraryBash,
}, },
} }
} }
@@ -353,6 +470,7 @@ func CollectTelemetryData(exec Executor) TelemetryData {
disks := collectDiskItems() disks := collectDiskItems()
cpuDet := collectCPUDetails() cpuDet := collectCPUDetails()
loggedUsers := collectLoggedUsers() loggedUsers := collectLoggedUsers()
hostDet := collectHostDetails()
cpuVal := 0.0 cpuVal := 0.0
if len(cpuPerc) > 0 { if len(cpuPerc) > 0 {
@@ -378,6 +496,7 @@ func CollectTelemetryData(exec Executor) TelemetryData {
DiskUsagePercent: diskVal, DiskUsagePercent: diskVal,
Disks: disks, Disks: disks,
LoggedUsers: loggedUsers, LoggedUsers: loggedUsers,
HostDetails: hostDet,
Version: AgentVersion, Version: AgentVersion,
ZFSHealth: collectZFSHealth(exec), ZFSHealth: collectZFSHealth(exec),
GPUUsage: collectGPUUsage(exec), GPUUsage: collectGPUUsage(exec),
+9 -3
View File
@@ -402,16 +402,22 @@ func handleCommand(cm *ConfigManager, msg WSMessage, c MessageWriter, exec Execu
case "lock_session", "lock": case "lock_session", "lock":
out, err = exec.Execute("loginctl", "lock-sessions") out, err = exec.Execute("loginctl", "lock-sessions")
if err != nil { if err != nil {
out, err = exec.Execute("xset", "dpms", "force", "off") out, err = exec.Execute("sh", "-c", "DISPLAY=:0 xdg-screensaver lock || DISPLAY=:0 xset dpms force off")
} }
case "logout_user", "logout": case "logout_user", "logout":
if targetUser != "" { if targetUser != "" {
out, err = exec.Execute("pkill", "-KILL", "-u", targetUser) out, err = exec.Execute("loginctl", "terminate-user", targetUser)
if err != nil {
out, err = exec.Execute("pkill", "-KILL", "-u", targetUser)
}
} else { } else {
out, err = exec.Execute("loginctl", "terminate-session") out, err = exec.Execute("loginctl", "terminate-session")
if err != nil {
out, err = exec.Execute("pkill", "-9", "-f", "session-child")
}
} }
case "display_off": case "display_off":
out, err = exec.Execute("xset", "dpms", "force", "off") out, err = exec.Execute("sh", "-c", "DISPLAY=:0 xset dpms force off || loginctl lock-sessions")
case "sleep_host", "sleep": case "sleep_host", "sleep":
out, err = exec.Execute("systemctl", "suspend") out, err = exec.Execute("systemctl", "suspend")
default: default: