mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 14:00:29 +00:00
Fix silent fingerprint loss for LXC and VMs
processFingerprint ran v.Index(i).Interface() then reflect.ValueOf(item), dropping addressability and making reflect.Call panic on every iteration with "Container as type *Container". The defer/recover in collectFingerprints swallowed it, so LXC and VM fingerprints never landed in the store — change-detection and discovery for those resource types have been broken since v6. Pass the slice element's address straight through (.Addr()) so the generator's pointer receiver gets the right type. Add a regression test that fails if anyone goes back through .Interface().
This commit is contained in:
@@ -1104,14 +1104,19 @@ func (s *Service) processFingerprint(
|
||||
default:
|
||||
}
|
||||
|
||||
item := v.Index(i).Interface()
|
||||
itemVal := reflect.ValueOf(item)
|
||||
// Generators take *Container / *VM. Reach through .Addr() — going via
|
||||
// .Interface() drops addressability and reflect.Call panics on the type
|
||||
// mismatch.
|
||||
elem := v.Index(i)
|
||||
if !elem.CanAddr() {
|
||||
continue
|
||||
}
|
||||
|
||||
node := itemVal.FieldByName("Node").String()
|
||||
name := itemVal.FieldByName("Name").String()
|
||||
vmid := itemVal.FieldByName("VMID").Int()
|
||||
node := elem.FieldByName("Node").String()
|
||||
name := elem.FieldByName("Name").String()
|
||||
vmid := elem.FieldByName("VMID").Int()
|
||||
|
||||
args := []reflect.Value{reflect.ValueOf(node), reflect.ValueOf(item)}
|
||||
args := []reflect.Value{reflect.ValueOf(node), elem.Addr()}
|
||||
newFP := fpFuncVal.Call(args)[0].Interface().(*ContainerFingerprint)
|
||||
fpKey := prefix + node + ":" + newFP.ResourceID
|
||||
|
||||
|
||||
@@ -850,6 +850,51 @@ func TestService_FingerprintCollectionAndDiscoveryWrappers(t *testing.T) {
|
||||
service.collectFingerprints(context.Background())
|
||||
}
|
||||
|
||||
// Regression: collectFingerprints used to panic-and-recover for every LXC/VM
|
||||
// because processFingerprint went through reflect.Value.Interface(), losing
|
||||
// addressability so reflect.Call hit a Container-vs-*Container type mismatch.
|
||||
// Fingerprints for LXC and VMs silently never landed in the store. This test
|
||||
// fails (no rows under the expected keys) if anyone reintroduces that.
|
||||
func TestService_CollectFingerprints_LXCAndVM(t *testing.T) {
|
||||
store, err := NewStore(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore error: %v", err)
|
||||
}
|
||||
store.crypto = nil
|
||||
|
||||
state := StateSnapshot{
|
||||
Containers: []Container{
|
||||
{VMID: 100, Name: "lxc-one", Node: "pve1", Status: "running", OSTemplate: "debian-12", CPUs: 2, MaxMemory: 2 << 30},
|
||||
{VMID: 101, Name: "lxc-two", Node: "pve1", Status: "running", OSTemplate: "ubuntu-22", CPUs: 1, MaxMemory: 1 << 30},
|
||||
},
|
||||
VMs: []VM{
|
||||
{VMID: 200, Name: "vm-one", Node: "pve1", Status: "running", OSName: "ubuntu", CPUs: 4, MaxMemory: 4 << 30},
|
||||
},
|
||||
}
|
||||
|
||||
service := NewService(store, nil, DefaultConfig())
|
||||
service.SetReadState(readStateFromSnapshot(state))
|
||||
|
||||
service.collectFingerprints(context.Background())
|
||||
|
||||
for _, key := range []string{
|
||||
"system-container:pve1:100",
|
||||
"system-container:pve1:101",
|
||||
"vm:pve1:200",
|
||||
} {
|
||||
fp, err := store.GetFingerprint(key)
|
||||
if err != nil {
|
||||
t.Fatalf("GetFingerprint(%q) error: %v", key, err)
|
||||
}
|
||||
if fp == nil {
|
||||
t.Fatalf("expected fingerprint at %q, got nil — processFingerprint silently dropped it", key)
|
||||
}
|
||||
if fp.Hash == "" {
|
||||
t.Fatalf("fingerprint %q has empty hash", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_PromptsAndDiscoveryLoop(t *testing.T) {
|
||||
service := NewService(nil, nil, DefaultConfig())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user