Skip to content

store: scoped reads compare names byte-exact, so a case-variant spelling is invisible to the delete gates #195

Closed as not planned

Description

@IvanHunters

LINSTOR identifiers are case-insensitive on the wire, and this repository honours that almost everywhere: metadata.name is lowercased through crdname.Name(), VolumeDefinitions().ListAll keys on store.FoldName, resource list filters the whole listing case-insensitively, and pkg/store/cascade.go folds node names.

The scoped reads do not. At d2c6112:

  • pkg/store/k8s/resources.go:126 selects on FieldResourceDefinitionName with the caller's spelling, and :127 filters with r.Spec.ResourceDefinitionName == rdName, a byte comparison.
  • pkg/store/k8s/snapshots.go:103 and :139 do the same with FieldSnapshotDefinitionName.
  • The spec value they compare is stored verbatim: pkg/store/k8s/resources.go:1002 writes ResourceDefinitionName: in.Name from the request.

So metadata.name is folded while the spec field a scoped read selects on is not, and the two stop agreeing the moment a client spells the name in another case. Both of those reads gate rd d: the refusal that protects a definition with dependents, and the sweep that runs behind it. An object the gate cannot see is an object the refusal does not fire for.

Not a regression, and not introduced by any single change: the pre-field implementation missed the same objects for a different reason (an unset label). What changed is that the field selector is now presented as the fix for that class, so the remaining gap is easy to read as closed.

Why a comparison does not close it

The FoldName doc block at pkg/store/store.go:289 already works this through, and the conclusion there is the reason this needs a ticket rather than a patch:

Folding on the write side instead would fold what clients read back: crdToWireResource reports these spec values as the object's names, and crdname.go's annotation exists precisely to keep the stored spelling (DfltRscGrp) rather than the lowercased slug, because linstor-csi and runbooks compare those strings. Closing the gap properly means a folded field beside the display one, selected on and never rendered, a schema change with a migration for adopted objects, not a comparison.

That is the proposed shape, and it is a schema change with a migration for objects adopted from an existing cluster, which is why it does not belong in whatever PR happens to touch these reads next.

Reproducing

A StoragePool shows it without any REST call, because the CRD's own CEL rule compares with lowerAscii() and therefore admits the mixed-case spelling: apply a pool whose spec.nodeName is Node-Case on node node-case, then ask StoragePools().ListByNode(ctx, "node-case"). It answers empty, and node delete node-case is not refused.

Related

The same boundary has a second, smaller half on the CLI restore door, where the marker is written from the stored spelling but nothing pins it. That one is a test, not a schema change, and is tracked in the review of #190.

Activity

  1. IvanHunters commented on Sep 16, 2026

    @IvanHunters
    Author

    Duplicate of #194, which was filed a few minutes earlier and frames the same root more sharply: it follows the boundary to the destructive end (the definition goes, its replicas and snapshots stay with DRBD up) rather than to a gate that answers short. The two details this one added are now a comment there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions