#!/bin/bash
# solutions found until now
# for VMware we already have health daemon which detects this
# for Hyper-V use hyperv_pool_read (hyperv rpm must be installed) and check for PhysicalHostNameFullyQualified key
# 	this key should change in case of live migration
#
# SADLY - not working ...
# for kvm...
# after dozens of searches, reading documentations, this is what I found
# qemu-guest-agent rpm needs to be installed and customer needs to enable qemu-guest-agent from VM settings in PROXMOX, oVirt, Nutanix (to be checked if exist there)
# AND THE COMMUNICATION CHANNEL MUST BE SET to virtio
# this agent will the create an virtio device which is /dev/virtio-ports/org.qemu.guest_agent.0
# in case of live migration this device is closed on the source and may be opened on destination (source: https://www.linux-kvm.org/page/Virtio-serial_API)
# so we might use this in our advantage to detect the live migration
# Unfortunately this is not working..

# special handle for GCP -> use google-guest-agent

# for Nutanix check NGT (Nutanix Guest Tools)

VENDOR_FILE="/sys/class/dmi/id/sys_vendor"
kvp_read_exe="/opt/vmutil/hyperv_pool_read"
PROG_NAME="`basename $0`"
HYPERVISOR=`/opt/vmutil/detect_hypervisor.sh`
PRODUCT=`/opt/vmutil/detect_product.sh`

check_package_and_service() {
	RPM_PACKAGE_NAME=$1
    GUEST_AGENT_NAME=$2

	# check if the neccessary RPM package is installed
	rpm -qi ${RPM_PACKAGE_NAME} 1>/dev/null 2>&1
    
    [ $? -ne 0 ] && {
        echo "${RPM_PACKAGE_NAME} RPM package not installed... Nothing I can do from here"
        echo "Exiting"
        exit 1
    }

    # RPM is installed, check the needed daemon state
    systemctl is-active --quiet ${GUEST_AGENT_NAME}
    [ $? -ne 0 ] && {
        echo "${GUEST_AGENT_NAME} is not running... Trying to start it"
        systemctl start ${GUEST_AGENT_NAME} 
        # check again
        systemctl is-active --quiet ${GUEST_AGENT_NAME}
        [ $? -ne 0 ] && {
            echo "Couldn't start ${GUEST_AGENT_NAME}... Exiting!"
            exit 2
        }
    }

	# Daemon is started -> also make sure it's enabled
    systemctl enable ${GUEST_AGENT_NAME}
}

# Report vMotion specific for each product
prod_specific_report() {
    local message="(vMotion detected) - Physical Host Node name changed from $1 to $2!"
    
    case ${PRODUCT} in
        "OS4K")
            # do SNMP Trap
            /bin/logger -p daemon.err -t SnmpTrap "${PROG_NAME}: hostVMMigratedNotice; ${message}"

            # do HISTA Message
            local hostname=`hostname`

            /opt/webservice/scripts/is_host_node
            
            local is_host=$?
            local identifier=""

            if [ ${is_host} -eq 1 ]; then
                identifier="Host: "
            else
                local ltu=`/opt/soco/native/os/linux/get_LTU.sh`
                local slot=`/opt/soco/native/os/linux/get_Slot.sh`
                identifier="LTU ${ltu}: Slot ${slot}: "
            fi

            message="${identifier} ${hostname} ${message}"
            local hista_params="--alarm 0 --event 0x2b --subevent 0x37 '${message}'"
            local output=""
            if [ ${is_host} -eq 1 ]; then
                output=`/opt/dscxl/hcm-test/histamessage.py ${hista_params}`
            else
                output=`/opt/inventory/inventory-client.sh notification HISTA_MESSAGE ${hista_params}`
            fi
            
            if [ "${output}" != "HISTA message successfully sent." ]; then
                /bin/logger -p daemon.err -t ${PROG_NAME} "Failed to send Hista message for vMotion! Reason: ${output}"
            fi
            ;;
        *)
            echo "Unkown product ${PRODUCT}"
            ;;
    esac
}

# vmware already handled by healthd
# take from healthd or reimplement?
[ "x${HYPERVISOR}" = "xVMware" ] && {
    echo "TODO: Not Yet Implemented"
    exit 0
}

# Hyper-V
[ "x${HYPERVISOR}" = "xHyper-V" ] && {
	HYPERV_PACKAGE_NAME="hyper-v"
	HYPERV_GUEST_AGENT_NAME="hv_kvp_daemon.service"

	echo "Running on ${HYPERVISOR} hypervisor"

	check_package_and_service ${HYPERV_PACKAGE_NAME} ${HYPERV_GUEST_AGENT_NAME}

	# If we reach here the daemon is started
	ORIG_PHNFQ=`${kvp_read_exe} 3 | grep PhysicalHostNameFullyQualified`
	[ $? -ne 0 ] && {
		echo "Something went wrong when trying to retrieve PhysicalHostNameFullyQualified value... Exiting"
		exit 3
	}

	CURRENT_PHNFQ=""

	while true
    do
        CURRENT_PHNFQ=`${kvp_read_exe} 3 | grep PhysicalHostNameFullyQualified`
        [ "x${ORIG_PHNFQ}" != "x${CURRENT_PHNFQ}" ] && {
            # complain about it
            /usr/bin/logger -p user.alert -t $PROG_NAME "PhysicalHostNameFullyQualified has changed from ${ORIG_PHNFQ} to ${CURRENT_PHNFQ}! It's possible that we have been migrated!"
            # Request: allow product specific report logic for vMotion
            prod_specific_report ${ORIG_PHNFQ} ${CURRENT_PHNFQ}
            ORIG_PHNFQ=${CURRENT_PHNFQ}
        }

        sleep 5 # better 5 sec
    done

}

# KVM
[ "x${HYPERVISOR}" = "xQEMU" -o "x${HYPERVISOR}" = "xPROXMOX" -o "x${HYPERVISOR}" = "xoVirt"] && {
	KVM_PACKAGE_NAME="qemu-guest-agent"
	KVM_GUEST_AGENT_NAME="qemu-guest-agent"

	echo "Running on ${HYPERVISOR} hypervisor"

	check_package_and_service ${KVM_PACKAGE_NAME} ${KVM_GUEST_AGENT_NAME}
	
	# This approach is not working - Radu 23.09.2024
	#qemu_ga_chardev="/dev/virtio-ports/org.qemu.guest_agent.0"
	#while true
        #do
	#	[ -e "$qemu_ga_chardev" ] || {
	#		/usr/bin/logger -p user.alert -t $PROG_NAME "$qemu_ga_chardev device doesn't exist! It's possible that we have been migrated!"
	#	}
	#	sleep 30 # might be better to check this on 30 secs (or maybe less?)
	#done
	echo "Here live migration can't be detected!"
	echo "We can only rely on reports from cpu_info_timer -> Check /var/log/vmutil"
	exit 0
}

# GCP
[ "x${HYPERVISOR}" = "xGoogle Cloud" ] && {
	GOOGLE_PACKAGE_NAME="google-guest-agent"
	GOOGLE_GUEST_AGENT_NAME="google-guest-agent"

	echo "Running on ${HYPERVISOR} hypervisor"

	check_package_and_service ${GOOGLE_PACKAGE_NAME} ${GOOGLE_GUEST_AGENT_NAME}

	# If we reach here the daemon is started
	ORIG_PHYSICAL_HOST=`curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/physical_host" -H "Metadata-Flavor: Google"`

	[ "x${ORIG_PHYSICAL_HOST}" = "x" ] && {
		echo "Couldn't retrieve Physical Host metadata"
		echo "Exiting..."
		exit 3
	}

    # if we are here we have the physical host name
    # just sleep 60s and check if it was changed
    while true
    do
        CURRENT_PHYSICAL_HOST=`curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/physical_host" -H "Metadata-Flavor: Google"`
        [ "x${ORIG_PHYSICAL_HOST}" != "x${CURRENT_PHYSICAL_HOST}" ] && {
            # complain about it
            /usr/bin/logger -p user.alert -t $PROG_NAME "Physical Host has changed from ${ORIG_PHYSICAL_HOST} to ${CURRENT_PHYSICAL_HOST}! It's possible that we have been migrated!"
            prod_specific_report ${ORIG_PHYSICAL_HOST} ${CURRENT_PHYSICAL_HOST}
            ORIG_PHYSICAL_HOST=${CURRENT_PHYSICAL_HOST}
        }

        sleep 5 # better 5 sec
    done
}

[ "x${HYPERVISOR}" = "xNutanix" ] && {
    echo "Running on ${HYPERVISOR} hypervisor"
    echo "TODO: Not Yet Implemented"
}

echo "Detected unknown hypervisor: ${HYPERVISOR}!"
echo "Exiting..."
exit 0 # Exit with 0 so that service is not restarted everytime in case of unknown Hypervisor
