#!/bin/bash # Simple backup script for your personal cloud set -e set -o pipefail # Parse command line flags BACKUP_HOME=true BACKUP_APPS=true BACKUP_CLUSTER=true show_help() { echo "Usage: $0 [OPTIONS]" echo "Backup components of your wild-cloud infrastructure" echo "" echo "Options:" echo " --home-only Backup only WC_HOME (wild-cloud configuration)" echo " --apps-only Backup only applications (databases and PVCs)" echo " --cluster-only Backup only Kubernetes cluster resources" echo " --no-home Skip WC_HOME backup" echo " --no-apps Skip application backups" echo " --no-cluster Skip cluster resource backup" echo " -h, --help Show this help message" echo "" echo "Default: Backup all components (home, apps, cluster)" } # Process command line arguments while [[ $# -gt 0 ]]; do case $1 in --home-only) BACKUP_HOME=true BACKUP_APPS=false BACKUP_CLUSTER=false shift ;; --apps-only) BACKUP_HOME=false BACKUP_APPS=true BACKUP_CLUSTER=false shift ;; --cluster-only) BACKUP_HOME=false BACKUP_APPS=false BACKUP_CLUSTER=true shift ;; --no-home) BACKUP_HOME=false shift ;; --no-apps) BACKUP_APPS=false shift ;; --no-cluster) BACKUP_CLUSTER=false shift ;; -h|--help) show_help exit 0 ;; *) echo "Unknown option: $1" show_help exit 1 ;; esac done # Initialize Wild Cloud environment if [ -z "${WC_ROOT}" ]; then echo "WC_ROOT is not set." exit 1 else source "${WC_ROOT}/scripts/common.sh" init_wild_env fi if `wild-config cloud.backup.root --check`; then export RESTIC_REPOSITORY="$(wild-config cloud.backup.root)" else echo "WARNING: Could not get cloud backup root." exit 1 fi if `wild-secret cloud.backupPassword --check`; then export RESTIC_PASSWORD="$(wild-secret cloud.backupPassword)" else echo "WARNING: Could not get cloud backup secret." exit 1 fi if `wild-config cloud.backup.staging --check`; then STAGING_DIR="$(wild-config cloud.backup.staging)" else echo "WARNING: Could not get cloud backup staging directory." exit 1 fi echo "Backup at '$RESTIC_REPOSITORY'." # Initialize the repository if needed. echo "Checking if restic repository exists..." if restic cat config >/dev/null 2>&1; then echo "Using existing backup repository." else echo "No existing backup repository found. Initializing restic repository..." restic init echo "Repository initialized successfully." fi # Backup entire WC_HOME if [ "$BACKUP_HOME" = true ]; then echo "Backing up WC_HOME..." restic --verbose --tag wild-cloud --tag wc-home --tag "$(date +%Y-%m-%d)" backup $WC_HOME echo "WC_HOME backup completed." # TODO: Ignore wild cloud cache? else echo "Skipping WC_HOME backup." fi mkdir -p "$STAGING_DIR" # Run backup for all apps at once if [ "$BACKUP_APPS" = true ]; then echo "Running backup for all apps..." wild-app-backup --all # Upload each app's backup to restic individually for app_dir in "$STAGING_DIR"/apps/*; do if [ ! -d "$app_dir" ]; then continue fi app="$(basename "$app_dir")" echo "Uploading backup for app: $app" restic --verbose --tag wild-cloud --tag "$app" --tag "$(date +%Y-%m-%d)" backup "$app_dir" echo "Backup for app '$app' completed." done else echo "Skipping application backups." fi # --- etcd Backup Function ---------------------------------------------------- backup_etcd() { local cluster_backup_dir="$1" local etcd_backup_file="$cluster_backup_dir/etcd-snapshot.db" echo "Creating etcd snapshot..." # For Talos, we use talosctl to create etcd snapshots if command -v talosctl >/dev/null 2>&1; then # Try to get etcd snapshot via talosctl (works for Talos clusters) local control_plane_nodes control_plane_nodes=$(kubectl get nodes -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}' | tr ' ' '\n' | head -1) if [[ -n "$control_plane_nodes" ]]; then echo "Using talosctl to backup etcd from control plane node: $control_plane_nodes" if talosctl --nodes "$control_plane_nodes" etcd snapshot "$etcd_backup_file"; then echo " etcd backup created: $etcd_backup_file" return 0 else echo " talosctl etcd snapshot failed, trying alternative method..." fi else echo " No control plane nodes found for talosctl method" fi fi # Alternative: Try to backup via etcd pod if available local etcd_pod etcd_pod=$(kubectl get pods -n kube-system -l component=etcd -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true) if [[ -n "$etcd_pod" ]]; then echo "Using etcd pod: $etcd_pod" # Create snapshot using etcdctl inside the etcd pod if kubectl exec -n kube-system "$etcd_pod" -- etcdctl \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ snapshot save /tmp/etcd-snapshot.db; then # Copy snapshot out of pod kubectl cp -n kube-system "$etcd_pod:/tmp/etcd-snapshot.db" "$etcd_backup_file" # Clean up temporary file in pod kubectl exec -n kube-system "$etcd_pod" -- rm -f /tmp/etcd-snapshot.db echo " etcd backup created: $etcd_backup_file" return 0 else echo " etcd pod snapshot failed" fi else echo " No etcd pod found in kube-system namespace" fi # Final fallback: Try direct etcdctl if available on local system if command -v etcdctl >/dev/null 2>&1; then echo "Attempting local etcdctl backup..." # This would need proper certificates and endpoints configured echo " Local etcdctl backup not implemented (requires certificate configuration)" fi echo " Warning: Could not create etcd backup - no working method found" echo " Consider installing talosctl or ensuring etcd pods are accessible" return 1 } # Back up Kubernetes cluster resources if [ "$BACKUP_CLUSTER" = true ]; then echo "Backing up Kubernetes cluster resources..." CLUSTER_BACKUP_DIR="$STAGING_DIR/cluster" # Clean up any existing cluster backup files if [[ -d "$CLUSTER_BACKUP_DIR" ]]; then echo "Cleaning up existing cluster backup files..." rm -rf "$CLUSTER_BACKUP_DIR" fi mkdir -p "$CLUSTER_BACKUP_DIR" kubectl get all -A -o yaml > "$CLUSTER_BACKUP_DIR/all-resources.yaml" kubectl get secrets -A -o yaml > "$CLUSTER_BACKUP_DIR/secrets.yaml" kubectl get configmaps -A -o yaml > "$CLUSTER_BACKUP_DIR/configmaps.yaml" kubectl get persistentvolumes -o yaml > "$CLUSTER_BACKUP_DIR/persistentvolumes.yaml" kubectl get persistentvolumeclaims -A -o yaml > "$CLUSTER_BACKUP_DIR/persistentvolumeclaims.yaml" kubectl get storageclasses -o yaml > "$CLUSTER_BACKUP_DIR/storageclasses.yaml" echo "Backing up etcd..." backup_etcd "$CLUSTER_BACKUP_DIR" echo "Cluster resources backed up to $CLUSTER_BACKUP_DIR" # Upload cluster backup to restic echo "Uploading cluster backup to restic..." restic --verbose --tag wild-cloud --tag cluster --tag "$(date +%Y-%m-%d)" backup "$CLUSTER_BACKUP_DIR" echo "Cluster backup completed." else echo "Skipping cluster backup." fi echo "Backup completed: $BACKUP_DIR"