skills/kubernetes-csi-pv-spec-update/SKILL.md
Update or correct fields in a CSI PersistentVolume spec (e.g., volumeAttributes, volumeHandle) that cannot be patched in place because spec.persistentvolumesource is immutable after creation. Use when: (1) kubectl patch on a PV fails with "spec.persistentvolumesource: Forbidden: spec.persistentvolumesource is immutable after creation", (2) a PV stores stale connection info (wrong IP, endpoint, or config) set at provision time that now differs from the desired state, (3) any CSI driver where volumeAttributes need to be corrected post-provisioning. Covers the replace --force procedure and pv-protection finalizer removal required to complete it.
npx skillsauth add aldengolab/lorist kubernetes-csi-pv-spec-updateInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A CSI PersistentVolume stores incorrect or outdated values in its spec (commonly
spec.csi.volumeAttributes) that were written at provision time and now need to
change. Attempting to patch the PV fails with:
The PersistentVolume "<name>" is invalid:
spec.persistentvolumesource: Forbidden: spec.persistentvolumesource is immutable after creation
kubectl patch pv <name> fails with "immutable after creation"volumeAttributes set at provision time takes
precedence over current driver config for existing volumesspec.csi needs to change after the PV was createdspec.persistentvolumesource is enforced as immutable by the Kubernetes API server
itself (not an admission webhook), so there is no way to patch it. The only path is
delete and recreate the PV using kubectl replace --force.
When a PVC is bound to a PV, the kubernetes.io/pv-protection controller adds a
finalizer that blocks PV deletion. kubectl replace --force will hang until the PV
is fully deleted, which won't happen while the finalizer is present. Remove it first:
kubectl patch pv <pv-name> -p '{"metadata":{"finalizers":null}}'
The PVC will briefly emit a ClaimLost warning event during the window between PV
deletion and recreation. This is transient — the PVC rebinds automatically when the
new PV appears. If the storage has a Retain reclaim policy (recommended for
stateful workloads), no data is at risk.
kubectl get pv <pv-name> -o json | \
python3 -c "
import json, sys
pv = json.load(sys.stdin)
# Make your changes here, e.g.:
pv['spec']['csi']['volumeAttributes']['transports'] = 'tcp://192.168.0.19:4420'
# Strip fields that cause conflicts on re-create
pv['metadata'].pop('managedFields', None)
pv['metadata'].pop('resourceVersion', None)
print(json.dumps(pv))
" | kubectl replace --force -f -
kubectl get pv <pv-name> -o jsonpath='{.status.phase}' # should be Bound
kubectl get pvc -n <namespace> # should show Bound
For multiple PVs with the same fix:
for pv in pv-name-1 pv-name-2 pv-name-3; do
kubectl patch pv $pv -p '{"metadata":{"finalizers":null}}'
kubectl get pv $pv -o json | \
python3 -c "
import json, sys
pv = json.load(sys.stdin)
pv['spec']['csi']['volumeAttributes']['<key>'] = '<new-value>'
pv['metadata'].pop('managedFields', None)
pv['metadata'].pop('resourceVersion', None)
print(json.dumps(pv))
" | kubectl replace --force -f -
done
# Confirm the field is updated
kubectl get pv <pv-name> -o jsonpath='{.spec.csi.volumeAttributes}'
# Confirm PVC is rebound
kubectl get pvc -n <namespace>
pv-protection finalizer is added by the PersistentVolumeProtection admission
controller and removed only when the PVC is deleted or the PV is released. Removing
it manually is safe as long as you immediately recreate the PV.ClaimLost warning events on the PVC during the replace cycle are expected and
transient. They do not indicate data loss when reclaim policy is Retain.volumeAttributes are written by the provisioner at CreateVolume time from
information returned by the storage backend. Changing the driver config does not
retroactively update existing PVs — only newly provisioned volumes will have the
corrected values.Init (volume never mounted) can be left running — they will
pick up the new PV automatically on next kubelet retry.democratic-csi-nvmeof-attach-failure — diagnose when the wrong transport IP is
being used by the NVMe-oF CSI node plugindevelopment
Build a UEFI Secure Boot PXE netboot server for Ubuntu autoinstall. Use when: designing or implementing network boot infrastructure for automated Ubuntu provisioning with Secure Boot enabled. Covers the complete chain: signed shim+GRUB selection, TFTP layout, kernel parameters, autoinstall config requirements, and post-install bootstrapping scripts. Also applicable when debugging an existing PXE setup that uses the wrong GRUB binary or config paths.
development
Design pattern for running a persistent PXE/TFTP server that safely coexists with already-installed nodes. Use when: building PXE infrastructure that should stay always-on, designing automated bare-metal provisioning in GitOps/Kubernetes environments, or any PXE setup where UEFI boot order has network boot first. Eliminates boot loops without requiring UEFI firmware changes.
development
This skill governs all prose output — Claude's own responses, documentation, PR descriptions, commit messages, README content, comments, and any text the user asks to draft or edit. It should also be used when the user asks to "review my writing", "edit this for clarity", "make this clearer", "simplify this text", "rewrite this", "check my prose", "tighten this up", or "make this more concise". Based on George Orwell's "Politics and the English Language" (1946).
development
Debug Kubernetes pods using hostNetwork: true that crash with "Address already in use" or "failed to create listening socket for port N". Use when: (1) a hostNetwork pod container is in CrashLoopBackOff and logs show a port bind failure, (2) the port works fine in non-hostNetwork pods but fails with hostNetwork, (3) you need to identify which host-level process holds a port from within Kubernetes (no SSH). Covers /proc/net/udp inspection and kubectl debug node with nsenter.