Created
May 7, 2025 21:08
-
-
Save ParadoxGuitarist/5cfbe9baeb39e8e9324afc2899d8a163 to your computer and use it in GitHub Desktop.
Bash scripts for migrating block devices Mostly for Harvester/Longhorn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# LICENSE: MIT | |
# This takes a PVC name and namespace then flattens the boot disk (to get it off a backed image disk). | |
# Exit if there's none provided. | |
if [ -z $1 ] && [ -z $2 ]; then | |
echo "You need to provide a pvcname and namespace for the disk you want to flatten." | |
exit 1 | |
fi | |
echo "Looking to flatten $1 from image backed $vmVolumePVC" | |
# Get the PVC object related stuff | |
diskPVC=$(kubectl -n $2 get pvc $1 -o json) | |
diskSC=$(echo $diskPVC | jq -r .spec.storageClassName) | |
diskCap=$(echo $diskPVC | jq -r .status.capacity.storage) | |
defaultSC=$(kubectl get storageclasses.storage.k8s.io |grep "(default)" | awk '{ print $1}') | |
vmns=$2 | |
#If the disk mode permits, we might not have to shut it down, but I'd feel better about it if we did. | |
diskMode=$(kubectl -n $vmns get pvc $vmVolumePVC --no-headers | awk '{ print $5 }') | |
# Make sure we can actually flatten this and it's currently and image backed SC. | |
if [ $diskSC == $defaultSC ]; then | |
echo "Yoooo.. This disk is already the default storage class. I don't think it can be flattened. Exiting." | |
exit 1 | |
fi | |
if [ $(kubectl get sc $diskSC -o json |jq .parameters.backingImage) == 'null' ]; then | |
echo "This doesn't seem to be an image backed disk so there's nothing to flatten" | |
exit 1 | |
else | |
echo "We got a image backed disk: $(kubectl get sc $diskSC -o json |jq -r .parameters.backingImage)" | |
fi | |
if [ $(kubectl get sc $defaultSC -o json |jq .parameters.backingImage) == 'null' ]; then | |
echo "The default storage class ($defaultSC) looks flat." | |
else | |
echo "The default storage class - $defaultSC - seems to be backed by an image - $(kubectl get sc $defaultSC -o json |jq .parameters.backingImage)" | |
echo "This isn't going to work." | |
exit 1 | |
fi | |
# Make a new PVC Root-Flat disk. | |
if [ -n $3 ] ; then | |
newDiskName="$3" | |
else | |
newDiskName="$1-flat" | |
fi | |
echo "We're going to make a new $diskCap disk called $newDiskName with the default StorageClass: $defaultSC." | |
cat <<EOF | kubectl apply -f - | |
apiVersion: v1 | |
kind: PersistentVolumeClaim | |
metadata: | |
name: $newDiskName | |
namespace: $vmns | |
spec: | |
accessModes: | |
- ReadWriteMany | |
resources: | |
requests: | |
storage: $diskCap | |
storageClassName: $defaultSC | |
volumeMode: Block | |
EOF | |
echo -n "Waiting for $newDiskName to be ready..." | |
while [[ $(kubectl -n $vmns get pvc $newDiskName -o json |jq -r '.metadata.annotations.["pv.kubernetes.io/bind-completed"]' ) != "yes" ]]; do | |
echo -n "." | |
sleep 3 | |
done | |
echo "" | |
echo -n "Creating a job to block copy the disks." | |
# Mount the PVCs in a pod so we can dd them in a job. | |
cat <<EOF | kubectl apply -f - | |
apiVersion: batch/v1 | |
kind: Job | |
metadata: | |
name: $1-disk-flattener | |
namespace: $2 | |
spec: | |
backoffLimit: 2 | |
completionMode: NonIndexed | |
completions: 1 | |
parallelism: 1 | |
template: | |
metadata: | |
labels: | |
job-name: $1-disk-flattener | |
namespace: $2 | |
spec: | |
dnsPolicy: ClusterFirst | |
restartPolicy: Never | |
schedulerName: default-scheduler | |
terminationGracePeriodSeconds: 30 | |
containers: | |
- name: sak-disk-flattener | |
image: supporttools/swiss-army-knife | |
command: ["/bin/sh", "-c"] | |
args: [ "dd if=/dev/xvdb of=/dev/xvdc status=progress bs=4096" ] | |
imagePullPolicy: IfNotPresent | |
volumeDevices: | |
- name: old-disk | |
devicePath: /dev/xvdb | |
- name: new-disk | |
devicePath: /dev/xvdc | |
volumes: | |
- name: old-disk | |
persistentVolumeClaim: | |
claimName: $1 | |
- name: new-disk | |
persistentVolumeClaim: | |
claimName: $newDiskName | |
EOF | |
echo "" | |
echo -n "Waiting for $1-disk-flattener job to complete..." | |
sleep 5 | |
while [[ $(kubectl -n $vmns get job $1-disk-flattener -o json | jq -r .status.succeeded ) != 1 ]]; do | |
echo -n "." | |
sleep 5 | |
done | |
echo "" | |
echo "The new disk $newDiskName is ready now. You'll probably need to delete the jobs and related pods in $3 before you can delete $1. Good luck!" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# LICENSE: MIT | |
# This takes a PVC name and namespace then flattens the boot disk (to get it off a backed image disk). | |
# Exit if there's none provided. | |
if [ -z $1 ] && [ -z $2 ] [ -z $3 ] [ -z $4 ]; then | |
echo "You need to provide a pvcname, namespace, new-diskname, and storageclass for the disk you want to migrate" | |
exit 1 | |
fi | |
echo "Looking to migrate $1 to $4" | |
# Get the PVC object related stuff | |
diskPVC=$(kubectl -n $2 get pvc $1 -o json) | |
diskSC=$(echo $diskPVC | jq -r .spec.storageClassName) | |
diskCap=$(echo $diskPVC | jq -r .status.capacity.storage) | |
defaultSC=$(kubectl get storageclasses.storage.k8s.io |grep "(default)" | awk '{ print $1}') | |
vmns=$2 | |
#If the disk mode permits, we might not have to shut it down, but I'd feel better about it if we did. | |
diskMode=$(kubectl -n $vmns get pvc $vmVolumePVC --no-headers | awk '{ print $5 }') | |
# Make sure we can actually flatten this and it's currently and image backed SC. | |
if [ $diskSC == $4 ]; then | |
echo "Yoooo.. This disk is already the sane storage class. Exiting." | |
exit 1 | |
fi | |
# Make a new PVC Root-Flat disk. | |
if [ -n $3 ] ; then | |
newDiskName="$3" | |
else | |
newDiskName="$1-flat" | |
fi | |
echo "We're going to make a new $diskCap disk called $newDiskName with the $4 StorageClass." | |
cat <<EOF | kubectl apply -f - | |
apiVersion: v1 | |
kind: PersistentVolumeClaim | |
metadata: | |
name: $newDiskName | |
namespace: $vmns | |
spec: | |
accessModes: | |
- ReadWriteMany | |
resources: | |
requests: | |
storage: $diskCap | |
storageClassName: $4 | |
volumeMode: Block | |
EOF | |
echo -n "Waiting for $newDiskName to be ready..." | |
while [[ $(kubectl -n $vmns get pvc $newDiskName -o json |jq -r '.metadata.annotations.["pv.kubernetes.io/bind-completed"]' ) != "yes" ]]; do | |
echo -n "." | |
sleep 3 | |
done | |
echo "" | |
echo -n "Creating a job to block copy the disks." | |
# Mount the PVCs in a pod so we can dd them in a job. | |
cat <<EOF | kubectl apply -f - | |
apiVersion: batch/v1 | |
kind: Job | |
metadata: | |
name: $1-sc-migration | |
namespace: $2 | |
spec: | |
backoffLimit: 2 | |
completionMode: NonIndexed | |
completions: 1 | |
parallelism: 1 | |
template: | |
metadata: | |
labels: | |
job-name: $1-sc-migration | |
namespace: $2 | |
spec: | |
dnsPolicy: ClusterFirst | |
restartPolicy: Never | |
schedulerName: default-scheduler | |
terminationGracePeriodSeconds: 30 | |
containers: | |
- name: sak-disk-flattener | |
image: supporttools/swiss-army-knife | |
command: ["/bin/sh", "-c"] | |
args: [ "dd if=/dev/xvdb of=/dev/xvdc status=progress bs=4096" ] | |
imagePullPolicy: IfNotPresent | |
volumeDevices: | |
- name: old-disk | |
devicePath: /dev/xvdb | |
- name: new-disk | |
devicePath: /dev/xvdc | |
volumes: | |
- name: old-disk | |
persistentVolumeClaim: | |
claimName: $1 | |
- name: new-disk | |
persistentVolumeClaim: | |
claimName: $newDiskName | |
EOF | |
echo "" | |
echo -n "Waiting for $1-sc-migration job to complete..." | |
sleep 5 | |
while [[ $(kubectl -n $vmns get job $1-sc-migration -o json | jq -r .status.succeeded ) != 1 ]]; do | |
echo -n "." | |
sleep 5 | |
done | |
echo "" | |
echo "The new disk $newDiskName is ready now. You'll probably need to delete the jobs and related pods in $3 before you can delete $1. Good luck!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment