#!/bin/bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2024, OpenNebula Project, OpenNebula Systems                #
#                                                                            #
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
# not use this file except in compliance with the License. You may obtain    #
# a copy of the License at                                                   #
#                                                                            #
# http://www.apache.org/licenses/LICENSE-2.0                                 #
#                                                                            #
# Unless required by applicable law or agreed to in writing, software        #
# distributed under the License is distributed on an "AS IS" BASIS,          #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
# See the License for the specific language governing permissions and        #
# limitations under the License.                                             #
#--------------------------------------------------------------------------- #

# ------------------------------------------------------------------------------
# HELPERS
# ------------------------------------------------------------------------------
# Get VGPU devices UUID
function get_uuids() {
    uuids="$(base64 --decode "$1" | xmllint --xpath '/VM/TEMPLATE/VGPU/UUID/text()' - --format 2>/dev/null)"
    echo "$uuids" | sed -e 's/<!\[CDATA\[//g; s/\]\]>/\n/g'
}

# Get value from XML and remove CDATA part
function get_xpath_val() {
    echo "$1" | xmllint --format --xpath "$2/text()" - | sed -e 's/<!\[CDATA\[//g; s/\]\]>//g'
}

# Get mdev path used to (de)activate mediated device
function get_mdevs_path() {
    HOST=$3
    vgpu=$(base64 --decode "$2" | xmllint --format --xpath "/VM/TEMPLATE/VGPU[UUID='$1']" - 2>/dev/null)

    # Get specific information about the VGPU
    vfs=$(get_xpath_val "$vgpu" "/VGPU/VFS")
    profile=$(get_xpath_val "$vgpu" "/VGPU/PROFILE")

    # Generate mdev path
    path="/sys/class/mdev_bus/*/mdev_supported_types/$profile/"
    file="available_instances"

    for_body="avail=\$(cat \$aifile); [[ \$avail -gt 0 ]] && for i in \$(seq 1 \$avail); do echo \$(dirname \$aifile); done;"
    command="for aifile in \$(ls $path$file); do $for_body done | head -n$vfs"

    mdevs=$($SSH $HOST $command)

    echo "$mdevs"
}

# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
ACTION=${1,,}
# create -> vm.xml path host
# delete -> vm.xml path host
VM="$2"
HOST="$3"

XPATH="$(dirname $0)/../../datastore/xpath.rb --stdin"

source "$(dirname $0)/../../etc/vmm/kvm/kvmrc"
source "$(dirname $0)/../../scripts_common.sh"

case "$ACTION" in
    "create")
        uuids="$(get_uuids "$VM")"

        if [ -n "$uuids" ]; then
            for uuid in $uuids; do
                MDEVS=($(get_mdevs_path $uuid $VM $HOST))
                IFS=',' read -ra UUIDS <<< "$uuid"

                if [ "x${#MDEVS[@]}" = "x0" ] || \
                   [ "x${#UUIDS[@]}" = "x0" ] || \
                   [ "x${#MDEVS[@]}" != "x${#UUIDS[@]}" ]
                then
                    error_message "VGPU not attached, can't find free virtual function on $HOST"
                    exit 1
                fi

                for index in "${!UUIDS[@]}"; do
                    mdev="${MDEVS[$index]}"
                    profile="$(basename $mdev)"

                    if ! $SSH $HOST "echo ${UUIDS[$index]} | $SUDO tee --append $mdev/create > /dev/null"
                    then
                        error_message "VGPU with PROFILE: $profile not attached"
                        exit 1
                    else
                        log "VGPU with PROFILE: $profile successfully attached"
                    fi

                done
            done
        fi
    ;;
    "delete")
        uuids="$(get_uuids "$VM")"
        if [ -n "$uuids" ]; then
            for uuid in $uuids; do
                IFS=',' read -ra UUIDS <<< "$uuid"
                for index in "${!UUIDS[@]}"; do
                    mdev="/sys/class/mdev_bus/*/mdev_supported_types/*/devices/${UUIDS[$index]}/remove"

                    vgpu=$(base64 --decode "$2" | xmllint --format --xpath "/VM/TEMPLATE/VGPU[UUID='${UUIDS[$index]}']" - 2>/dev/null)

                    # Get specific information about the VGPU
                    profile=$(get_xpath_val "$vgpu" "/VGPU/PROFILE")

                    if ! $SSH $HOST "echo 1 | $SUDO tee --append $mdev > /dev/null"
                    then
                        error_message "VGPU with PROFILE: $profile not detached"
                        # Not exit with error, just log the error

                        # exit -1
                    else
                        log "VGPU with PROFILE: $profile successfully detached"
                    fi
                done
            done
        fi
    ;;
    *)
        error_message "Unsupported action '$ACTION'"
        exit 1
esac

