mirror of
https://github.com/apache/cloudstack.git
synced 2025-12-16 02:22:52 +01:00
bug 6772: use vhd-util to coalesce snapshots into primary storage
status 6772: resolved fixed
This commit is contained in:
parent
b8e03aca4c
commit
0c2a639a2d
@ -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;
|
||||
|
||||
112
scripts/vm/hypervisor/xenserver/create_privatetemplate_from_snapshot.sh
Executable file
112
scripts/vm/hypervisor/xenserver/create_privatetemplate_from_snapshot.sh
Executable file
@ -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
|
||||
Binary file not shown.
@ -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
|
||||
@ -103,25 +104,21 @@ def delete_secondary_storage_folder(session, args):
|
||||
@echo
|
||||
def post_create_private_template(session, args):
|
||||
local_mount_path = None
|
||||
try:
|
||||
try:
|
||||
# get local template folder
|
||||
sruuid = args["tmpltSrUUID"]
|
||||
local_mount_path = os.path.join(SR.MOUNT_BASE, sruuid)
|
||||
|
||||
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"]
|
||||
size = args["size"]
|
||||
file_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")
|
||||
@ -151,6 +148,12 @@ def post_create_private_template(session, args):
|
||||
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/<dcId>/<relativeDir>
|
||||
# And create <accountId>/<instanceId> 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)
|
||||
|
||||
@ -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})
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user