release: v1.8.0 - Active Logged-in Users, Physical Disks & Desktop Operations
This commit is contained in:
@@ -5,6 +5,14 @@ All notable changes to the `theta-agent` daemon will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [v1.8.0] - 2026-08-08
|
||||
|
||||
### Added
|
||||
- **Active Logged-in User Sessions.** Added `collectLoggedUsers()` gathering terminal sessions (`who` / `host.Users()`) reported in discovery and live telemetry payloads.
|
||||
- **Full Physical Partition & Filesystem Collection.** Switched to `disk.Partitions(true)` to list all physical drives, ZFS pools, and mount points while filtering pseudo/virtual filesystems.
|
||||
- **Desktop Control Operations.** Implemented `desktop_control` WebSocket actions supporting `lock_session` (`loginctl lock-sessions`), `logout_user` (`pkill -u <user>`), `display_off` (`xset dpms force off`), and `sleep_host` (`systemctl suspend`).
|
||||
- **Binary Version Reporting.** Included `AgentVersion` (`v1.8.0`) in discovery and telemetry frames.
|
||||
|
||||
## [v1.7.0] - 2026-08-08
|
||||
|
||||
### Added
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+53
-1
@@ -48,6 +48,13 @@ type DiskItem struct {
|
||||
UsagePercent float64 `json:"usage_percent"`
|
||||
}
|
||||
|
||||
type LoggedUser struct {
|
||||
User string `json:"user"`
|
||||
Terminal string `json:"terminal"`
|
||||
Host string `json:"host"`
|
||||
Started int64 `json:"started"`
|
||||
}
|
||||
|
||||
type DiscoveryData struct {
|
||||
Hostname string `json:"hostname"`
|
||||
IPs []string `json:"ip_addresses"`
|
||||
@@ -60,6 +67,8 @@ type DiscoveryData struct {
|
||||
RAMDetails RAMDetails `json:"ram_details"`
|
||||
DiskTotalGB float64 `json:"disk_total_gb"`
|
||||
Disks []DiskItem `json:"disks"`
|
||||
LoggedUsers []LoggedUser `json:"logged_users"`
|
||||
Version string `json:"version"`
|
||||
Location string `json:"location"`
|
||||
Capabilities map[string]interface{} `json:"capabilities"`
|
||||
}
|
||||
@@ -71,6 +80,8 @@ type TelemetryData struct {
|
||||
RAMDetails RAMDetails `json:"ram_details"`
|
||||
DiskUsagePercent float64 `json:"disk_usage_percent"`
|
||||
Disks []DiskItem `json:"disks"`
|
||||
LoggedUsers []LoggedUser `json:"logged_users"`
|
||||
Version string `json:"version"`
|
||||
ZFSHealth string `json:"zfs_health,omitempty"`
|
||||
GPUUsage float64 `json:"gpu_usage_percent,omitempty"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
@@ -176,9 +187,32 @@ func getDriveType(device string) string {
|
||||
return "SSD/HDD"
|
||||
}
|
||||
|
||||
func collectLoggedUsers() []LoggedUser {
|
||||
var list []LoggedUser
|
||||
users, err := host.Users()
|
||||
if err != nil || len(users) == 0 {
|
||||
return list
|
||||
}
|
||||
seen := make(map[string]bool)
|
||||
for _, u := range users {
|
||||
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),
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func collectDiskItems() []DiskItem {
|
||||
var items []DiskItem
|
||||
partitions, err := disk.Partitions(false)
|
||||
partitions, err := disk.Partitions(true)
|
||||
if err != nil || len(partitions) == 0 {
|
||||
d, err2 := disk.Usage("/")
|
||||
if err2 == nil {
|
||||
@@ -195,10 +229,19 @@ func collectDiskItems() []DiskItem {
|
||||
return items
|
||||
}
|
||||
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 {
|
||||
if strings.HasPrefix(p.Mountpoint, "/proc") || strings.HasPrefix(p.Mountpoint, "/sys") || strings.HasPrefix(p.Mountpoint, "/dev") {
|
||||
continue
|
||||
}
|
||||
if ignoredFSTypes[strings.ToLower(p.Fstype)] {
|
||||
continue
|
||||
}
|
||||
if seen[p.Mountpoint] {
|
||||
continue
|
||||
}
|
||||
@@ -239,6 +282,8 @@ func collectDiskItems() []DiskItem {
|
||||
return items
|
||||
}
|
||||
|
||||
const AgentVersion = "v1.7.0"
|
||||
|
||||
// CollectDiscoveryData gathers static host information.
|
||||
func CollectDiscoveryData(cfg *Config) DiscoveryData {
|
||||
h, _ := host.Info()
|
||||
@@ -256,6 +301,7 @@ func CollectDiscoveryData(cfg *Config) DiscoveryData {
|
||||
vm := collectRAMDetails()
|
||||
disks := collectDiskItems()
|
||||
cpuDet := collectCPUDetails()
|
||||
loggedUsers := collectLoggedUsers()
|
||||
|
||||
pubIP := getPublicIP()
|
||||
|
||||
@@ -282,6 +328,8 @@ func CollectDiscoveryData(cfg *Config) DiscoveryData {
|
||||
RAMDetails: vm,
|
||||
DiskTotalGB: diskTotalGB,
|
||||
Disks: disks,
|
||||
LoggedUsers: loggedUsers,
|
||||
Version: AgentVersion,
|
||||
Location: cfg.Location,
|
||||
Capabilities: map[string]interface{}{
|
||||
"telemetry": cfg.Capabilities.Telemetry,
|
||||
@@ -291,6 +339,7 @@ func CollectDiscoveryData(cfg *Config) DiscoveryData {
|
||||
"iam": cfg.Capabilities.IAM,
|
||||
"reboot": cfg.Capabilities.Reboot,
|
||||
"shutdown": true,
|
||||
"desktop_controls": true,
|
||||
"service_control": cfg.Capabilities.ServiceControl,
|
||||
"arbitrary_bash": cfg.Capabilities.ArbitraryBash,
|
||||
},
|
||||
@@ -303,6 +352,7 @@ func CollectTelemetryData(exec Executor) TelemetryData {
|
||||
vm := collectRAMDetails()
|
||||
disks := collectDiskItems()
|
||||
cpuDet := collectCPUDetails()
|
||||
loggedUsers := collectLoggedUsers()
|
||||
|
||||
cpuVal := 0.0
|
||||
if len(cpuPerc) > 0 {
|
||||
@@ -327,6 +377,8 @@ func CollectTelemetryData(exec Executor) TelemetryData {
|
||||
RAMDetails: vm,
|
||||
DiskUsagePercent: diskVal,
|
||||
Disks: disks,
|
||||
LoggedUsers: loggedUsers,
|
||||
Version: AgentVersion,
|
||||
ZFSHealth: collectZFSHealth(exec),
|
||||
GPUUsage: collectGPUUsage(exec),
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
|
||||
@@ -388,6 +388,50 @@ func handleCommand(cm *ConfigManager, msg WSMessage, c MessageWriter, exec Execu
|
||||
exec.Execute("poweroff")
|
||||
}
|
||||
return
|
||||
case "desktop_control", "lock_session", "logout_user", "display_off", "sleep_host":
|
||||
subAction, _ := msg.Payload["subAction"].(string)
|
||||
if subAction == "" {
|
||||
subAction = msg.Type
|
||||
}
|
||||
targetUser, _ := msg.Payload["user"].(string)
|
||||
log.Printf("Executing desktop control action '%s' for user '%s'...", subAction, targetUser)
|
||||
var out []byte
|
||||
var err error
|
||||
|
||||
switch subAction {
|
||||
case "lock_session", "lock":
|
||||
out, err = exec.Execute("loginctl", "lock-sessions")
|
||||
if err != nil {
|
||||
out, err = exec.Execute("xset", "dpms", "force", "off")
|
||||
}
|
||||
case "logout_user", "logout":
|
||||
if targetUser != "" {
|
||||
out, err = exec.Execute("pkill", "-KILL", "-u", targetUser)
|
||||
} else {
|
||||
out, err = exec.Execute("loginctl", "terminate-session")
|
||||
}
|
||||
case "display_off":
|
||||
out, err = exec.Execute("xset", "dpms", "force", "off")
|
||||
case "sleep_host", "sleep":
|
||||
out, err = exec.Execute("systemctl", "suspend")
|
||||
default:
|
||||
sendResponse("error", fmt.Sprintf("unknown desktop action '%s'", subAction))
|
||||
return
|
||||
}
|
||||
|
||||
errMsg := ""
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
respMap := map[string]interface{}{
|
||||
"status": "ok",
|
||||
"subAction": subAction,
|
||||
"output": string(out),
|
||||
"error": errMsg,
|
||||
}
|
||||
respPayload, _ := json.Marshal(respMap)
|
||||
c.WriteMessage(websocket.TextMessage, respPayload)
|
||||
return
|
||||
case "systemd_action":
|
||||
serviceName, _ := msg.Payload["service"].(string)
|
||||
action, _ := msg.Payload["action"].(string)
|
||||
|
||||
Reference in New Issue
Block a user