#!/bin/bash
PSTORAGE_ISCSI_LIB=/usr/libexec/vstorage-iscsi/vstorage_functions
ROOT=""
IQN=""
UUID=""
LUN_ID=""
CMD=""
DESCRIPTION=""
SHOW_PARENT_UUID="yes"
SHOW_DESCRIPTION=""
ARGS="${@}"

function print_usage {
	exec 1>&2
	case "${CMD}" in
		"snapshot-create")
			echo "Create a snapshot for specified LUN."
			echo "Usage:"
			echo "$CTL_TOOL ${CMD} -t,--target IQN"
			echo "                      -l,--lun LUN_ID [-u,--uuid UUID] [-d,--description DESC]"
			echo "Options:"
			echo "  -t,--target IQN         target's IQN."
			echo "  -l,--lun LUN_ID         LUN's id."
			echo "  -u,--uuid UUID          Specify a uuid for a new snapshot (optional). If option"
			echo "                          is not given, uuid is generated automatically."
			echo "                          To generate uuid manually, one can use the uuidgen(1) utility."
			echo "  --d,--description DESC  User specified description for new snapshot (optional)."
			;;
		"snapshot-list")
			echo "List LUN's snapshots."
			echo "Usage:"
			echo "$CTL_TOOL ${CMD} -t,--target IQN -l,--lun LUN_ID"
			echo "                      [-D,--show-desc]"
			echo "Options:"
			echo "  -t,--target IQN         target's IQN."
			echo "  -l,--lun LUN_ID         LUN's id."
			echo "  -D,--show-desc          Show description for listed snapshots if available."
			;;
		"snapshot-info")
			echo "Show information about specified snapshot."
			echo "Usage:"
			echo "$CTL_TOOL ${CMD} -u,--uuid UUID"
			echo "Options:"
			echo "  -u,--uuid UUID          Specify a snapshot UUID to show information."
			;;
		"snapshot-delete")
			echo "Delete the specifed LUN's snapshot."
			echo "   This operation can only be performed if the specified"
			echo "   snapshot is not active. In case snapshot doesn’t have"
			echo "   any children, it will simply be removed. In case snapshot"
			echo "   has a single child, it will be merged to that child."
			echo "   Deleting a snapshot that has multiple children is currently not supported."
			echo "Usage:"
			echo "$CTL_TOOL ${CMD} -u,--uuid UUID"
			echo "Options:"
			echo "  -u,--uuid UUID          Specify a snapshot UUID to be deleted."
			;;
		"snapshot-switch")
			echo "Switch to the specified LUN's snapshot."
			echo "   This operation can only be performed while LUN is not"
			echo "   online. The current top delta image will be removed."
			echo "Usage:"
			echo "$CTL_TOOL ${CMD} -u,--uuid UUID"
			echo "Options:"
			echo "  -u,--uuid UUID          Specify a snapshot UUID to switch to."
			;;

                *)
			echo "Unknown command '${CMD}'." 1>&2
	esac
	echo " "
	exit 1
}

function check_target_lun()
{
	if [ -z "$IQN" ] ; then
		echo "Target (-t,--target) must be specified." 1>&2
		print_usage $CMD
	fi

	if [ -z "$LUN_ID" ] ; then
		echo "LUN id (-l,--lun) must be specified." 1>&2
		print_usage $CMD
	fi
}

function parse_list_args {
        while [ "${#}" -gt 0 ]; do
                case "${1}" in
                        "-h"|"--help")
                                print_usage $CMD
                                ;;
                        "-r"|"--root")
                                [ -z "${2}" ] && print_usage $CMD
                                ROOT="${2}"
                                shift
                                shift
                                ;;
                        "-t"|"--target")
                                [ -z "${2}" ] && print_usage $CMD
                                IQN="${2}"
                                shift
                                shift
                                ;;
                        "-D"|"--show-desc")
                                SHOW_DESCRIPTION="yes"
                                shift
                                ;;
                        "-l"|"--lun")
                                [ -z "${2}" ] && print_usage $CMD
                                LUN_ID="${2}"
                                shift
                                shift
                                ;;
                        *)
                                echo "Unknown option '${1}'." 1>&2
                                print_usage $CMD
                                ;;
                esac
        done
}

function parse_create_args {
        while [ "${#}" -gt 0 ]; do
                case "${1}" in
                        "-h"|"--help")
                                print_usage $CMD
                                ;;
                        "-r"|"--root")
                                [ -z "${2}" ] && print_usage $CMD
                                ROOT="${2}"
                                shift
                                shift
                                ;;
                        "-t"|"--target")
                                [ -z "${2}" ] && print_usage $CMD
                                IQN="${2}"
                                shift
                                shift
                                ;;
                        "-d"|"--description")
                                [ -z "${2}" ] && print_usage $CMD
                                DESCRIPTION="${2}"
                                shift
                                shift
                                ;;
                        "-l"|"--lun")
                                [ -z "${2}" ] && print_usage $CMD
                                LUN_ID="${2}"
                                shift
                                shift
                                ;;
                        "-u"|"--uuid")
                                [ -z "${2}" ] && print_usage $CMD
                                UUID="${2}"
                                shift
                                shift
                                ;;
                        *)
                                echo "Unknown option '${1}'." 1>&2
                                print_usage $CMD
                                ;;
                esac
        done
}

function parse_uuid_args {
        while [ "${#}" -gt 0 ]; do
                case "${1}" in
                        "-h"|"--help")
                                print_usage $CMD
                                ;;
                        "-r"|"--root")
                                [ -z "${2}" ] && print_usage $CMD
                                ROOT="${2}"
                                shift
                                shift
                                ;;
                        "-u"|"--uuid")
                                [ -z "${2}" ] && print_usage $CMD
                                UUID="${2}"
                                shift
                                shift
                                ;;
                        *)
                                echo "Unknown option '${1}'." 1>&2
                                print_usage $CMD
                                ;;
                esac
        done
}

function parse_args {
	if [ ${#} -eq 0 ]; then
		echo "Command not specified" 1>&2
		exit 1
	fi

	CMD="${1}"; shift
        case "${CMD}" in
		snapshot-list)
			parse_list_args ${@}
			check_target_lun
			;;
                snapshot-create)
			parse_create_args ${@}
			check_target_lun
			;;
		snapshot-delete|snapshot-switch|snapshot-info)
			parse_uuid_args ${@}
			if [ -z "$UUID" ] ; then
				echo "Snapshot's UUID (-u,--uuid) must be specified." 1>&2
				print_usage $CMD
			fi
			;;
		*)
			print_usage $CMD
			;;
	esac
}

function do_take_snapshot {
        local target="$1"
        local lun_id="$2"
        local uuid="$3"

	pcs_iscsi_check_target $target

        if [ ! -d "$ISCSI_ROOT/$target/lun${lun_id}" ] ; then
                echo "LUN $lun_id does not exist." 1>&2
                return 1
        fi

	[ -z "$uuid" ] && uuid=`/usr/bin/uuidgen 2>/dev/null`
	if [ -z "$uuid" ] ; then
		echo "uuidgen failed" 1>&2
		return 2
	fi

	pcs_iscsi_save_snapshot_info "$target" "$lun_id" "$uuid" "${DESCRIPTION}"
	[ $? -ne 0 ] && return 3

        $PLOOP snapshot -u "{$uuid}" "$ISCSI_ROOT/$target/lun${lun_id}/DiskDescriptor.xml" >/dev/null
        rc=$?
	if [ $rc -ne 0 ] ; then
		echo "Can't create snapshot for target $target LUN $lun_id" 1>&2
		rm -f "$ISCSI_ROOT/snapshots/$uuid"
	fi
	echo "Snapshot $uuid successfully created."
        return $rc
}

function check_ploop_descriptor {
	local target="$1"
	local lun="$2"
        if [ ! -d "$ISCSI_ROOT/$target/${lun}" ] ; then
		local lun_id=`expr "$lun" : "^lun\([0-9]*\)" `
                echo "LUN $lun_id does not exist." 1>&2
                return 1
        fi

	if [ ! -f "$ISCSI_ROOT/$target/${lun}/DiskDescriptor.xml" ]; then
		echo "ploop descriptor not found at $ISCSI_ROOT/$target/${lun}/DiskDescriptor.xml" 1>&2
		return 1
	fi
	return 0
}

function do_list_snapshots {
	local target="$1"
	local lun_id="$2"
	local lun="lun$lun_id"
	pcs_iscsi_check_target $target
	check_ploop_descriptor $target $lun
	[ $? -ne 0 ] && return 1
	hdr="CREATED             C UUID                                "
	if [ -n "$SHOW_PARENT_UUID" ]; then
		hdr="$hdr PARENT_UUID                         "
	fi
	if [ -n "$SHOW_DESCRIPTION" ] ; then
		hdr="$hdr DESCRIPTION"
	fi
	echo "$hdr"
	$PLOOP  snapshot-list -s -H -o UUID,PARENT_UUID,CURRENT "$ISCSI_ROOT/$target/$lun/DiskDescriptor.xml" \
		| while read UUID PARENT_UUID CURRENT; do
		        [ -z "$CURRENT" ] && CURRENT=" "
		        UUID=`expr "$UUID" : "^\{\(.*\)\}$"`
			PARENT_UUID=`expr "$PARENT_UUID" : "^\{\(.*\)\}$"`
			[ ! -f "$ISCSI_ROOT/snapshots/$UUID" ] && continue
			source "$ISCSI_ROOT/snapshots/$UUID"
			
			echo -n "$SNAP_CREATE_DATE $CURRENT $UUID"
			[ -n "$SHOW_PARENT_UUID" ] && echo -n " $PARENT_UUID"
			if [ -n "$SHOW_DESCRIPTION" ]; then
				[ -z "$SNAP_DESCRIPTION" ] && SNAP_DESCRIPTION="None"
				echo -n " $SNAP_DESCRIPTION"
			fi
			echo ""
	done
	return 0
}

function do_delete_snapshot {
	local target="$1"
	local lun="lun$2"
	local uuid="$3"
	pcs_iscsi_check_target $target
	check_ploop_descriptor $target $lun
	[ $? -ne 0 ] && return 1

        $PLOOP snapshot-delete -u "{$uuid}" "$ISCSI_ROOT/$target/${lun}/DiskDescriptor.xml" >/dev/null
        rc=$?
	if [ $rc -eq 0 ] ; then
		rm -f "$ISCSI_ROOT/snapshots/$uuid"
	else
		echo "Failed to delete snapshot $uuid." 1>&2
	fi
	return $rc
}

function get_snapshot_parent {
	local target="$1"
	local lun="$2"
	local uuid="$3"
	
	parent=`$PLOOP snapshot-list -H -o UUID,PARENT_UUID "$ISCSI_ROOT/$target/${lun}/DiskDescriptor.xml" 2>/dev/null | grep "$uuid" | cut -d ' ' -f 2`
	if [ -z "$parent" ] ; then
		echo "Unknown"
	else
		expr "$parent" : "^\{\(.*\)\}$"
	fi
}

function do_snapshot_info {
	local target="$1"
	local lun_id="$2"
	local lun="lun$lun_id"
	local uuid="$3"
	echo "Target: $target"
	echo "LUN: $lun_id"
	echo -n "Created: "
	if [ -n "$SNAP_CREATE_DATE" ]; then
		echo "$SNAP_CREATE_DATE"
	else
		echo "Unknown"
	fi
	echo "Parent: $(get_snapshot_parent $target $lun $uuid)"
	echo -n "Description: "
	if [ -n "$SNAP_DESCRIPTION" ] ; then
		echo "$SNAP_DESCRIPTION"
	else
		echo "None"
	fi
}

function uuid_to_target {
	if [ ! -f "$ISCSI_ROOT/snapshots/$UUID" ] ; then
		echo "Can't find snapshot $UUID in $ISCSI_ROOT/snapshots" 1>&2
		exit 1
	fi

	source "$ISCSI_ROOT/snapshots/$UUID" 2>/dev/null
	if [ $? -ne 0 ]; then
		echo "Unable load configuration from $ISCSI_ROOT/snapshots/$UUID" 1>&2
		exit 2
	fi

	if [ -z "$SNAP_IQN" ]; then
		echo "Unable find target for $UUID: SNAP_IQN does not specified in $ISCSI_ROOT/snapshots/$UUID" 1>&2
		exit 3
	fi

	if [ -z "$SNAP_LUN" ]; then
		echo "Unable find target for $UUID: SNAP_LUN does not specified in $ISCSI_ROOT/snapshots/$UUID" 1>&2
		exit 4
	fi
}

function do_switch_to_snapshot {
	local target="$1"
	local lun="lun$2"
	local uuid="$3"

	pcs_iscsi_check_target $target
	check_ploop_descriptor $target $lun
	[ $? -ne 0 ] && return 1

        $PLOOP snapshot-switch -u "{$uuid}" "$ISCSI_ROOT/$target/${lun}/DiskDescriptor.xml" >/dev/null
        rc=$?
	[ $rc -ne 0 ] && echo "Unable switch snapshot to $uuid" 1>&2
	return $rc
}

if [ ! -x $PSTORAGE_ISCSI_LIB ] ; then
	echo "Unable find executable $PSTORAGE_ISCSI_LIB" 1>&2
	exit 1
fi

source $PSTORAGE_ISCSI_LIB
[ -f $ISCSI_ETC/config ] && source $ISCSI_ETC/config

parse_args $ARGS

ISCSI_ROOT=`pcs_iscsi_get_root "${ROOT}"`
pcs_iscsi_check_root
RET=-1
case "${CMD}" in
                "snapshot-create")
			[ ! -d ${ISCSI_ROOT}/snapshots ] && mkdir -p ${ISCSI_ROOT}/snapshots
			pcs_iscsi_lock_exec do_take_snapshot $IQN $LUN_ID $UUID
			RET=$?
			;;
		"snapshot-list")
			pcs_iscsi_lock_exec do_list_snapshots $IQN $LUN_ID
			RET=$?
			;;
		"snapshot-delete")
			uuid_to_target
			pcs_iscsi_lock_exec do_delete_snapshot $SNAP_IQN $SNAP_LUN $UUID
			RET=$?
			;;
		"snapshot-switch")
			uuid_to_target
			pcs_iscsi_lock_exec do_switch_to_snapshot $SNAP_IQN $SNAP_LUN $UUID
			RET=$?
			;;
		"snapshot-info")
			uuid_to_target
			pcs_iscsi_lock_exec do_snapshot_info $SNAP_IQN "$SNAP_LUN"
			
esac
exit $RET

