#!/bin/bash

### log
SHELL_FOLDER=$(dirname $(readlink -f "$0"))
LOG_FILE=${SHELL_FOLDER}"/linux_image.log"
DATA_FORMAT="+%Y-%m-%d %H:%M:%S"
BACKUP_TIME=$(date +%Y%m%d%H%M%S)

function log_info()
{
    infomsg=$1
    echo `date "${DATA_FORMAT}"`  "Info:${infomsg}"
    echo `date "${DATA_FORMAT}"`  "Info:${infomsg}" >> ${LOG_FILE}
}

function log_warning()
{
    warnmsg=$1
    echo `date "${DATA_FORMAT}"`  "Warn:${warnmsg}"
    echo `date "${DATA_FORMAT}"`  "Warn:${warnmsg}" >> ${LOG_FILE}
}

function log_error()
{
    errorcode=$1
    errormsg=$2
    echo `date "${DATA_FORMAT}"`  "Error:${errormsg}"
    echo `date "${DATA_FORMAT}"`  "Error:${errormsg}" >> ${LOG_FILE}
    rollbackBackupFile
    exit ${errorcode}
}
###

### backup file
function backupFile()
{
    file=$1
    backup_file="${file}.rbak.${BACKUP_TIME}"
    log_info "backup file: ${file}"

    if [ ! -e "${backup_file}" ]; then
        if ! cp ${file} ${backup_file}; then
            log_warning "backup ${file} failed"
            return 1
        fi
        MODIFIED_FILE_LIST="${MODIFIED_FILE_LIST} ${file}"
    fi
}

function rollbackBackupFile()
{
    modified_file_list=($MODIFIED_FILE_LIST)
    for file in ${modified_file_list[@]}
    do
        if ! cp ${file}.rbak.${BACKUP_TIME} ${file}; then
            log_warning "rollback ${file} failed"
        fi
    done
}

function deleteBackupFile()
{
    modified_file_list=($MODIFIED_FILE_LIST)
    for file in ${modified_file_list[@]}
    do
        backupFile="${file}.rbak"
        if [ -e "${backupFile}" ]; then
            log_info "delete backupfile:${backupFile}"
            rm -f ${backupFile}
        fi
    done
}

# grub file and syslinux file
GRUB_FILE_LIST=""
SYSLINUX_FILE_LIST=""

########################################################################

# check hinic
check_hinic_in_initrd () {

    os_distro=`cat /etc/os-release |sed -n 's|^ID="\([a-z]\{4\}\).*|\1|p'`      # Check System distro

    if [ -f /etc/redhat-release ] ; then
        # Distribution is Red hat
        lsinitrd /boot/initramfs-$(uname -r).img|grep hinic > /dev/null 2>&1
        if [ $? -ne 0 ]; then
        # Hinic module is not loaded in initrd/initramfs
        log_info " ERROR  Hinic Module is not loaded in the initramfs image.\n\t- Please run the following command on your instance to recreate initramfs:"
        log_info ' # sudo dracut -f -v'
        fi
    elif [[ "${os_distro}" == "sles" ]] ; then
        # Distribution is SuSe Linux
        lsinitrd /boot/initrd-$(uname -r)|grep hinic > /dev/null 2>&1
        if [ $? -ne 0 ]; then
        # Hinic module is not loaded in initrd/initramfs
        log_info " ERROR  Hinic Module is not loaded in the initramfs image.\n\t- Please run the following command on your instance to recreate initramfs:"
        log_info ' # sudo dracut -f -v'
        fi

    elif [ -f /etc/debian_version ] ; then
        # Distribution is debian based(Debian/Ubuntu)
        lsinitramfs /boot/initrd.img-$(uname -r)|grep hinic > /dev/null 2>&1
        if [ $? -ne 0 ]; then
        # Hinic module is not loaded in initrd/initramfs
        log_info " ERROR  Hinic Module is not loaded in the initramfs image.\n\t- Please run the following command on your instance to recreate initramfs:"
        log_info ' sudo update-initramfs -c -k all'
        fi

    else
        log_info " Unsupported OS for this script."
        log_info " ------------------------------------------------"
        exit 1
    fi
}
########################################################################

### find grub file
function find_grub_file()
{
    log_info " Search grub file..."
    if [ -e "/boot/grub/grub.conf" ]; then
        GRUB_FILE_LIST="${GRUB_FILE_LIST} /boot/grub/grub.conf"
    fi
    if [ -e "/boot/grub/menu.lst" ]; then
        GRUB_FILE_LIST="${GRUB_FILE_LIST} /boot/grub/menu.lst"
    fi
    if [ -e "/boot/grub/grub.cfg" ]; then
        GRUB_FILE_LIST="${GRUB_FILE_LIST} /boot/grub/grub.cfg"
    fi
    if [ -e "/boot/grub2/grub.cfg" ]; then
        GRUB_FILE_LIST="${GRUB_FILE_LIST} /boot/grub2/grub.cfg"
    fi
    log_info " Find grub file: ${GRUB_FILE_LIST}"

    if [ -z "${GRUB_FILE_LIST}" -a -z "${SYSLINUX_FILE_LIST}" ]; then
        return 1
    fi
}
###

#modify fstab
function modify_fstab()
{
    #modify fstab
    log_info " Begin to modify fstab file..."
    #get device uuids
    device_uuids=`blkid | sed s/[[:space:]]//g`
    device_uuids=($device_uuids)
    fstab_file="/etc/fstab"
    log_info " Modify fstab file: ${fstab_file}"
    backupFile ${fstab_file}
    for item in ${device_uuids[@]}
    do
        device=`echo ${item} | awk -F ':' '{print $1}' | sed 's;\/;\\\/;g'`
        uuid=`echo ${item} | awk -F 'UUID=' '{print $2}' | awk '{print $1}' | awk -F '"' '{print $2}'`
        sed -i "s/^[[:space:]]*${device}[[:space:]]/UUID=${uuid}    /g" ${fstab_file}
    done
    change_dev_device_to_uuid ${fstab_file}
    log_info " Modify fstab file success!"
}

function change_dev_device_to_uuid()
{
    file=$1
    #change dev device name
    while [ -n "`cat ${file} | grep /dev/disk/by-id/`" ]
    do
        dev=`cat ${file} | grep -m 1 '/dev/disk/by-id/' | awk -F '/dev/disk/by-id/' '{print $2}' | awk '{print $1}'`
        dev_device=`ls -l /dev/disk/by-id/ | grep "${dev}" | awk -F '->' '{print $2}'`
        if [ -z "${dev_device}" ]; then
            log_error 2 " Cannot find dev!"
        fi
        dev_device=${dev_device##*/}
        uuid=`blkid | grep "${dev_device}" | awk -F 'UUID="' '{print $2}' | awk -F '"' '{print $1}'`
        sed -i "s/\/dev\/disk\/by-id\/${dev}/UUID=${uuid}/g" ${file}
    done
}

function set_metadata()
{
    meta_log="/var/log/ecs_modify.log"
    code=`curl 'http://169.254.169.254/openstack/latest/support_hypervisor' -X POST -H "Accept: application/json" -d '{"support_hypervisor":["qingtian"]}' -w %{http_code} -s`
    if [ "$code" == "200" ];then
        echo '{"support_hypervisor":["qingtian"]}' > ${meta_log}
        log_info " Success to set qingtian meta!"
    else
        log_error 7 " Failed to set metadata, please try again"
    fi
}

########################################################################
log_info " ------------------------------------------------"
log_info " Begin to check and correct grub and fstab file"

#1) check to see if script is run as root
PATH=/bin:/sbin:/usr/bin:/usr/sbin
if [ `id -u` -ne 0 ]; then
        log_info " ------------------------------------------------"
        log_info " This script must be run as root"
        log_info " ------------------------------------------------"
        exit 1
fi

#2) check /etc/fstab, and correct fstab file
sed -n 's|^/dev/\([sv]*d[a-z][0-9]*\).*|\1|p' </etc/fstab >/tmp/device_names
if [ -s /tmp/device_names ]; then
    log_info " Your fstab file contains device names. Mount the partitions using UUID's before changing an instance type to Full Offload instance."
    # change fstab and grub
    printf "\nEnter y to replace device names with UUID in /etc/fstab file to make it compatible for NVMe block device names.\nEnter n to keep the file as-is with no modification (y/n) "
    read RESPONSE;
    case "$RESPONSE" in
        [yY]|[yY][eE][sS])                                              # If answer is yes, change grub and fstab file to correct form.
                log_info " Begin to modify fstab"
                modify_fstab
                log_info ${MODIFIED_FILE_LIST}
                deleteBackupFile
                ;;
        [nN]|[nN][oO]|"")                                               # If answer is no
                log_info " Aborting: Not saving changes..."
                log_info " If you want to change instance type to Full Offload instance, please run this script again."
                ;;
        *)                                                              # If answer is anything else, exit and do not change grub and fstab file.
                log_info " Invalid Response"
                log_info " Exiting"
                log_info " If you want to change instance type to Full Offload instance, please run this script again."
                deleteBackupFile
                log_info "------------------------------------------------"
                exit 1
                ;;
    esac
else
    log_info " OK      fstab file looks fine and does not contain any device names."
    deleteBackupFile
fi

# 3) check grub, and correct grub file
if ! find_grub_file ; then
  log_info " Can not find grub file!"
else
    for file in ${GRUB_FILE_LIST[@]}
    do
        log_info " Check grub file: ${file}"
        sed -n 's|/dev/\([sv]*d[a-z][0-9]*\).*|\1|p' <${file} >/tmp/device_names
        if [ -s /tmp/device_names ]; then
              log_info " Your ${file} file contains device names. Mount the partitions using UUID's before changing an instance type to Full Offload instance."
              printf "\nEnter y to replace device names with UUID in ${file} file to make it compatible for NVMe block device names.\nEnter n to keep the file as-is with no modification (y/n) "
              read RESPONSE;
              case "$RESPONSE" in
                  [yY]|[yY][eE][sS])                                              # If answer is yes, change grub and fstab file to correct form.
                          log_info " Begin to modify ${file}"
                          #get device uuids
                          device_uuids=`blkid | sed s/[[:space:]]//g`
                          device_uuids=($device_uuids)
                          #modify grub
                          log_info " Modify grub file: ${file}"
                          backupFile ${file}
                          for item in ${device_uuids[@]}
                          do
                              device=`echo ${item} | awk -F ':' '{print $1}' | sed 's;\/;\\\/;g'`
                              uuid=`echo ${item} | awk -F 'UUID=' '{print $2}' | awk '{print $1}' | awk -F '"' '{print $2}'`
                              sed -i "s/${device}/UUID=${uuid} /g" ${file}
                          done
                          change_dev_device_to_uuid ${file}
                          log_info " Modify grub file success!"
                          log_info ${MODIFIED_FILE_LIST}
                          deleteBackupFile
                          ;;
                  [nN]|[nN][oO]|"")                                               # If answer is no
                          log_info " Aborting: Not saving changes..."
                          log_info " If you want to change instance type to Full Offload instance, please run this script again."
                          ;;
                  *)                                                              # If answer is anything else, exit and do not change grub and fstab file.
                          log_info " Invalid Response"
                          log_info " Exiting"
                          log_info " If you want to change instance type to Full Offload instance, please run this script again."
                          deleteBackupFile
                          log_info "------------------------------------------------"
                          exit 1
                          ;;
              esac
        else
              log_info " OK      ${file} file looks fine and does not contain any device names."
              deleteBackupFile
        fi
    done
fi

# 4) check virtio_scsi driver
modprobe virtio_scsi
grep -w virtio_scsi /proc/modules >/dev/null
if [ $? -eq 0 ]; then
    log_info " OK      modprobe virtio_scsi success."
else
    # modprobe virtio_scsi failed
    log_error 7 " ERROR  modprobe virtio_scsi failed, please make sure the virtio_scsi module is installed correctly."
    log_info " ------------------------------------------------"
    exit 1
fi

# 5) set metadata to instance
set_metadata

log_info " ------------------------------------------------"
