# Scripting library for Service Console VCB Tools wrappers.
# Provides functionality for detecting and converting ESX 2.5.x
# legacy virtual machines backed up with "vmsnap.pl"
#
# (C) 2005 VMware, Inc. All rights reserved.

#
# Description:
# Converts a path into an absolute path
#
# Arguments:
# $1 path (relative or absolute)
#
# Result
# Writes an absolute path corresponding to $1 to stdout.
#
function libP_abspath
{
    local path="$1"

    if [ "${path:0:1}" != "/" ] ; then
	path=`pwd`"/${path}"
    fi
    echo $path
}



#
# Description:
# Looks for a .vmx file in a given directory and infers the VM's
# base name from the name of the .vmx file:
#   /<path>/<basename>.vmx --> <basename>
#
# Arguments:
# $1: directory to search
#
# Result:
# Writes the resulting basename to stdout.
#
function libP_get_vm_basename
{
    local basedir="$1"
    local vmxname

    # When we get there, we know that there is exactly one
    # matching .vmx file in this directory.
    vmxname=`ls "$basedir"/*.vmx`

    # Cut off the path and the ".vmx" suffix
    vmxname=`basename "$vmxname"`
    vmxname=${vmxname%*.vmx}
    echo $vmxname
}



#
# Description:
# Copies a VM's config file into the temporary import directory.
# Files copied are *.log, *.vmx, *.nvram. Also, names are sanitized
# if applicable.
#
# Arguments:
# $1: source directory to read files from
# $2: destination directory to copy files to.
#
# Result:
# 0 on success != 0 on failure.
#
function libP_copy_config_files
{
    local sourcedir="$1"
    local tempdir="$2"

    cp "$sourcedir/"*.log "$sourcedir/"*.vmx "$tempdir" &&
    cp "$sourcedir/"*.nvram "$tempdir/"nvram
}



#
# Description:
# Find all the SCSI disks mentioned in the .vmx file. Copy the 
# corresponding metadata file to the temp. import directory
# thereby sanitizing the file name. 

# Files copied are *.log, *.vmx, *.nvram. Also, names are sanitized
# if applicable.
#
# Arguments:
# $1: source directory to read files from
# $2: destination directory to copy files to.
# $3: VM base name (i.e: .vmx file name w/o extension and path component)
#
# Result:
# 0 on success != 0 on failure.
#
function libP_fix_disks
{
    local sourcedir="$1"
    local tempdir="$2"
    local vmname="$3"
    local i
    local diskbase
    local descfile
    local j
    local rv

    # Get all the lines in the .vmx file identifying SCSI virt. disk names.
    for i in `cat "$sourcedir/$vmname".vmx | \
	      grep 'scsi[0-9][0-9]*:[0-9][0-9]*\.name' | cut -d\" -f2`
    do
	# Disect the disk name. In general, it has the form
	# vmhbaX:X:X:X:<name>.vmdk:

	# see if there is a vmhba prefix and remove it if so. Also, remove the
	# ".vmdk" postfix.
	diskbase=`echo $i | \
	    sed s/^vmhba[0-9][0-9]*:[0-9][0-9]*:[0-9][0-9]*:[0-9][0-9]*:// | \
	    sed s/.vmdk$//`
	
	# Get the descriptor name and copy it to some sane file name
	descfile="${vmname}.${diskbase}"
	cp "$sourcedir/$vmname.${diskbase}.vmdk" "$tempdir/${diskbase}.vmdk"
	rv=$?
	if [ "$rv" != "0" ] ; then
	    echo "Could not copy $sourcedir/$vmname.${diskbase}.vmdk" >&2
	    return 1
	fi

	# Create a symlink for all the extents in the temp. dir
	for j in `cat "$sourcedir/$vmname.${diskbase}.vmdk" | grep '^RW' | \
		  cut -d\" -f2`
	do
	    ln -s "$sourcedir/$j" "$tempdir/$j"
	    rv=$?
	    if [ "$rv" != "0" ] ; then
		echo "Could not create symlink $j" >&2
		return 1
	    fi	    
        done
    done
    return 0
}



#
# Description:
# Find all SCSI disk mentioned in the .vmx file and create the
# catalog file entries that maps each disk to a SCSI ID
# in the VM. 
#
# Arguments:
# $1: VM base name (i.e: .vmx file name w/o extension and path component)
# $2: temporary directory to look for .vmdk disk file in  
# $3: Datastore target path for imported disk images.
#
# Result:
# None.
#
function libP_map_disks
{
    local vmname="$1"
    local tempdir="$2"
    local dstarget="$3"
    local vmxfile
    local base
    local scsi
    local i

    vmxfile="$tempdir/${vmname}.vmx"

    # iterate over all the disks
    for i in `find "$tempdir" -name \*.vmdk -a -type f`
    do

	# Find the matching scsiX.Y.name line and reduce it down to scsiX:Y
	base=${i##*/}
	scsi=`cat "$vmxfile" | grep '^scsi[0-9][0-9]*:[0-9][0-9]*\.name' | grep "$base"`
	scsi=${scsi%%.*}

	echo "disk.${scsi}.filename= \"$base\""
	echo "disk.${scsi}.diskname= \"$dstarget/$base\""
    done

}



#
# Description:
# Create a catalog file that contains enough information to allow
# the virtual machine to be imported with vcbRestore.
#
# Arguments:
# $1: VM base name (i.e: .vmx file name w/o extension and path component)
# $2: temporary directory to look for .vmdk disk file in  
# $3: Datastore target path for imported disk images.
# $4: Host name the VM is supposed to be associated with.
#
# Result:
# None. Writes the contents of the catalog file to stdout.
#
function libP_write_catalog
{
    local vmname="$1"
    local tempdir="$2"
    local dstarget="$3"
    local host="$4"
    local catfile="${tempdir}/catalog"
    local i
    local cnt
    local base
    local pool

    typeset -i cnt

    echo "version= esx-3.0"
    echo "state= poweredOn"

    ## get the disks
    libP_map_disks "$vmname" "$tempdir" "$dstarget"
    echo "config.vmx= \"$dstarget/${vmname}.vmx\""
    echo "host= $host"
    echo "config.suspenddir= \"$dstarget\""
    echo "config.snapshotdir= \"$dstarget\""
    echo "config.file0= \"nvram\""
    echo "config.logdir= \"$dstarget\""
    
    cnt=0
    for i in `ls "$tempdir/"*.log`
    do
	base=${i##*/}
	echo "config.log${cnt}= \"$base\""
	cnt=cnt+1
    done

    echo "folderpath= \"$FOLDERPATH\""
    pool=`echo $RESOURCEPOOL | sed s/%VMHOST%/$host/g`
    echo "resourcepool= \"$pool\""
}



#
# Description:
# Convert a VM that has been backed up under ESX 2.5.x using vmsnap.pl into
# a format that allows the VM to be restored under ESX 3.0 using vcbRestore.
#
# Arguments:
# $1: Directory containing the VM as backed up with vmsnap.pl
# Uses the following environment variables:
# FOLDERPATH, RESOURCEPOOL, VMHOST, DSPATH
#
# Result:
# Returns 0 on success. Writes the full path to a temporary directory
# containing a vcbRestore compatible file set for the VM. The directory and
# its contents should be deleted by the caller after the import.
#
function convert_legacy_vm
{
    local sourcedir=`libP_abspath "$1"`
    local dspath
    local vmname=`libP_get_vm_basename "$sourcedir"`
    local tempdir="/$TEMPDIR/vm-convert-$$"
    local rv=$?

    # Check if all required config variables are set
    if [ -z "$VMHOST" ] ; then
	echo "Config variable VMHOST is not set. Edit /etc/backuptools.conf" >&2
	echo "or specify an alternate config file." >&2
	return 1
    fi
    if [ -z "$RESOURCEPOOL" ] ; then
	echo "Config variable FOLDERPATH is not set. Edit /etc/backuptools.conf" >&2
	echo "or specify an alternate config file." >&2
	return 1
    fi
    if [ -z "$FOLDERPATH" ] ; then
	echo "Config variable FOLDERPATH is not set. Edit /etc/backuptools.conf" >&2
	echo "or specify an alternate config file." >&2
	return 1
    fi
    if [ -z "$DSPATH" ] ; then
	echo "Config variable DSPATH is not set. Edit /etc/backuptools.conf" >&2
	echo "or specify an alternate config file." >&2
	return 1
    fi

    dspath=`echo $DSPATH | sed s/%VMNAME%/$vmname/g`

    if [ -e "$tempdir" ] ; then
	echo "Temporary file/directory \"$tempdir\" already exists." >&2
	return 1
    fi

    mkdir "$tempdir" && \
    libP_copy_config_files "$sourcedir" "$tempdir" && \
    libP_fix_disks "$sourcedir" "$tempdir" "$vmname" && \
    libP_write_catalog "$vmname" "$tempdir" "$dspath" "$VMHOST" > "$tempdir"/catalog
    rv=$?
    if [ "$rv" = "0" ] ; then
	echo $tempdir
    fi
    return $rv
}



#
# Description:
# Check if a given directory contains a legacy VM backup. A legacy VM
# backup has been produced on ESX 2.5.x using "vmsnap.pl".
#
# Arguments:
# $1: Directory containing the VM backup to be examined.
#
# Result:
# 0: $1 points to a directory containing a legacy VM backup
# 1: $1 points to an ESX 3.x style VM backup
# 2: $1 does not contain any valid VM backup
#
function is_legacy_vm
{
    local sourcedir="$1"
    local rv

    if [ -z "$sourcedir" ] ; then
	# If no source dir. is specified, we assume that no legacy VM was
	# found. vcbRestore will evenutally print a usage message.
	return 1 
    fi

    if [ ! -d "$sourcedir" ] ; then
	echo "$sourecdir does not exist or is not a directory." >&2
	return 2
    fi

    if [ ! -r "$sourcedir" ] ; then
	echo "Source directory $sourcedir is not readable." >&2
	return 2
    fi

    # check for a .vmx file - Use "ls" here to avoid shell script breakage
    # should there be more than one .vmx file in this directory.
    ls "${sourcedir}"/*.vmx >/dev/null 2>&1
    rv=$?
    if [ "$rv" != "0" ] ; then
	echo "Directory $sourcedir does not seem to contain a virtual machine backup" >&2
	return 2
    fi
    
    # check for a catalog file. If none is present, we are dealing with a
    # legacy VM.
    if [ -e "$sourcedir/catalog" ] ; then
	return 1 # not a legacy VM
    fi
    return 0 # found a legacy VM
}
