#!/bin/bash

############## Clone VirtualBox Machine ##############
# Written By: Samy Antoun                            #
#                                                    #
# Usage:                                             #
# ./clonevm.sh "Source Machine" "Clone Machine"      #
#                                                    #
# Limitations:                                       #
#   1. Clone only VM that has ONE Hard Drive (hda)   #
#   2. Clone only VM that has NO Snapshots           #
#   3. Clone only VM that is Powered Off             #
#                                                    #
# ToDo:                                              #
#   1. Check if the Hard Disk Partition has          #
#      sufficiant space for the cloned HD            #
######################################################

################### Functions ########################
function ChkUtility {
    res=`which $1 | grep "no $1"`
    if [ "$res" != "" ]; then
        echo "\"$1\" is missing";
        exit 2;
    fi
}

function GetValue {
    Line=`VBoxManage -nologo showvminfo "$1" -machinereadable | grep "^$2="`;
    Raw=`echo $Line | cut -d= -f2`;
    Fixed=`echo $Raw | sed 's/"//g'`;
    echo $Fixed;
}

function CheckUUID {
    CheckID=`echo "$1" | sed -e "s/\w\{8\}-\w\{4\}-\w\{4\}-\w\{4\}-\w\{12\}/ok/"`;
    if [ "$CheckID" != "ok" ]; then
        echo "Source Disk \"$1\" UUID Not Valid";
        exit 2;
    fi
}

################## Sanity Check ######################
# Make Sure that we have the required software
ChkUtility "grep";
ChkUtility "cut";
ChkUtility "sed";
ChkUtility "uuidgen";
ChkUtility "VBoxManage";

# Command line Parameters must be 2
if [ $# != 2 ]; then
    echo "Source VM Name Or Clone VM Name is Missing";
    exit 2;
fi

# Get Command line Parameters
SrcVM=$1;
CloneVM=$2;

# Set Clone Machine Directory
MachinesDirLine=`VBoxManage -nologo list systemproperties | grep "Default machine folder:"`;
MachinesDirRaw=`echo $MachinesDirLine | cut -d: -f2`;
MachinesDir=`echo $MachinesDirRaw | sed -e "s/^ *//g"`;
CloneMachineDir=$MachinesDir/$CloneVM;

# Make Sure that the Source VM is Registered
res=`VBoxManage -nologo showvminfo "$SrcVM" | grep "[!]"`
if [ "$res" != "" ]; then
    echo "Source VM \"$SrcVM\" Not Registered";
    exit 2;
fi

# Make Sure that the Clone VM NOT Registered
res=`VBoxManage -nologo showvminfo "$CloneVM" | grep "[!]"`
if [ "$res" = "" ]; then
    echo "Clone VM \"$CloneVM\" Already Registered";
    exit 2;
fi

# Make Sure that the Clone VM Directory Doesn't Exsits
if [ -d "$CloneMachineDir" ]; then
    echo "The Directory \"$CloneMachineDir\" Already Exists";
    exit 2;
fi

# Make Sure that the Source Disk UUID is Valid
SrcDiskID=`GetValue "$SrcVM" "HdaImageUUID"`;
CheckDiskID=`CheckUUID "$SrcDiskID"`;

# Make Sure that the Source Machine UUID is Valid
SrcVMid=`GetValue "$SrcVM" "UUID"`;
CheckDiskID=`CheckUUID "$SrcVMid"`;

# Make Sure that the Source Machine Config File Exists
SrcVMcfg=`GetValue "$SrcVM" "CfgFile"`;
if [ ! -f "$SrcVMcfg" ]; then
    echo "Source Config File \"$SrcVMcfg\" Doesn't Exist";
    exit 2;
fi

# Make Sure that the Source Machine Dosen't have a Snapshot
res=`GetValue "$SrcVM" "SnapshotName"`;
if [ "$res" != "" ]; then
    echo "Source Machine has a Snapshot";
    exit 2;
fi

# Make Sure that the Source Machine NOT Running
res=`GetValue "$SrcVM" "VMState"`;
if [ "$res" != "poweroff" ]; then
    echo "Source Machine is NOT Powered Off";
    exit 2;
fi

# Make Sure that the Source Machine has Only ONE Hard Disk (hda)
res=`VBoxManage list hdds | grep -c "$SrcVMid"`;
if [ "$res" != "1" ]; then
    echo "Source Machine have $res Hard Disk(s), It Must has only ONE Hard Disk";
    exit 2;
else
    res=`sed -n '/<HardDiskAttachment /p' "$SrcVMcfg" | grep "bus=\"SATA\""`;
    if [ "$res" != "" ]; then
        echo "Source Machine Hard Disk Type is \"SATA\"";
        exit 2;
    fi
    if [[ `GetValue "$SrcVM" "hda"` = "none" ]] || [[ `GetValue "$SrcVM" "hdb"` != "none" ]] || [[ `GetValue "$SrcVM" "hdd"` != "none" ]]; then
        echo "Source Machine Hard Disk is NOT hda";
        exit 2;
    fi
fi

################# Main Functions #####################
# Clone Disk
SrcDiskVDI=`GetValue "$SrcVM" "hda"`;
echo "Cloning Disk ...";
VBoxManage -nologo clonevdi "$SrcDiskID" "$CloneVM.vdi";
echo -e "Source Disk\nUUID: $SrcDiskID\nvdi:  $SrcDiskVDI\nHas been Cloned to\n$CloneMachineDir/$CloneVM.vdi\n";

# Create Clone Machine Directory and Copy Machine Config File
mkdir "$CloneMachineDir";
echo -e "Created Clone Machine Directory\n$CloneMachineDir\n";
cp -f "$SrcVMcfg" "$CloneMachineDir/$CloneVM.xml";
echo -e "Copied Source Machine Config File \n$SrcVMcfg\nto\n$CloneMachineDir/$CloneVM.xml\n";

# Create a new Machine UUID and replace the original
sed -i "s/<Machine uuid=\"{$SrcVMid}\" name=\"$SrcVM\"/<Machine uuid=\"{`uuidgen`}\" name=\"$CloneVM\"/" "$CloneMachineDir/$CloneVM.xml";
echo -e "Clone Machine UUID has been Updated\n";

# Remove Hard Disk Description from xml file
sed -i 's/<HardDiskAttachment .*\/>//' "$CloneMachineDir/$CloneVM.xml";
echo -e "Hard Disk Description has been Removed from \"$CloneMachineDir/$CloneVM.xml\"\n";

# Register the New Machine
VBoxManage -nologo registervm "$CloneMachineDir/$CloneVM.xml";
echo -e "Clone Machine has been Registered\n";

# Register the New Disk
VBoxManage -nologo modifyvm "$CloneVM" -hda "$CloneVM.vdi";
echo -e "Clone Machine Hard Disk has been Registered\n";

######################## Done ########################
echo -e "*** DONE ***\n*** The Clone Machine \"$CloneVM\" Created Succesfully ***";