#!/usr/bin/env bash # written by Aaron 2023-08-27 command_exists() { command -v "$1" >/dev/null 2>&1 if [[ $? -ne 0 ]]; then echo "Software dependency not met: $1" exit 1 fi } command_exists "velero" command_exists "kubectl" velero backup get || exit 1 echo -n "Please specify backup to be restored: " read BACKUPNAME echo "restore CRDs and services (services are just restored to create the namespaces)" velero restore create --from-backup $BACKUPNAME --include-resources customresourcedefinitions,services --include-cluster-resources=true restore-part-1 || exit 1 echo "restore Longhorn and ingress controller" velero restore create --from-backup $BACKUPNAME --include-namespaces nginx-ingress,longhorn-system --include-cluster-resources=true restore-part-2 || exit 1 echo "" ###### # Wait for Longhorn deployment ###### namespace="longhorn-system" pod_name_pattern="instance-manager" wait_timeout=300 # Maximum time to wait for pod creation in seconds wait_interval=5 # Interval for checking pod creation in seconds echo "Waiting for $pod_name_pattern pods to be created in namespace $namespace..." # Wait loop to check pod creation elapsed_time=0 while [ $elapsed_time -lt $wait_timeout ]; do pod_names=$(kubectl get pods -n "$namespace" --output=jsonpath='{.items[*].metadata.name}' | grep -E "$pod_name_pattern") if [ -n "$pod_names" ]; then break fi sleep $wait_interval elapsed_time=$((elapsed_time + wait_interval)) done if [ -z "$pod_names" ]; then echo "No pods matching the pattern were created within the specified timeout." exit 1 fi echo "$pod_name_pattern pods detected. Proceeding with deletion in 10s..." sleep 10 ###### # Delete Longhorn Instance Pods ###### namespace="longhorn-system" pod_name_pattern="instance-manager" # Get the list of pod names in the specified namespace pod_names=$(kubectl get pods -n "$namespace" --output=jsonpath='{.items[*].metadata.name}') if [ -z "$pod_names" ]; then echo "No pods found in namespace $namespace." exit 0 fi # Delete the matching pods one by one for pod_name in $pod_names; do if echo "$pod_name" | grep -q "^$pod_name_pattern"; then kubectl delete pod "$pod_name" -n "$namespace" echo "Deleted pod: $pod_name" fi done function yes_or_no { while true; do read -p "$* [y/n]: " yn case $yn in [Yy]*) return 0 ;; [Nn]*) return 1 ;; esac done } if yes_or_no "Should the script restore all backups automatically?"; then command_exists "curl" command_exists "jq" while :; do echo -n "longhorn username: " read USERNAME echo -n "longhorn password: " read -s PASSWORD echo "" # check if credentials work API_STATUS_CODE=$(curl -o /dev/null -su "$USERNAME:$PASSWORD" -w "%{http_code}" -X "GET" "https://longhorn.services.yolokube.de/v1") if [[ $API_STATUS_CODE == "200" ]]; then break else echo "login credentials seem to be wrong, got error $API_STATUS_CODE" fi done # get Backup Target BACKUPTARGET=$(curl -su "$USERNAME:$PASSWORD" https://longhorn.services.yolokube.de/v1/backuptargets | jq -r ".data[0].backupTargetURL") while IFS= read -r b; do LASTBACKUP=$(echo $b | jq -r ".lastBackupName") VOLUMEID=$(echo $b | jq -r ".id") API_STATUS_CODE=$(curl -o /dev/null -su "$USERNAME:$PASSWORD" -w "%{http_code}" -X "POST" "https://longhorn.services.yolokube.de/v1/volumes" \ -H 'Content-Type: application/json' \ -d $"{ \"name\": \"${VOLUMEID}\", \"numberOfReplicas\": 3, \"accessMode\": \"rwo\", \"encrypted\": false, \"restoreVolumeRecurringJob\": \"ignored\", \"nodeSelector\": [], \"diskSelector\": [], \"fromBackup\": \"${BACKUPTARGET}?backup=${LASTBACKUP}&volume=${VOLUMEID}\", \"staleReplicaTimeout\": 20 }") if [[ $API_STATUS_CODE != "200" ]]; then echo "could not restore $VOLUMEID" fi done <<< "$(curl -su "$USERNAME:$PASSWORD" https://longhorn.services.yolokube.de/v1/backupvolumes | jq -c '.data[]')" wait_for_volume () { counter=0 while [ $counter -lt 50 ]; do # get volume info VOLUME=$(curl -su "$USERNAME:$PASSWORD" https://longhorn.services.yolokube.de/v1/volumes/$1) # parse json READY=$(echo $VOLUME | jq -r ".ready") STATE=$(echo $VOLUME | jq -r ".state") # if the volume is ready return if [ $READY == "true" ] && [ $STATE == "detached" ]; then return fi let counter++ sleep 5 done echo "timeout while waiting for volume $1 to become ready" } # wait a while for longhorn to create the volumes from backup echo "waiting for backups to be restored" sleep 10 # go through all volumes while IFS= read -r b; do VOLUMEID=$(echo $b | jq -r ".id") VOLUMENAME=$(echo $b | jq -r ".name") NAMESPACE=$(echo $b | jq -r ".kubernetesStatus.namespace") PVCNAME=$(echo $b | jq -r ".kubernetesStatus.pvcName") echo "wait for $VOLUMEID to bevome ready" wait_for_volume $VOLUMEID echo "volume is ready... create PVs and PVCs" API_STATUS_CODE=$(curl -o /dev/null -su "$USERNAME:$PASSWORD" -w "%{http_code}" -X "POST" "https://longhorn.services.yolokube.de/v1/volumes/$VOLUMEID?action=pvCreate" \ -H 'Content-Type: application/json' \ -d $"{ \"pvName\":\"${VOLUMENAME}\", \"fsType\":\"ext4\" }") if [[ $API_STATUS_CODE != "200" ]]; then echo "could not create PV for $VOLUMEID" fi API_STATUS_CODE=$(curl -o /dev/null -su "$USERNAME:$PASSWORD" -w "%{http_code}" -X "POST" "https://longhorn.services.yolokube.de/v1/volumes/$VOLUMEID?action=pvcCreate" \ -H 'Content-Type: application/json' \ -d $"{ \"pvcName\":\"${PVCNAME}\", \"namespace\":\"${NAMESPACE}\" }") if [[ $API_STATUS_CODE != "200" ]]; then echo "could not create PVC for $VOLUMEID" fi done <<< "$(curl -su "$USERNAME:$PASSWORD" https://longhorn.services.yolokube.de/v1/volumes | jq -c '.data[]')" else echo "Please restore the pvs and pvcs manually. After that write done: " while :; do read INPUT if [[ $INPUT == "done" ]]; then break fi done fi echo "Restore everything else" velero restore create --from-backup "$BACKUPNAME" --exclude-resources persistentvolumes,persistentvolumeclaims restore-part-3 || exit 1