linode / linode/linode-blockstorage-csi-driver
Build the Volume label from the PVC's identity, not req.GetName()
- Dominant language
- Go
- Stars
- 76
- Forks
- 62
- Avg merge
- 10h 58m
- Merged PRs (30d)
- 10
Description
### Summary
`CreateVolume` builds the Linode Volume label from `req.GetName()`, which for dynamic provisioning is the external-provisioner's generated `pvc-`. The PVC's own namespace and name never reach the label, so every dynamically-provisioned Volume is opaque in the Cloud Manager, the billing export and the quota census.
The only lever today is `--volume-label-prefix`, which is driver-level: it can distinguish clusters, but not workloads within one.
### Why this cannot be worked around downstream
Renaming the Volume after creation looks like the obvious fix. It is not — it permanently breaks the Volume.
`findDevicePath` resolves the block device by **label**:
```go
deviceName := key.GetNormalizedLabel()
devicePaths := ns.deviceutils.GetDiskByIdPaths(deviceName, partition)
```
and that label comes from the CSI volume handle, which is parsed as free-form text after the first dash:
```go
func ParseLinodeVolumeKey(key string) (*LinodeVolumeKey, error) {
keys := strings.SplitN(key, "-", 2)
...
lvk := LinodeVolumeKey{volumeID, keys[1]}
```
The handle is stamped at CreateVolume and never changes, so renaming the Volume moves the in-guest udev symlink while the driver goes on looking for the old name:
```
MountVolume.MountDevice failed for volume "pvc-72af5c8ff02c4813":
Unable to find device path out of attempted paths:
[/dev/disk/by-id/linode-pvc-72af5c8ff02c4813
/dev/disk/by-id/scsi-0Linode_Volume_pvc-72af5c8ff02c4813]
```
It never recovers, and it is not limited to the moment of the rename: a renamed Volume that is already mounted keeps working, then fails on its **next** attach — a node drain, a pod reschedule, an upgrade.
We learned this the expensive way. An in-cluster reconciler of ours renamed bound Volumes to `--` for readability. It reproduced 3/3 on fresh clusters, and in the field showed up as "1 of 3 Loki ingesters ready for 16 days". We have retired that reconciler entirely; there is no safe subset of it.
### The request
Build the label from the PVC identity the external-provisioner already supplies with `--extra-create-metadata`:
- `csi.storage.k8s.io/pvc/name`
- `csi.storage.k8s.io/pvc/namespace`
falling back to the current `req.GetName()` behaviour when they are absent.
**This is safe by construction, and that is the point.** `CreateVolume` builds the handle from the Volume it just created:
```go
key := linodevolumes.CreateLinodeVolumeKey(vol.ID, vol.Label)
```
so label and handle come from a single value and cannot diverge. That is the invariant no post-creation rename can hold, and it is why this has to happen in the driver rather than anywhere downstream.
### One design note, from having got it wrong
`LinodeVolumeLabelLength` is 32 and `GetNormalizedLabel` truncates from the right:
```go
if len(label) > LinodeVolumeLabelLength {
label = label[:LinodeVolumeLabelLength]
}
```
The right-hand side is exactly where a StatefulSet's ordinal lives. `llz-openbao/data-platform-openbao-{0,1,2}` all truncate to the same string, and Linode Volume labels are account-unique — so the first wins and the rest fail `400 {"reason":"Must be unique"}`. We measured 17 of 17 renames rejected this way before fixing it.
If the label starts carrying `-`, truncation needs to drop from the **middle** and keep the discriminating tail. Ours ended up as: keep the last 8 characters, join with `-`, trim. Not a guarantee of uniqueness, but it removes the systematic collision.
### Related
`--extra-create-metadata` also needs to be set on the external-provisioner for these parameters to be populated. On managed LKE-Enterprise that is not operator-settable, so the two halves need to land together to be useful there.
Contributor guide
Research direction
Start at CreateVolume and trace how the label enters CreateLinodeVolumeKey, then read ParseLinodeVolumeKey, findDevicePath, and GetNormalizedLabel to understand the label-handle invariant. Done means PVC namespace/name metadata is used when present, the current name remains the fallback, and normalized labels avoid systematic collisions while the created handle still resolves the same label.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes
- Domain
- infrastructure
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100