#!/bin/bash

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

# mkimage size format host:remote_system_ds/disk.i vmid dsid
#   - size in MB of the image
#   - format for the image
#   - remote_system_ds is the path for the system datastore in the host
#   - vmid is the id of the VM
#   - dsid is the target datastore (0 is the system datastore)

SIZE=$1
FSTYPE=$2
DST=$3
VM_ID=$4
DS_ID=$5

if [ -z "${ONE_LOCATION}" ]; then
    TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
else
    TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
fi

DRIVER_PATH=$(dirname $0)

source $TMCOMMON
source ${DRIVER_PATH}/../../datastore/libfs.sh
source ${DRIVER_PATH}/../../etc/datastore/linstor_un/linstor_un.conf
source ${DRIVER_PATH}/../../datastore/linstor_un/linstor_utils.sh

#-------------------------------------------------------------------------------
# Set dst path and dir
#-------------------------------------------------------------------------------

DST_PATH=`arg_path $DST`
DST_HOST=`arg_host $DST`
DST_DIR=`dirname $DST_PATH`

DISK_ID=$(basename ${DST_PATH} | cut -d. -f2)
DST_RES="one-vm-${VM_ID}-disk-${DISK_ID}"
DST_DEV="/dev/drbd/by-res/${DST_RES}/0"

#-------------------------------------------------------------------------------
# Get Datastore information
#-------------------------------------------------------------------------------

XPATH="${DRIVER_PATH}/../../datastore/xpath.rb --stdin"

unset i j XPATH_ELEMENTS

while IFS= read -r -d '' element; do
        XPATH_ELEMENTS[i++]="$element"
done < <(onedatastore show -x $DS_ID | $XPATH \
                    /DATASTORE/TEMPLATE/LS_CONTROLLERS \
                    /DATASTORE/TEMPLATE/LS_CERTFILE \
                    /DATASTORE/TEMPLATE/LS_KEYFILE \
                    /DATASTORE/TEMPLATE/LS_CAFILE \
                    /DATASTORE/TEMPLATE/RESOURCE_GROUP \
                    /DATASTORE/TEMPLATE/NODE_LIST \
                    /DATASTORE/TEMPLATE/LAYER_LIST \
                    /DATASTORE/TEMPLATE/PROVIDERS \
                    /DATASTORE/TEMPLATE/REPLICAS_ON_SAME \
                    /DATASTORE/TEMPLATE/REPLICAS_ON_DIFFERENT \
                    /DATASTORE/TEMPLATE/AUTO_PLACE \
                    /DATASTORE/TEMPLATE/REPLICA_COUNT \
                    /DATASTORE/TEMPLATE/DO_NOT_PLACE_WITH \
                    /DATASTORE/TEMPLATE/DO_NOT_PLACE_WITH_REGEX \
                    /DATASTORE/TEMPLATE/STORAGE_POOL \
                    /DATASTORE/TEMPLATE/DISKLESS_POOL \
                    /DATASTORE/TEMPLATE/PREFER_NODE \
                    /DATASTORE/TEMPLATE/ENCRYPTION)

LS_CONTROLLERS="${XPATH_ELEMENTS[j++]}"
LS_CERTFILE="${XPATH_ELEMENTS[j++]}"
LS_KEYFILE="${XPATH_ELEMENTS[j++]}"
LS_CAFILE="${XPATH_ELEMENTS[j++]}"
RESOURCE_GROUP="${XPATH_ELEMENTS[j++]}"
NODE_LIST="${XPATH_ELEMENTS[j++]}"
LAYER_LIST="${XPATH_ELEMENTS[j++]}"
PROVIDERS="${XPATH_ELEMENTS[j++]}"
REPLICAS_ON_SAME="${XPATH_ELEMENTS[j++]}"
REPLICAS_ON_DIFFERENT="${XPATH_ELEMENTS[j++]}"
AUTO_PLACE="${XPATH_ELEMENTS[j++]}"
REPLICA_COUNT="${XPATH_ELEMENTS[j++]:-$AUTO_PLACE}"
DO_NOT_PLACE_WITH="${XPATH_ELEMENTS[j++]}"
DO_NOT_PLACE_WITH_REGEX="${XPATH_ELEMENTS[j++]}"
STORAGE_POOL="${XPATH_ELEMENTS[j++]}"
DISKLESS_POOL="${XPATH_ELEMENTS[j++]:-DfltDisklessStorPool}"
PREFER_NODE="${XPATH_ELEMENTS[j++]}"
ENCRYPTION="${XPATH_ELEMENTS[j++]}"

#-------------------------------------------------------------------------------
# Create new volume
#-------------------------------------------------------------------------------

if [ -z "$RESOURCE_GROUP" ]; then
    if [ -z "$NODE_LIST" ] && [ -z "$REPLICA_COUNT" ]; then
        error_message "Datastore template missing 'RESOURCE_GROUP', 'NODE_LIST' or 'REPLICA_COUNT' attribute."
        exit -1
    fi
    if [ -z "$STORAGE_POOL" ]; then
        error_message "Datastore template missing 'STORAGE_POOL' attribute."
        exit -1
    fi
fi

linstor_load_keys

# Load cleanup trap
trap linstor_cleanup_trap EXIT

# Deploy new volume
linstor_exec_and_log \
    "resource-definition create $DST_RES $RD_CREATE_ARGS" 
LINSTOR_CLEANUP_RD+=" $DST_RES"
linstor_exec_and_log \
    "volume-definition create $DST_RES ${SIZE}M $VOL_CREATE_ARGS"

if [ "${PREFER_NODE,,}" = "yes" ]; then
    STORAGE_POOL=${STORAGE_POOL:-$($LINSTOR -m --output-version v0 resource-group list -r "$RESOURCE_GROUP" \
        | $JQ -r '.[][].select_filter.storage_pool_list // [] | join(" ")')}
    if [ -z "$STORAGE_POOL" ]; then
        error_message "Resource group missing 'StoragePool' attribute."
        exit -1
    fi
    NODE_HAS_STORAGE_POOL=$($LINSTOR -m --output-version v0 storage-pool list --node "$DST_HOST" --storage-pool $STORAGE_POOL \
        | $JQ -r ".[].stor_pools[] | .free_space.free_capacity / 1024 > ${SIZE}" )
    if [ "$NODE_HAS_STORAGE_POOL" = "true" ]; then
        linstor_exec_and_log \
            "resource create $DST_HOST $DST_RES $RES_CREATE_SHORT_ARGS --storage-pool $STORAGE_POOL"
    fi
fi

if [ -n "$RESOURCE_GROUP" ]; then
    linstor_exec_and_log \
        "resource-definition auto-place $DST_RES $RD_AUTO_PLACE_ARGS"
else
    linstor_exec_and_log \
        "resource create $NODE_LIST $DST_RES $RES_CREATE_ARGS"
fi

# Set properties
linstor_exec_and_log \
    "resource-definition set-property $DST_RES Aux/one/VM_ID $VM_ID"
linstor_exec_and_log \
    "resource-definition set-property $DST_RES Aux/one/DS_ID $DS_ID"
linstor_exec_and_log \
    "resource-definition set-property $DST_RES Aux/one/DISK_ID $DISK_ID"

# Attach diskless resource on destination host
linstor_attach_diskless "$DST_HOST" "$DST_RES" "$DISKLESS_POOL"

# Link device on destination host
LINK_CMD=$(cat <<EOF
    set -e -o pipefail
    mkdir -p $DST_DIR
    rm -f $DST_PATH
    ln -s $DST_DEV $DST_PATH
EOF
)

ssh_exec_and_log "$DST_HOST" "$LINK_CMD" \
    "Error linking $DST_DEV to $DST_PATH on $DST_HOST"

# Make filesystem on device
if [ "$FSTYPE" != "raw" ]; then
    MKFS_CMD=`mkfs_command $DST_PATH $FSTYPE $SIZE`
    
    ssh_exec_and_log "$DST_HOST" "$MKFS_CMD" \
        "Unable to create filesystem $FSTYPE in $DST_HOST:$DST_PATH"
fi

LINSTOR_CLEANUP_RD=
exit 0
