You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
rd delete folds the name while its gates compare it byte-exact, so a mixed-case delete strands replicas and snapshots #194
rd d PVC-X against a definition stored as pvc-x deletes the definition and leaves its replicas and snapshots behind, with live DRBD state under them.
The store folds a name when it addresses one object and compares it byte-exact when it lists several. pkg/store/k8s/crdname.go lowercases on the way to the CRD name, so ResourceDefinitions().Delete and Get resolve whatever case the operator typed. Resources().ListByDefinition and Snapshots().ListByDefinition select on spec.resourceDefinitionName and compare it as stored (pkg/store/k8s/resources.go, snapshots.go), and both spellings are legal LINSTOR input.
So on the delete path the snapshot gate lists zero rows and passes, the cascade lists zero replicas and reaps nothing, and the final Delete folds and takes the definition. What is left points at a definition that is gone, and the replica still has DRBD up on its node.
Reproduced on envtest during the review of #191: the gate saw 0 snapshots, Delete returned nil, and one replica and one snapshot survived.
This is not a regression. The merge base compares the same way and has no FoldName at all. It was carried as a review note through several rounds of #191 and is filed here instead, because the door it leaves is destructive rather than a read that answers short.
The fix FoldName's own doc comment describes is a folded field beside the display one, selected on and never rendered, which is a CRD schema change plus a migration for objects adopted from LINSTOR. Folding on the write side instead would fold what clients read back: crdToWireResource reports these spec values as the object's names, and the annotation in crdname.go exists to keep the stored spelling, because linstor-csi and runbooks compare those strings.
Worth knowing for whoever picks this up: the in-memory store keys its objects by the spelling they were written with, so a unit fixture cannot express a stored spelling that differs from the queried one. A test for this needs envtest or the fold has to reach the in-memory store first.
Filed #195 for the same boundary before seeing this one; closing mine as a duplicate. Two details from it that are not here, in case they are useful.
A reproduction that needs no REST call. The StoragePool CRD's own CEL rule compares with lowerAscii(), so it admits a pool whose spec.nodeName is Node-Case on node node-case. StoragePools().ListByNode(ctx, "node-case") then answers empty, and node delete node-case is not refused. Same root, third kind, and it reaches the node-delete gate rather than the definition-delete one.
Coordinates at d2c6112, for whoever picks this up:
pkg/store/k8s/resources.go:126 selects with the caller's spelling, :127 filters with r.Spec.ResourceDefinitionName == rdName
pkg/store/k8s/snapshots.go:103 and :139
pkg/store/k8s/resources.go:1002 stores the spec value verbatim as ResourceDefinitionName: in.Name
the FoldName doc block starts at pkg/store/store.go:289
Activity
IvanHunters commentedon Sep 16, 2026
Filed #195 for the same boundary before seeing this one; closing mine as a duplicate. Two details from it that are not here, in case they are useful.
A reproduction that needs no REST call. The
StoragePoolCRD's own CEL rule compares withlowerAscii(), so it admits a pool whosespec.nodeNameisNode-Caseon nodenode-case.StoragePools().ListByNode(ctx, "node-case")then answers empty, andnode delete node-caseis not refused. Same root, third kind, and it reaches the node-delete gate rather than the definition-delete one.Coordinates at
d2c6112, for whoever picks this up:pkg/store/k8s/resources.go:126selects with the caller's spelling,:127filters withr.Spec.ResourceDefinitionName == rdNamepkg/store/k8s/snapshots.go:103and:139pkg/store/k8s/resources.go:1002stores the spec value verbatim asResourceDefinitionName: in.NameFoldNamedoc block starts atpkg/store/store.go:289fix(store): find a definition's replicas and snapshots in any spelling
fix(store): find a definition's replicas and snapshots in any spelling
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names
fix(store): store a replica's parents under their CR names