From b51e87477e3aac0225994d67da7f0017541d452d Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Thu, 13 Aug 2026 10:39:27 +0000 Subject: [PATCH] feat: Report whether a managed host is waiting on a reboot --- agent/internal/grpc/pb/vantage.pb.go | 48 ++++++++++----------------- agent/internal/sync/sync.go | 10 ++++++ proto/vantage/v1/vantage.proto | 3 ++ server/internal/grpc/pb/vantage.pb.go | 19 ++++++----- server/internal/models/server.go | 1 + server/internal/services/inventory.go | 1 + 6 files changed, 42 insertions(+), 40 deletions(-) diff --git a/agent/internal/grpc/pb/vantage.pb.go b/agent/internal/grpc/pb/vantage.pb.go index a914114..5f6a9a8 100644 --- a/agent/internal/grpc/pb/vantage.pb.go +++ b/agent/internal/grpc/pb/vantage.pb.go @@ -1,5 +1,3 @@ - - package pb import ( @@ -83,8 +81,6 @@ type UploadKeyResponse struct { KeyId string `json:"key_id"` } - - type PackageUpdate struct { Name string `json:"name"` CurrentVersion string `json:"current_version,omitempty"` @@ -99,8 +95,6 @@ type ReportUpdatesRequest struct { type ReportUpdatesResponse struct{} - - type CPUReport struct { Model string `json:"model,omitempty"` Cores int `json:"cores,omitempty"` @@ -119,20 +113,19 @@ type PartitionReport struct { UsedBytes uint64 `json:"used_bytes"` } type InventoryReport struct { - ServerId string `json:"server_id"` - AgentToken string `json:"agent_token"` - IncludeStatic bool `json:"include_static"` - CPU *CPUReport `json:"cpu,omitempty"` - Memory *MemReport `json:"memory,omitempty"` - SwapTotal uint64 `json:"swap_total"` - SwapUsed uint64 `json:"swap_used"` - Partitions []PartitionReport `json:"partitions,omitempty"` - Kernel string `json:"kernel,omitempty"` + ServerId string `json:"server_id"` + AgentToken string `json:"agent_token"` + IncludeStatic bool `json:"include_static"` + CPU *CPUReport `json:"cpu,omitempty"` + Memory *MemReport `json:"memory,omitempty"` + SwapTotal uint64 `json:"swap_total"` + SwapUsed uint64 `json:"swap_used"` + Partitions []PartitionReport `json:"partitions,omitempty"` + Kernel string `json:"kernel,omitempty"` + RebootRequired bool `json:"reboot_required,omitempty"` } type InventoryReportResponse struct{} - - type MonitorSpec struct { MonitorId string `json:"monitor_id"` Type string `json:"type"` @@ -217,8 +210,6 @@ type ServerCommand struct { // keepalive is not sufficient on its own. type PingCmd struct{} - - type CleanupWorkspaceCmd struct { WorkspaceId string `json:"workspace_id"` } @@ -241,12 +232,12 @@ type GenerateKeyCmd struct { } type AgentMessage struct { - ServerId string `json:"server_id"` - AgentToken string `json:"agent_token"` - Ready *AgentReady `json:"ready,omitempty"` - Result *CommandResult `json:"result,omitempty"` - StepResult *StepResult `json:"step_result,omitempty"` - StepOutput *StepOutputChunk `json:"step_output,omitempty"` + ServerId string `json:"server_id"` + AgentToken string `json:"agent_token"` + Ready *AgentReady `json:"ready,omitempty"` + Result *CommandResult `json:"result,omitempty"` + StepResult *StepResult `json:"step_result,omitempty"` + StepOutput *StepOutputChunk `json:"step_output,omitempty"` WorkloadLogsResult *WorkloadLogsResult `json:"workload_logs_result,omitempty"` } @@ -264,8 +255,7 @@ type RunStepCmd struct { Script string `json:"script"` Env map[string]string `json:"env,omitempty"` TimeoutSeconds int `json:"timeout_seconds,omitempty"` - - + WorkspaceId string `json:"workspace_id,omitempty"` } @@ -284,8 +274,6 @@ type StepOutputChunk struct { Eof bool `json:"eof,omitempty"` } - - type Vantage_CommandStreamClient interface { Send(*AgentMessage) error Recv() (*ServerCommand, error) @@ -308,8 +296,6 @@ func (c *vantageCommandStreamClient) Recv() (*ServerCommand, error) { return m, nil } - - type Vantage_CommandStreamServer interface { Send(*ServerCommand) error Recv() (*AgentMessage, error) diff --git a/agent/internal/sync/sync.go b/agent/internal/sync/sync.go index 0fa6bd0..14c7cd7 100644 --- a/agent/internal/sync/sync.go +++ b/agent/internal/sync/sync.go @@ -450,6 +450,16 @@ func runInventory(ctx context.Context, cfg *config.Config) { r := inventory.Collect(static) r.ServerId = cfg.ServerID r.AgentToken = cfg.AgentToken + // Static snapshots only — every 15 minutes, not every 30 seconds. On + // Windows this spawns a PowerShell process, which is not something to + // do twice a minute forever, and a host rebooted by hand clearing the + // flag within a quarter of an hour is soon enough. + // + // Computed here rather than inside inventory.Collect so the inventory + // package gains no dependency on updates. + if static { + r.RebootRequired = updates.RebootRequired() + } if err := client.ReportInventory(r); err != nil { log.Printf("report inventory: %v", err) } diff --git a/proto/vantage/v1/vantage.proto b/proto/vantage/v1/vantage.proto index b02fe75..c0a2822 100644 --- a/proto/vantage/v1/vantage.proto +++ b/proto/vantage/v1/vantage.proto @@ -168,6 +168,9 @@ message InventoryReport { uint64 swap_used = 7; repeated PartitionReport partitions = 8; string kernel = 9; + // Set on static snapshots only. The agent never reboots; it reports that one + // is owed and leaves the decision to a person or a workflow. + bool reboot_required = 10; } message InventoryReportResponse { diff --git a/server/internal/grpc/pb/vantage.pb.go b/server/internal/grpc/pb/vantage.pb.go index f2b6936..5caa8fb 100644 --- a/server/internal/grpc/pb/vantage.pb.go +++ b/server/internal/grpc/pb/vantage.pb.go @@ -113,15 +113,16 @@ type PartitionReport struct { UsedBytes uint64 `json:"used_bytes"` } type InventoryReport struct { - ServerId string `json:"server_id"` - AgentToken string `json:"agent_token"` - IncludeStatic bool `json:"include_static"` - CPU *CPUReport `json:"cpu,omitempty"` - Memory *MemReport `json:"memory,omitempty"` - SwapTotal uint64 `json:"swap_total"` - SwapUsed uint64 `json:"swap_used"` - Partitions []PartitionReport `json:"partitions,omitempty"` - Kernel string `json:"kernel,omitempty"` + ServerId string `json:"server_id"` + AgentToken string `json:"agent_token"` + IncludeStatic bool `json:"include_static"` + CPU *CPUReport `json:"cpu,omitempty"` + Memory *MemReport `json:"memory,omitempty"` + SwapTotal uint64 `json:"swap_total"` + SwapUsed uint64 `json:"swap_used"` + Partitions []PartitionReport `json:"partitions,omitempty"` + Kernel string `json:"kernel,omitempty"` + RebootRequired bool `json:"reboot_required,omitempty"` } type InventoryReportResponse struct{} diff --git a/server/internal/models/server.go b/server/internal/models/server.go index 239c39d..4501159 100644 --- a/server/internal/models/server.go +++ b/server/internal/models/server.go @@ -39,6 +39,7 @@ type Inventory struct { SwapUsedBytes uint64 `bson:"swap_used_bytes" json:"swap_used_bytes"` Partitions []Partition `bson:"partitions,omitempty" json:"partitions,omitempty"` Kernel string `bson:"kernel,omitempty" json:"kernel,omitempty"` + RebootRequired bool `bson:"reboot_required,omitempty" json:"reboot_required,omitempty"` MetricsAt *time.Time `bson:"metrics_at,omitempty" json:"metrics_at,omitempty"` StaticAt *time.Time `bson:"static_at,omitempty" json:"static_at,omitempty"` } diff --git a/server/internal/services/inventory.go b/server/internal/services/inventory.go index bf845d0..4752c01 100644 --- a/server/internal/services/inventory.go +++ b/server/internal/services/inventory.go @@ -28,6 +28,7 @@ func StoreInventory(serverID string, r *pb.InventoryReport) error { set["inventory.static_at"] = now set["inventory.swap_total_bytes"] = r.SwapTotal set["inventory.kernel"] = r.Kernel + set["inventory.reboot_required"] = r.RebootRequired if r.CPU != nil { set["inventory.cpu.model"] = r.CPU.Model set["inventory.cpu.cores"] = r.CPU.Cores