Skip to content

Instantly share code, notes, and snippets.

@JohnStrunk
Last active January 20, 2025 13:36
Show Gist options
  • Save JohnStrunk/40ec88dea3b201da6af997dee427da90 to your computer and use it in GitHub Desktop.
Save JohnStrunk/40ec88dea3b201da6af997dee427da90 to your computer and use it in GitHub Desktop.
"Rename" a bound PVC
#! /bin/bash
set -e -o pipefail
function usage {
cat - <<USAGE
Usage:
$0 -n namespace -s source -d destination
USAGE
}
while getopts "d:hn:s:" opt; do
case ${opt} in
d)
DESTINATION_NAME="$OPTARG";;
h)
usage "$0"
exit 0;;
n)
NAMESPACE="$OPTARG";;
s)
SOURCE_NAME="$OPTARG";;
\?)
usage "$0"
exit 1;;
esac
done
shift $((OPTIND-1))
if [[ -z "$DESTINATION_NAME" || -z "$SOURCE_NAME" || -z "$NAMESPACE" ]]; then
usage "$0"
exit 1
fi
# Save source PVC
SOURCE_PVC=$(mktemp /tmp/pvc-XXXXXX.json)
kubectl -n "$NAMESPACE" get pvc "$SOURCE_NAME" -ojson > "$SOURCE_PVC"
# Create destination from source
# Strip out unneeded info & change name
DESTINATION_PVC=$(mktemp /tmp/pvc-XXXXXX.json)
jq "del(.metadata.annotations.\"pv.kubernetes.io/bind-completed\") |
del(.metadata.creationTimestamp) |
del(.metadata.finalizers[] | select(. == \"kubernetes.io/pvc-protection\")) |
del(.metadata.resourceVersion) |
del(.metadata.selfLink) |
del(.metadata.uid) |
del(.status) |
.metadata.name = \"$DESTINATION_NAME\"" \
"$SOURCE_PVC" > "$DESTINATION_PVC"
kubectl create -f "$DESTINATION_PVC"
# Set PV to retain
PV_NAME=$(jq -r .spec.volumeName "$SOURCE_PVC")
ORIG_RECLAIM=$(kubectl get pv "$PV_NAME" -ojson | jq -r .spec.persistentVolumeReclaimPolicy)
kubectl patch pv "$PV_NAME" --patch '{"spec": {"persistentVolumeReclaimPolicy": "Retain"}}'
# Delete source PVC
kubectl -n "$NAMESPACE" delete pvc "$SOURCE_NAME"
# Wait for PV to be Released
while [[ "$(kubectl get pv "$PV_NAME" -ojson | jq -r .status.phase)" != "Released" ]]; do
echo "Waiting for PV to be Released"
sleep 5
done
# Change PV to point to dest, mark available
kubectl patch pv "$PV_NAME" --type json --patch \
"[
{\"op\": \"replace\", \"path\": \"/spec/claimRef/name\", \"value\": \"$DESTINATION_NAME\"},
{\"op\": \"remove\", \"path\": \"/spec/claimRef/resourceVersion\"},
{\"op\": \"remove\", \"path\": \"/spec/claimRef/uid\"},
{\"op\": \"replace\", \"path\": \"/status.phase\", \"value\": \"Available\"},
]"
# Wait for PV to bind to new PVC
while [[ "$(kubectl -n "$NAMESPACE" get pvc "$DESTINATION_NAME" -ojson | jq -r .status.phase)" != "Bound" ]]; do
echo "Waiting for PVC to Bind"
sleep 5
done
while [[ "$(kubectl get pv "$PV_NAME" -ojson | jq -r .status.phase)" != "Bound" ]]; do
echo "Waiting for PV to Bind"
sleep 5
done
# Change PV to back to original reclaim policy
kubectl patch pv "$PV_NAME" --patch "{\"spec\": {\"persistentVolumeReclaimPolicy\": \"$ORIG_RECLAIM\"}}"
rm "$SOURCE_PVC" "$DESTINATION_PVC"
@vshlapakov
Copy link

Thanks a lot, works like a charm πŸ‘

A small addition is that the last 3 kubectl commands (2 while-s and the patch) also require a namespace parameter πŸ‘Œ

@JohnStrunk
Copy link
Author

Thanks for pointing that out. I updated L78 to have the namespace. The others reference PVs which aren't namespaced, so those should be ok as is.

@augusto-gtns
Copy link

tks

@lucanoderugeriis
Copy link

so useful!

@mmoisse
Copy link

mmoisse commented Jan 20, 2025

Works very well! Tx πŸ‘Œ

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