#!/bin/bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2025, 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.                                             #
#--------------------------------------------------------------------------- #

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

DEFAULT_TYPE="raw"

DOMAIN="$1"
SOURCE="$2"
TARGET="$3"
TARGET_INDEX="$4"
DRV_ACTION="$5"

get_disk_information "ATTACH='YES'"

function insert_sec() {
    name=$1
    s=$2
    sm=$3
    sml=$4

    if [ -n "${s}" ]; then
        XML+="<${name}_sec>$(xml_esc "${s}")</${name}_sec>"
    else
        s="0"
    fi

    if [ -n "${sm}" ]; then
        if [ "${sm}" -gt "${s}" ]; then
            XML+="<${name}_sec_max>$(xml_esc "${sm}")</${name}_sec_max>"

            if [ -n "${sml}" ]; then
                XML+="<${name}_sec_max_length>$(xml_esc "${sml}")"
                XML+="</${name}_sec_max_length>"
            fi
        fi
    fi
}

# defaults
CACHE=${CACHE:-${DEFAULT_ATTACH_CACHE}}
CACHE=${CACHE:-default}
DISCARD=${DISCARD:-${DEFAULT_ATTACH_DISCARD}}
DISK_IO=${DISK_IO:-${DEFAULT_ATTACH_IO}}
TOTAL_BYTES_SEC=${TOTAL_BYTES_SEC:-${DEFAULT_ATTACH_TOTAL_BYTES_SEC}}
TOTAL_BYTES_SEC_MAX_LENGTH=${TOTAL_BYTES_SEC_MAX_LENGTH:-${DEFAULT_ATTACH_TOTAL_BYTES_SEC_MAX_LENGTH}}
TOTAL_BYTES_SEC_MAX=${TOTAL_BYTES_SEC_MAX:-${DEFAULT_ATTACH_TOTAL_BYTES_SEC_MAX}}
READ_BYTES_SEC=${READ_BYTES_SEC:-${DEFAULT_ATTACH_READ_BYTES_SEC}}
READ_BYTES_SEC_MAX_LENGTH=${READ_BYTES_SEC_MAX_LENGTH:-${DEFAULT_ATTACH_READ_BYTES_SEC_MAX_LENGTH}}
READ_BYTES_SEC_MAX=${READ_BYTES_SEC_MAX:-${DEFAULT_ATTACH_READ_BYTES_SEC_MAX}}
WRITE_BYTES_SEC=${WRITE_BYTES_SEC:-${DEFAULT_ATTACH_WRITE_BYTES_SEC}}
WRITE_BYTES_SEC_MAX_LENGTH=${WRITE_BYTES_SEC_MAX_LENGTH:-${DEFAULT_ATTACH_WRITE_BYTES_SEC_MAX_LENGTH}}
WRITE_BYTES_SEC_MAX=${WRITE_BYTES_SEC_MAX:-${DEFAULT_ATTACH_WRITE_BYTES_SEC_MAX}}
TOTAL_IOPS_SEC=${TOTAL_IOPS_SEC:-${DEFAULT_ATTACH_TOTAL_IOPS_SEC}}
TOTAL_IOPS_SEC_MAX_LENGTH=${TOTAL_IOPS_SEC_MAX_LENGTH:-${DEFAULT_ATTACH_TOTAL_IOPS_SEC_MAX_LENGTH}}
TOTAL_IOPS_SEC_MAX=${TOTAL_IOPS_SEC_MAX:-${DEFAULT_ATTACH_TOTAL_IOPS_SEC_MAX}}
READ_IOPS_SEC=${READ_IOPS_SEC:-${DEFAULT_ATTACH_READ_IOPS_SEC}}
READ_IOPS_SEC_MAX_LENGTH=${READ_IOPS_SEC_MAX_LENGTH:-${DEFAULT_ATTACH_READ_IOPS_SEC_MAX_LENGTH}}
READ_IOPS_SEC_MAX=${READ_IOPS_SEC_MAX:-${DEFAULT_ATTACH_READ_IOPS_SEC_MAX}}
WRITE_IOPS_SEC=${WRITE_IOPS_SEC:-${DEFAULT_ATTACH_WRITE_IOPS_SEC}}
WRITE_IOPS_SEC_MAX_LENGTH=${WRITE_IOPS_SEC_MAX_LENGTH:-${DEFAULT_ATTACH_WRITE_IOPS_SEC_MAX_LENGTH}}
WRITE_IOPS_SEC_MAX=${WRITE_IOPS_SEC_MAX:-${DEFAULT_ATTACH_WRITE_IOPS_SEC_MAX}}
SIZE_IOPS_SEC=${SIZE_IOPS_SEC:-${DEFAULT_ATTACH_SIZE_IOPS_SEC}}
VIRTIO_BLK_QUEUES=${VIRTIO_BLK_QUEUES:-${DEFAULT_ATTACH_VIRTIO_BLK_QUEUES}}

if [ "${VIRTIO_BLK_QUEUES}" = "auto" ]; then
    VIRTIO_BLK_QUEUES="$VCPU"
fi

# disk XML
XML=''

XML+="<disk type='$(xml_esc "${TYPE_XML}")' device='$(xml_esc "${DEVICE}")'>"

XML+="<driver name='qemu' type='$(xml_esc "${DRIVER}")'"
[ -n "${CACHE}" ] && XML+=" cache='$(xml_esc "${CACHE}")'"
[ -n "${DISK_IO}" ] && XML+=" io='$(xml_esc "${DISK_IO}")'"
[ -n "${DISCARD}" ] && XML+=" discard='$(xml_esc "${DISCARD}")'"
[ -n "${IOTHREAD}" ] && XML+=" iothread='$(xml_esc "${IOTHREAD}")'"
[ -n "${VIRTIO_BLK_QUEUES}" ] && XML+=" queues='$(xml_esc "${VIRTIO_BLK_QUEUES}")'"
XML+="/>"

if [ "${TYPE_SOURCE}" == "file" ]; then
    f=$(echo ${SOURCE} | sed 's/[[:space:]]*$//')

    if [[ "${f}" =~ .*/disk\.[0-9]+$ && -L "${f}" ]]; then
        rl=$(readlink ${f})

        if [ "${rl:0:1}" != "/" ]; then
            rl="$(dirname ${f})/${rl}"
        fi

        if [ -e "${rl}" ]; then
            SOURCE="${rl}"
        fi
    fi
fi

XML+="<source ${TYPE_SOURCE}='$(xml_esc "${SOURCE}")' ${SOURCE_ARGS}>"
XML+="${SOURCE_HOST}"
XML+="</source>"

[ -n "${AUTH}" ] && XML+=" ${AUTH}"

XML+="<target dev='$(xml_esc "${TARGET}")'/>"
[ -n "${ORDER}" ] && XML+=" <boot order='$(xml_esc "${ORDER}")'/>"
[ "${READONLY}" = 'yes' ] && XML+="<readonly/>"
[ "${SHAREABLE}" = 'yes' ] && XML+="<shareable/>"
[ -n "${LUKS}" ] && XML+="${LUKS}"

if [ -n "${TOTAL_BYTES_SEC}${READ_BYTES_SEC}${WRITE_BYTES_SEC}" ] || \
   [ -n "${TOTAL_BYTES_SEC_MAX}${READ_BYTES_SEC_MAX}${WRITE_BYTES_SEC_MAX}" ] || \
   [ -n "${TOTAL_IOPS_SEC}${READ_IOPS_SEC}${WRITE_IOPS_SEC}" ] || \
   [ -n "${TOTAL_IOPS_SEC_MAX}${READ_IOPS_SEC_MAX}${WRITE_IOPS_SEC_MAX}" ];
then
    XML+="<iotune>"

    if [ -n "${TOTAL_BYTES_SEC}${TOTAL_BYTES_SEC_MAX}" ]; then
        insert_sec "total_bytes" "${TOTAL_BYTES_SEC}" "${TOTAL_BYTES_SEC_MAX}" \
            "${TOTAL_BYTES_SEC_MAX_LENGTH}"
    else
        insert_sec "read_bytes" "${READ_BYTES_SEC}" "${READ_BYTES_SEC_MAX}" \
            "${READ_BYTES_SEC_MAX_LENGTH}"

        insert_sec "write_bytes" "${WRITE_BYTES_SEC}" "${WRITE_BYTES_SEC_MAX}" \
            "${WRITE_BYTES_SEC_MAX_LENGTH}"
    fi

    if [ -n "${TOTAL_IOPS_SEC}${TOTAL_IOPS_SEC_MAX}" ]; then
        insert_sec "total_iops" "${TOTAL_IOPS_SEC}" "${TOTAL_IOPS_SEC_MAX}" \
            "${TOTAL_IOPS_SEC_MAX_LENGTH}"
    else
        insert_sec "read_iops" "${READ_IOPS_SEC}" "${READ_IOPS_SEC_MAX}" \
            "${READ_IOPS_SEC_MAX_LENGTH}"

        insert_sec "write_iops" "${WRITE_IOPS_SEC}" "${WRITE_IOPS_SEC_MAX}" \
            "${WRITE_IOPS_SEC_MAX_LENGTH}"
    fi

    if [ -n "${SIZE_IOPS_SEC}" ] && \
       [ -n "${TOTAL_IOPS_SEC}${READ_IOPS_SEC}${WRITE_IOPS_SEC}" ];
    then
        insert_sec "size_iops" "${SIZE_IOPS_SEC}" "" ""
    fi

    XML+="</iotune>"
fi

if [ -z "${DISK_TARGET##sd*}" ]; then
    CTRL_TARGET=$(( $(LC_CTYPE=C printf '%d' "'${DISK_TARGET##sd}") - 97 ))
    if [ ${CTRL_TARGET} -ge 0 ] && [ ${CTRL_TARGET} -lt 256 ]; then
        XML+="<address type='drive' controller='0' bus='0' target='${CTRL_TARGET}' unit='0'/>"
    fi
fi

XML+="</disk>"

# device attach
ATTACH_CMD=$(cat <<EOF
set -e -o pipefail
virsh --connect $LIBVIRT_URI attach-device $DOMAIN <(
cat <<EOT
${XML}
EOT
)
EOF
)

multiline_exec_and_log "${ATTACH_CMD}" \
    "Could not attach ${SOURCE} (${TARGET}) to ${DOMAIN}"
