feat(inventory): record when a reboot became required

This commit is contained in:
2026-09-17 08:37:41 +00:00
parent 42358f57cb
commit 1a1f6998a4
2 changed files with 58 additions and 1 deletions
+34 -1
View File
@@ -7,6 +7,7 @@ import (
"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/db"
"gitea.hostxtra.co.uk/vantage/vantage-shared/grpc/pb"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
func StoreInventory(serverID string, r *pb.InventoryReport) error {
@@ -29,6 +30,7 @@ func StoreInventory(serverID string, r *pb.InventoryReport) error {
set["inventory.boot_time"] = time.Unix(r.BootTimeUnix, 0).UTC()
}
var unset bson.M
if r.IncludeStatic {
set["inventory.static_at"] = now
set["inventory.swap_total_bytes"] = r.SwapTotal
@@ -49,8 +51,39 @@ func StoreInventory(serverID string, r *pb.InventoryReport) error {
})
}
set["inventory.partitions"] = parts
var prev struct {
Inventory struct {
RebootRequired bool `bson:"reboot_required"`
RebootRequiredSince *time.Time `bson:"reboot_required_since"`
} `bson:"inventory"`
}
_ = db.Col("servers").FindOne(ctx, bson.M{"server_id": serverID},
options.FindOne().SetProjection(bson.M{"inventory.reboot_required": 1, "inventory.reboot_required_since": 1})).Decode(&prev)
if since, clear := rebootSinceUpdate(prev.Inventory.RebootRequired, prev.Inventory.RebootRequiredSince, r.RebootRequired, now); since != nil {
set["inventory.reboot_required_since"] = *since
} else if clear {
unset = bson.M{"inventory.reboot_required_since": ""}
}
}
_, err := db.Col("servers").UpdateOne(ctx, bson.M{"server_id": serverID}, bson.M{"$set": set})
upd := bson.M{"$set": set}
if unset != nil {
upd["$unset"] = unset
}
_, err := db.Col("servers").UpdateOne(ctx, bson.M{"server_id": serverID}, upd)
return err
}
// rebootSinceUpdate decides how reboot_required_since changes. The stamp is
// kept from the first report that needed a reboot, so "pending for 7 days"
// means seven days, not seven days since the last static report.
func rebootSinceUpdate(prevRequired bool, prevSince *time.Time, nowRequired bool, now time.Time) (*time.Time, bool) {
if !nowRequired {
return nil, prevSince != nil || prevRequired
}
if prevSince == nil {
return &now, false
}
return nil, false
}
@@ -0,0 +1,24 @@
package services
import (
"testing"
"time"
)
func TestRebootSinceUpdate(t *testing.T) {
now := time.Date(2026, 9, 17, 0, 0, 0, 0, time.UTC)
earlier := now.Add(-72 * time.Hour)
if set, unset := rebootSinceUpdate(false, nil, true, now); set == nil || !set.Equal(now) || unset {
t.Fatal("turning on must stamp now")
}
if set, unset := rebootSinceUpdate(true, &earlier, true, now); set != nil || unset {
t.Fatal("staying on must keep the original stamp")
}
if set, _ := rebootSinceUpdate(true, nil, true, now); set == nil {
t.Fatal("on with no stamp (pre-upgrade data) must stamp now")
}
if set, unset := rebootSinceUpdate(true, &earlier, false, now); set != nil || !unset {
t.Fatal("turning off must clear the stamp")
}
}