#!/bin/bash
# ---------------------------------------------------------------------
# Copyright (c) 2020, 2022 by Cisco Systems, Inc.
# All rights reserved.
#
# xr_recovery
# Script that tries to run LVM commands to recover from some minor
# LVM metadata corruption. It tries to deactivate all the VGs, then
# recreate the PV from a backup or archived LVM metadata file and
# does a vgcfgrestore to restore the VG.
# The script is run first in auto mode trying to recover automatically.
# If that fails then the system will drop to a shell for manual
# recovery.
# ---------------------------------------------------------------------

#Recovery script for diskbooted image

DR_PART="/mnt/dr_part"
DR_LVM_DIR="$DR_PART/lvm"
DR_LVM_LOG_FILE="$DR_LVM_DIR/log/lvm2.log"
DR_BACKUP_DIR="$DR_LVM_DIR/backup"
DR_ARCHIVE_DIR="$DR_LVM_DIR/archive"
BACKUP_DIR=/etc/lvm/backup
ARCHIVE_DIR=/etc/lvm/archive


function print_recovery_types
{
    echo "****Running recovery script ****"
    echo "1. Repair LVM errors "
    echo "2. Boot mode USB"
    echo "3: Boot mode external PXE"
    echo "4: Boot mode internal PXE"
    echo "5: Run LVM diagnostics"
    echo "6. Print LVM recovery steps"
  
    BOOT_MODE_USB=2
    BOOT_MODE_EXT_PXE=3
    BOOT_MODE_INT_PXE=4
 
    source /usr/local/etc/fpga-functions
 
    read -n 1 -p "Choose option: " rec_type
    echo ""

    if [ $rec_type -eq 1 ]; then
        echo "Trying to recover the LVs"
        run_lvm_recovery_steps
    elif [ $rec_type -eq 2 ]; then
        fpga_set_bios_boot_mode $BOOT_MODE_USB
        reboot -f
    elif [ $rec_type -eq 3 ]; then
        fpga_set_bios_boot_mode $BOOT_MODE_EXT_PXE
        reboot -f
    elif [ $rec_type -eq 4 ]; then
        fpga_set_bios_boot_mode $BOOT_MODE_INT_PXE
        reboot -f
    elif [ $rec_type -eq 5 ]; then
        echo "LVM Diags"
        run_lvm_diags
    elif [ $rec_type -eq 6 ]; then
        print_lvm_recovery_steps
    else
        exit 1 
    fi
}

function print_lvm_recovery_steps
{
    echo "LVM Recovery Steps "
    echo "*******************"
    echo "1: Find the restore file in DR partition, This is   "
    echo "   the file for restoring the PV (restore_file)     "
    echo "   Command: \"ls -lt /mnt/dr_part/lvm/archive/*\"   "
    echo "   Pick the top file in list.                       "
    echo "2: Find UUID of the device to be repaired in this  "
    echo "   backup file. Open the file, look for the ID under" 
    echo "   physical_volume pv0 section. This is the UUID.   "
    echo "   For example:						"
    echo "    physical_volumes {					"
    echo "           pv0 {						"	
    echo "                   id = \"32lw6c-VpSN-lpcv-Dhjw-5JDm-MIte-s1Ntp5i\" " 
    echo "3. Deactivate all LVs first                         "
    echo     Command: \"vgchange -a n\"
    echo "4. Try to create the PV again with the following cmd.  "
    echo "   Command: \"pvcreate --uuid <UUID> --restorefile <restore_file> <dev>\" "
    echo "5. If successful, restore the volume group. "
    echo "   Find vg_name from /mnt/dr_part/lvm/backup/"
    echo "   Restore VG "
    echo "   Command: \"vgcfgrestore <vg_name> --force\""
    echo "6. Run diag commands to see if restore is successful"
    echo "   Commands: \"pvs, vgs, lvs -a\""
}


function run_lvm_diags
{
    echo "*****LVM Diagnostics*****"
    #Run diag commands to see health of the LVs
    out=$(pvck -v -d $dev 2>&1)
    if [[ "$out" == *"Incorrect metadata"* ]]; then
        echo "  LVM metadata corrupted. Run recovery script "
        echo "  again and choose \"1. Repair LVM errors\"."
    else 
        echo "LVM looks clean!"
    fi 
    if [ -f $DR_LVM_LOG_FILE ]; then 
        echo "Additional LVM logs are stored at $DR_LVM_LOG_FILE."
    fi
}

function get_lvm_info
{
    echo "*****LVM INFO*****"
    pvs
    vgs
    lvs -a
    if [ -f $DR_LVM_LOG_FILE ]; then
        echo "Additional LVM logs are stored at $DR_LVM_LOG_FILE."
    fi
   
}

function run_lvm_recovery_steps
{
    #Get VG name, UUID and restore file from LVM backup
    vg=$(ls $DR_BACKUP_DIR)
    echo "VG name: $vg"
    DR_BACKUP_FILE=$DR_BACKUP_DIR/$vg

    #Get UUID
    # Get the line after pv0 that has UUID and remove the double quotes from the end
    uuid=$(sed -n '/pv0/{n; p}' $DR_BACKUP_FILE | head -n 1 | awk '{print $3}')
    uuid=${uuid//\"}

    # Get archive file to restore PV
    DR_ARCHIVE_FILE=$(ls $DR_ARCHIVE_DIR)
    restorefile=$DR_ARCHIVE_DIR/$DR_ARCHIVE_FILE
    if [ ! -f $restorefile ]; then
        restorefile=$DR_BACKUPDIR/$DR_BACKUP_FILE
    fi

    if [ ! -f $restorefile ]; then
        echo "Cannot find LVM metadata backup file. Run xr_recovery"
        echo "and choose PXE/USB boot options to recover this card."
        exit 1
    fi

    echo "UUID: $uuid"
    echo "Dev: $dev"
    echo "Restoring from: $restorefile"

    #Create the physical volume again
    if [ "$uuid" = "" ]; then 
        echo "Cannot find UUID. Try manual repair."
        print_lvm_recovery_steps
        exit 1
    fi
    #Deactivate all LVS before trying to recreate PV
    vgchange -a n 
    echo "Restoring physical volume..."
    pvcreate --uuid $uuid --restorefile $restorefile $dev -ff
    if [ $? -ne 0 ]; then
        echo "Cannot recreate PV: Try manual repair."
        print_lvm_recovery_steps
        exit 1
    else 
        #Copy over the backup/archive metadata from DR partition
        cp -r $DR_BACKUP_DIR/ $BACKUP_DIR/
        cp -r $DR_ARCHIVE_DIR/ $ARCHIVE_DIR/
        #Force restore of the XR VG
        echo "Restoring volume group..."
        vgcfgrestore $vg --force
        if [ $? -ne 0 ]; then
            echo "Cannot restore VG: $vg. Try manual repair."
            print_lvm_recovery_steps
            exit 1
        fi
    fi
    
    echo "Run diagnostics"
    run_lvm_diags $dev

    echo "Get LVM info"
    get_lvm_info

    echo "Rebooting in 3 seconds..."
    sleep 3
    reboot -f
}

#Get device name
DR_BACKUP_FILE=$DR_BACKUP_DIR/$(ls $DR_BACKUP_DIR)
dev=$(grep "device = " $DR_BACKUP_FILE | awk '{print $3}')
dev=${dev//\"}

if [ "$1" == "auto" ]; then
    touch $DR_PART/.auto_recovery
    run_lvm_recovery_steps
else
    print_recovery_types
fi


