diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index c1b296a4916..25b90acdfc0 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -1,5 +1,4 @@ /** - * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. * * This software is licensed under the GNU General Public License v3 or later. * @@ -2069,6 +2068,25 @@ public abstract class CitrixResourceBase implements ServerResource { } } + String createTemplateFromSnapshot(Connection conn, String templatePath, String snapshotPath) { + String results = callHostPluginAsync(conn, "vmopspremium", "create_privatetemplate_from_snapshot", + 2 * 60 * 60 * 1000, "templatePath", templatePath, "snapshotPath", snapshotPath); + + if (results == null || results.isEmpty()) { + String msg = "create_privatetemplate_from_snapshot return null"; + s_logger.warn(msg); + throw new CloudRuntimeException(msg); + } + String[] tmp = results.split("#"); + String status = tmp[0]; + if (status.equals("0")) { + return results; + } else { + s_logger.warn(results); + throw new CloudRuntimeException(results); + } + } + String copy_vhd_from_secondarystorage(Connection conn, String mountpoint, String sruuid) { String results = callHostPluginAsync(conn, "vmopspremium", "copy_vhd_from_secondarystorage", 2 * 60 * 60 * 1000, "mountpoint", mountpoint, "sruuid", sruuid); @@ -4812,7 +4830,7 @@ public abstract class CitrixResourceBase implements ServerResource { } } else { try { - String volumePath = mountpoint + volumeUUID + ".vhd"; + String volumePath = mountpoint + "/" + volumeUUID + ".vhd"; String uuid = copy_vhd_from_secondarystorage(conn, volumePath, srUuid); return new CopyVolumeAnswer(cmd, true, null, srUuid, uuid); } finally { @@ -5122,6 +5140,7 @@ public abstract class CitrixResourceBase implements ServerResource { s_logger.warn(details); return new CreatePrivateTemplateAnswer(cmd, false, details); } + VDI volume = getVDIbyUuid(conn, volumeUUID); // create template SR URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath); @@ -5134,13 +5153,13 @@ public abstract class CitrixResourceBase implements ServerResource { tmpltVDI.setNameLabel(conn, userSpecifiedName); } - String tmpltSrUUID = tmpltSR.getUuid(conn); String tmpltUUID = tmpltVDI.getUuid(conn); String tmpltFilename = tmpltUUID + ".vhd"; long virtualSize = tmpltVDI.getVirtualSize(conn); long physicalSize = tmpltVDI.getPhysicalUtilisation(conn); // create the template.properties file - result = postCreatePrivateTemplate(conn, tmpltSrUUID, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, templateId); + String templatePath = secondaryStorageMountPath + "/" + installPath; + result = postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, templateId); if (!result) { throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI); } @@ -5182,34 +5201,23 @@ public abstract class CitrixResourceBase implements ServerResource { s_logger.warn(details); return new CreatePrivateTemplateAnswer(cmd, false, details); } + String templatePath = secondaryStorageMountPath + "/" + installPath; // create snapshot SR - URI snapshotURI = new URI(secondaryStoragePoolURL + "/snapshots/" + accountId + "/" + volumeId ); - snapshotSR = createNfsSRbyURI(conn, snapshotURI, false); - snapshotSR.scan(conn); - VDI snapshotVDI = getVDIbyUuid(conn, backedUpSnapshotUuid); - - // create template SR - URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath); - tmpltSR = createNfsSRbyURI(conn, tmpltURI, false); - // copy snapshotVDI to template SR - VDI tmpltVDI = cloudVDIcopy(conn, snapshotVDI, tmpltSR); - - String tmpltSrUUID = tmpltSR.getUuid(conn); - String tmpltUUID = tmpltVDI.getUuid(conn); - String tmpltFilename = tmpltUUID + ".vhd"; - long virtualSize = tmpltVDI.getVirtualSize(conn); - long physicalSize = tmpltVDI.getPhysicalUtilisation(conn); + String snapshotPath = secondaryStorageMountPath + "/snapshots/" + accountId + "/" + volumeId + "/" + backedUpSnapshotUuid + ".vhd"; + String results = createTemplateFromSnapshot(conn, templatePath, snapshotPath); + String[] tmp = results.split("#"); + String tmpltUuid = tmp[1]; + long physicalSize = Long.parseLong(tmp[2]); + long virtualSize = Long.parseLong(tmp[3]) * 1024 * 1024; + String tmpltFilename = tmpltUuid + ".vhd"; // create the template.properties file - result = postCreatePrivateTemplate(conn, tmpltSrUUID, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, newTemplateId); + result = postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUuid, userSpecifiedName, null, physicalSize, virtualSize, newTemplateId); if (!result) { - throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI); + throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + templatePath); } installPath = installPath + "/" + tmpltFilename; - return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, physicalSize, tmpltUUID, ImageFormat.VHD); - } catch (XenAPIException e) { - details = "Creating template from snapshot " + backedUpSnapshotUuid + " failed due to " + e.getMessage(); - s_logger.error(details, e); + return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, physicalSize, tmpltUuid, ImageFormat.VHD); } catch (Exception e) { details = "Creating template from snapshot " + backedUpSnapshotUuid + " failed due to " + e.getMessage(); s_logger.error(details, e); @@ -5339,8 +5347,6 @@ public abstract class CitrixResourceBase implements ServerResource { String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL(); String backedUpSnapshotUuid = cmd.getSnapshotUuid(); - // By default, assume the command has failed and set the params to be - // passed to CreateVolumeFromSnapshotAnswer appropriately boolean result = false; // Generic error message. String details = null; @@ -5359,18 +5365,10 @@ public abstract class CitrixResourceBase implements ServerResource { } // Get the absolute path of the snapshot on the secondary storage. URI snapshotURI = new URI(secondaryStoragePoolURL + "/snapshots/" + accountId + "/" + volumeId ); - - snapshotSR = createNfsSRbyURI(conn, snapshotURI, false); - snapshotSR.scan(conn); - VDI snapshotVDI = getVDIbyUuid(conn, backedUpSnapshotUuid); - - VDI volumeVDI = cloudVDIcopy(conn, snapshotVDI, primaryStorageSR); - - volumeUUID = volumeVDI.getUuid(conn); - - + String snapshotPath = snapshotURI.getHost() + ":" + snapshotURI.getPath() + "/" + backedUpSnapshotUuid + ".vhd"; + String srUuid = primaryStorageSR.getUuid(conn); + volumeUUID = copy_vhd_from_secondarystorage(conn, snapshotPath, srUuid); result = true; - } catch (XenAPIException e) { details += " due to " + e.toString(); s_logger.warn(details, e); @@ -5640,6 +5638,7 @@ public abstract class CitrixResourceBase implements ServerResource { return new ConsoleProxyLoadAnswer(cmd, proxyVmId, proxyVmName, success, result); } + protected boolean createSecondaryStorageFolder(Connection conn, String remoteMountPath, String newFolder) { String result = callHostPlugin(conn, "vmopsSnapshot", "create_secondary_storage_folder", "remoteMountPath", remoteMountPath, "newFolder", newFolder); return (result != null); @@ -5650,7 +5649,7 @@ public abstract class CitrixResourceBase implements ServerResource { return (result != null); } - protected boolean postCreatePrivateTemplate(Connection conn, String tmpltSrUUID,String tmpltFilename, String templateName, String templateDescription, String checksum, long size, long virtualSize, long templateId) { + protected boolean postCreatePrivateTemplate(Connection conn, String templatePath, String tmpltFilename, String templateName, String templateDescription, String checksum, long size, long virtualSize, long templateId) { if (templateDescription == null) { templateDescription = ""; @@ -5660,7 +5659,7 @@ public abstract class CitrixResourceBase implements ServerResource { checksum = ""; } - String result = callHostPluginWithTimeOut(conn, "vmopsSnapshot", "post_create_private_template", 110*60, "tmpltSrUUID", tmpltSrUUID, "templateFilename", tmpltFilename, "templateName", templateName, "templateDescription", templateDescription, + String result = callHostPluginWithTimeOut(conn, "vmopsSnapshot", "post_create_private_template", 110*60, "templatePath", templatePath, "templateFilename", tmpltFilename, "templateName", templateName, "templateDescription", templateDescription, "checksum", checksum, "size", String.valueOf(size), "virtualSize", String.valueOf(virtualSize), "templateId", String.valueOf(templateId)); boolean success = false; diff --git a/scripts/vm/hypervisor/xenserver/create_privatetemplate_from_snapshot.sh b/scripts/vm/hypervisor/xenserver/create_privatetemplate_from_snapshot.sh new file mode 100755 index 00000000000..3fe82142bfe --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/create_privatetemplate_from_snapshot.sh @@ -0,0 +1,112 @@ +#!/bin/bash + +#set -x + +usage() { + printf "Usage: %s [vhd file in secondary storage] [template directory in secondary storage] \n" $(basename $0) +} + +cleanup() +{ + if [ ! -z $snapshotdir ]; then + umount $snapshotdir + if [ $? -eq 0 ]; then + rm $snapshotdir -rf + fi + fi + if [ ! -z $templatedir ]; then + umount $templatedir + if [ $? -eq 0 ]; then + rm $templatedir -rf + fi + fi +} + +if [ -z $1 ]; then + usage + echo "2#no vhd file path" + exit 0 +else + snapshoturl=${1%/*} + vhdfilename=${1##*/} +fi + +if [ -z $2 ]; then + usage + echo "3#no template path" + exit 0 +else + templateurl=$2 +fi + +snapshotdir=/var/run/cloud_mount/$(uuidgen -r) +mkdir -p $snapshotdir +if [ $? -ne 0 ]; then + echo "4#cann't make dir $snapshotdir" + exit 0 +fi + +mount $snapshoturl $snapshotdir +if [ $? -ne 0 ]; then + rm -rf $snapshotdir + echo "5#can not mount $snapshoturl to $snapshotdir" + exit 0 +fi + +templatedir=/var/run/cloud_mount/$(uuidgen -r) +mkdir -p $templatedir +if [ $? -ne 0 ]; then + templatedir="" + cleanup + echo "6#cann't make dir $templatedir" + exit 0 +fi + +mount $templateurl $templatedir +if [ $? -ne 0 ]; then + rm -rf $templatedir + templatedir="" + cleanup + echo "7#can not mount $templateurl to $templatedir" + exit 0 +fi + +VHDUTIL="/opt/xensource/bin/vhd-util" + +copyvhd() +{ + local desvhd=$1 + local srcvhd=$2 + local parent=`$VHDUTIL query -p -n $srcvhd` + if [ $? -ne 0 ]; then + echo "30#failed to query $srcvhd" + cleanup + exit 0 + fi + if [ "${parent##*vhd has}" = " no parent" ]; then + dd if=$srcvhd of=$desvhd bs=2M + if [ $? -ne 0 ]; then + echo "31#failed to dd $srcvhd to $desvhd" + cleanup + exit 0 + fi + else + copyvhd $desvhd $parent + $VHDUTIL coalesce -p $desvhd -n $srcvhd + if [ $? -ne 0 ]; then + echo "32#failed to coalesce $desvhd to $srcvhd" + cleanup + exit 0 + fi + fi +} + +templateuuid=$(uuidgen -r) +desvhd=$templatedir/$templateuuid.vhd +srcvhd=$snapshotdir/$vhdfilename +copyvhd $desvhd $srcvhd +virtualSize=`$VHDUTIL query -v -n $desvhd` +physicalSize=`ls -l $desvhd | awk '{print $5}'` +cleanup +echo "0#$templateuuid#$physicalSize#$virtualSize" +exit 0 diff --git a/scripts/vm/hypervisor/xenserver/vhd-util b/scripts/vm/hypervisor/xenserver/vhd-util index c2a98a505ba..46d62dd44d9 100755 Binary files a/scripts/vm/hypervisor/xenserver/vhd-util and b/scripts/vm/hypervisor/xenserver/vhd-util differ diff --git a/scripts/vm/hypervisor/xenserver/vmopsSnapshot b/scripts/vm/hypervisor/xenserver/vmopsSnapshot index 3afe1f14e60..affc8e50afb 100755 --- a/scripts/vm/hypervisor/xenserver/vmopsSnapshot +++ b/scripts/vm/hypervisor/xenserver/vmopsSnapshot @@ -19,6 +19,7 @@ import random VHD_UTIL = '/usr/sbin/vhd-util' VHD_PREFIX = 'VHD-' +CLOUD_DIR = '/var/run/cloud_mount' def echo(fn): def wrapped(*v, **k): @@ -40,7 +41,7 @@ def create_secondary_storage_folder(session, args): try: # Mount the remote resource folder locally remote_mount_path = args["remoteMountPath"] - local_mount_path = os.path.join(SR.MOUNT_BASE, "mount" + str(int(random.random() * 1000000))) + local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid()) mount(remote_mount_path, local_mount_path) # Create the new folder @@ -76,7 +77,7 @@ def delete_secondary_storage_folder(session, args): try: # Mount the remote resource folder locally remote_mount_path = args["remoteMountPath"] - local_mount_path = os.path.join(SR.MOUNT_BASE, "mount" + str(int(random.random() * 1000000))) + local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid()) mount(remote_mount_path, local_mount_path) # Delete the specified folder @@ -104,53 +105,55 @@ def delete_secondary_storage_folder(session, args): def post_create_private_template(session, args): local_mount_path = None try: - # get local template folder - sruuid = args["tmpltSrUUID"] - local_mount_path = os.path.join(SR.MOUNT_BASE, sruuid) - - # Retrieve args - filename = args["templateFilename"] - name = args["templateName"] - description = args["templateDescription"] - checksum = args["checksum"] - size = args["size"] - virtual_size = args["virtualSize"] - template_id = args["templateId"] - - # Determine the template size - template_install_path = local_mount_path + "/" + filename - file_size = os.path.getsize(template_install_path) - util.SMlog("Got template file_size: " + str(file_size)) - - # Create the template.properties file - template_properties_install_path = local_mount_path + "/template.properties" - f = open(template_properties_install_path, "w") - f.write("filename=" + filename + "\n") - f.write("vhd=true\n") - f.write("id=" + template_id + "\n") - f.write("vhd.filename=" + filename + "\n") - f.write("public=false\n") - f.write("uniquename=" + name + "\n") - f.write("vhd.virtualsize=" + virtual_size + "\n") - f.write("virtualsize=" + virtual_size + "\n") - f.write("checksum=" + checksum + "\n") - f.write("hvm=true\n") - f.write("description=" + description + "\n") - f.write("vhd.size=" + str(file_size) + "\n") - f.write("size=" + str(file_size) + "\n") - f.close() - util.SMlog("Created template.properties file") + try: + # get local template folder + templatePath = args["templatePath"] + local_mount_path = os.path.join(CLOUD_DIR, util.gen_uuid()) + mount(templatePath, local_mount_path) + # Retrieve args + filename = args["templateFilename"] + name = args["templateName"] + description = args["templateDescription"] + checksum = args["checksum"] + file_size = args["size"] + virtual_size = args["virtualSize"] + template_id = args["templateId"] - # Set permissions - permissions = stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH - os.chmod(template_properties_install_path, permissions) - util.SMlog("Set permissions on template and template.properties") + # Create the template.properties file + template_properties_install_path = local_mount_path + "/template.properties" + f = open(template_properties_install_path, "w") + f.write("filename=" + filename + "\n") + f.write("vhd=true\n") + f.write("id=" + template_id + "\n") + f.write("vhd.filename=" + filename + "\n") + f.write("public=false\n") + f.write("uniquename=" + name + "\n") + f.write("vhd.virtualsize=" + virtual_size + "\n") + f.write("virtualsize=" + virtual_size + "\n") + f.write("checksum=" + checksum + "\n") + f.write("hvm=true\n") + f.write("description=" + description + "\n") + f.write("vhd.size=" + str(file_size) + "\n") + f.write("size=" + str(file_size) + "\n") + f.close() + util.SMlog("Created template.properties file") + + # Set permissions + permissions = stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH + os.chmod(template_properties_install_path, permissions) + util.SMlog("Set permissions on template and template.properties") - except: - errMsg = "post_create_private_template failed." - util.SMlog(errMsg) - raise xs_errors.XenError(errMsg) + except: + errMsg = "post_create_private_template failed." + util.SMlog(errMsg) + raise xs_errors.XenError(errMsg) + finally: + if local_mount_path != None: + # Unmount the local folder + umount(local_mount_path) + # Remove the local folder + os.system("rm -rf " + local_mount_path) return "1" def isfile(path, isISCSI): @@ -306,7 +309,6 @@ def umount(localDir): def mountSnapshotsDir(secondaryStorageMountPath, relativeDir, dcId, accountId, instanceId): # The aim is to mount secondaryStorageMountPath on - # SR.MOUNT_BASE// # And create / dir on it, if it doesn't exist already. # Assuming that secondaryStorageMountPath exists remotely @@ -316,7 +318,7 @@ def mountSnapshotsDir(secondaryStorageMountPath, relativeDir, dcId, accountId, i snapshotsDir = os.path.join(secondaryStorageMountPath, relativeDir) # Mkdir local mount point dir, if it doesn't exist. - localMountPointPath = os.path.join(SR.MOUNT_BASE, dcId) + localMountPointPath = os.path.join(CLOUD_DIR, dcId) localMountPointPath = os.path.join(localMountPointPath, relativeDir) makedirs(localMountPointPath) @@ -339,7 +341,7 @@ def mountSnapshotsDir(secondaryStorageMountPath, relativeDir, dcId, accountId, i @echo def unmountSnapshotsDir(session, args): dcId = args['dcId'] - localMountPointPath = os.path.join(SR.MOUNT_BASE, dcId) + localMountPointPath = os.path.join(CLOUD_DIR, dcId) localMountPointPath = os.path.join(localMountPointPath, "snapshots") try: umount(localMountPointPath) diff --git a/scripts/vm/hypervisor/xenserver/vmopspremium b/scripts/vm/hypervisor/xenserver/vmopspremium index d86f0cb147b..a45464312a7 100755 --- a/scripts/vm/hypervisor/xenserver/vmopspremium +++ b/scripts/vm/hypervisor/xenserver/vmopspremium @@ -17,6 +17,17 @@ def echo(fn): return res return wrapped +@echo +def create_privatetemplate_from_snapshot(session, args): + templatePath = args['templatePath'] + snapshotPath = args['snapshotPath'] + try: + cmd = ["bash", "/opt/xensource/bin/create_privatetemplate_from_snapshot.sh",snapshotPath, templatePath] + txt = util.pread2(cmd) + except: + txt = '10#failed' + return txt + @echo def copy_vhd_to_secondarystorage(session, args): mountpoint = args['mountpoint'] @@ -86,5 +97,5 @@ def heartbeat(session, args): return txt if __name__ == "__main__": - XenAPIPlugin.dispatch({"copy_vhd_to_secondarystorage":copy_vhd_to_secondarystorage, "copy_vhd_from_secondarystorage":copy_vhd_from_secondarystorage, "setup_heartbeat_sr":setup_heartbeat_sr, "setup_heartbeat_file":setup_heartbeat_file, "check_heartbeat":check_heartbeat, "heartbeat": heartbeat}) + XenAPIPlugin.dispatch({"create_privatetemplate_from_snapshot":create_privatetemplate_from_snapshot, "copy_vhd_to_secondarystorage":copy_vhd_to_secondarystorage, "copy_vhd_from_secondarystorage":copy_vhd_from_secondarystorage, "setup_heartbeat_sr":setup_heartbeat_sr, "setup_heartbeat_file":setup_heartbeat_file, "check_heartbeat":check_heartbeat, "heartbeat": heartbeat}) diff --git a/scripts/vm/hypervisor/xenserver/xenserver56/patch b/scripts/vm/hypervisor/xenserver/xenserver56/patch index 0170f61af85..bdf86d3640f 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver56/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver56/patch @@ -41,3 +41,4 @@ vhd-util=..,0755,/opt/xensource/bin vmopspremium=..,0755,/etc/xapi.d/plugins InterfaceReconfigure.py=.,0755,/opt/xensource/bin fsimage.so=..,0755,/usr/lib/fs/ext2fs-lib +create_privatetemplate_from_snapshot.sh=..,0755,/opt/xensource/bin diff --git a/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch b/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch index a73beea2bc3..d0d5847e177 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch @@ -41,3 +41,4 @@ xenheartbeat.sh=..,0755,/opt/xensource/bin launch_hb.sh=..,0755,/opt/xensource/bin vhd-util=..,0755,/opt/xensource/bin vmopspremium=..,0755,/etc/xapi.d/plugins +create_privatetemplate_from_snapshot.sh=..,0755,/opt/xensource/bin