snapshot redesign

1. use full snapshot and delta snapshot, there are maxsnashot/2 of delta snapshot between two full snapshot
2. only support one policy for one volume
3. remove all coleases in secondary storage.
This commit is contained in:
anthony 2010-09-28 18:34:35 -07:00
parent 72cb2ce4ca
commit 319d4f1aa0
30 changed files with 1049 additions and 2090 deletions

View File

@ -27,7 +27,6 @@ package com.cloud.agent.api;
public class BackupSnapshotCommand extends SnapshotCommand {
private String prevSnapshotUuid;
private String prevBackupUuid;
private boolean isFirstSnapshotOfRootVolume;
private boolean isVolumeInactive;
private String firstBackupUuid;
private String vmName;
@ -56,7 +55,6 @@ public class BackupSnapshotCommand extends SnapshotCommand {
String prevSnapshotUuid,
String prevBackupUuid,
String firstBackupUuid,
boolean isFirstSnapshotOfRootVolume,
boolean isVolumeInactive,
String vmName)
{
@ -64,7 +62,6 @@ public class BackupSnapshotCommand extends SnapshotCommand {
this.prevSnapshotUuid = prevSnapshotUuid;
this.prevBackupUuid = prevBackupUuid;
this.firstBackupUuid = firstBackupUuid;
this.isFirstSnapshotOfRootVolume = isFirstSnapshotOfRootVolume;
this.isVolumeInactive = isVolumeInactive;
this.vmName = vmName;
}
@ -81,10 +78,6 @@ public class BackupSnapshotCommand extends SnapshotCommand {
return firstBackupUuid;
}
public boolean isFirstSnapshotOfRootVolume() {
return isFirstSnapshotOfRootVolume;
}
public boolean isVolumeInactive() {
return isVolumeInactive;
}

View File

@ -0,0 +1,79 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.agent.api;
public class CreatePrivateTemplateFromVolumeCommand extends SnapshotCommand {
private String _volumePath;
private String _userSpecifiedName;
private String _uniqueName;
private long _templateId;
private long _accountId;
// For XenServer
private String _secondaryStorageURL;
public CreatePrivateTemplateFromVolumeCommand() {}
public CreatePrivateTemplateFromVolumeCommand(String secondaryStorageURL, long templateId, long accountId, String userSpecifiedName, String uniqueName, String volumePath) {
_secondaryStorageURL = secondaryStorageURL;
_templateId = templateId;
_accountId = accountId;
_userSpecifiedName = userSpecifiedName;
_uniqueName = uniqueName;
_volumePath = volumePath;
}
@Override
public boolean executeInSequence() {
return false;
}
public String getSecondaryStorageURL() {
return _secondaryStorageURL;
}
public String getTemplateName() {
return _userSpecifiedName;
}
public String getUniqueName() {
return _uniqueName;
}
public long getTemplateId() {
return _templateId;
}
public void setVolumePath(String _volumePath) {
this._volumePath = _volumePath;
}
public String getVolumePath() {
return _volumePath;
}
public Long getAccountId() {
return _accountId;
}
public void setTemplateId(long templateId) {
_templateId = templateId;
}
}

View File

@ -22,7 +22,6 @@ package com.cloud.agent.api;
* This currently assumes that both primary and secondary storage are mounted on the XenServer.
*/
public class CreateVolumeFromSnapshotCommand extends SnapshotCommand {
private String templatePath;
protected CreateVolumeFromSnapshotCommand() {
@ -51,18 +50,9 @@ public class CreateVolumeFromSnapshotCommand extends SnapshotCommand {
Long accountId,
Long volumeId,
String backedUpSnapshotUuid,
String backedUpSnapshotName,
String templatePath)
String backedUpSnapshotName)
{
super(primaryStoragePoolNameLabel, secondaryStoragePoolURL, backedUpSnapshotUuid, backedUpSnapshotName, dcId, accountId, volumeId);
this.templatePath = templatePath;
}
/**
* @return the templatePath
*/
public String getTemplatePath() {
return templatePath;
}
}

View File

@ -22,7 +22,6 @@ package com.cloud.agent.api;
* This currently assumes that the secondary storage are mounted on the XenServer.
*/
public class DeleteSnapshotBackupCommand extends SnapshotCommand {
private String childUUID;
protected DeleteSnapshotBackupCommand() {
@ -59,18 +58,8 @@ public class DeleteSnapshotBackupCommand extends SnapshotCommand {
Long accountId,
Long volumeId,
String backupUUID,
String backupName,
String childUUID)
String backupName)
{
super(primaryStoragePoolNameLabel, secondaryStoragePoolURL, backupUUID, backupName, dcId, accountId, volumeId);
this.childUUID = childUUID;
}
/**
* @return the childUUID
*/
public String getChildUUID() {
return childUUID;
}
}

View File

@ -38,19 +38,21 @@ public class ManageSnapshotCommand extends Command {
public ManageSnapshotCommand() {}
public ManageSnapshotCommand(String commandSwitch, long snapshotId, String path, String snapshotName, String vmName) {
_commandSwitch = commandSwitch;
if (commandSwitch.equals(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
_volumePath = path;
}
else if (commandSwitch.equals(ManageSnapshotCommand.DESTROY_SNAPSHOT)) {
_snapshotPath = path;
}
public ManageSnapshotCommand(long snapshotId, String volumePath, String preSnapshotPath ,String snapshotName, String vmName) {
_commandSwitch = ManageSnapshotCommand.CREATE_SNAPSHOT;
_volumePath = volumePath;
_snapshotPath = preSnapshotPath;
_snapshotName = snapshotName;
_snapshotId = snapshotId;
_vmName = vmName;
}
public ManageSnapshotCommand(long snapshotId, String snapshotPath) {
_commandSwitch = ManageSnapshotCommand.DESTROY_SNAPSHOT;
_snapshotPath = snapshotPath;
}
@Override
public boolean executeInSequence() {
return false;

View File

@ -38,6 +38,10 @@ public class CreatePrivateTemplateAnswer extends Answer {
_format = format;
}
public CreatePrivateTemplateAnswer(Command cmd, boolean success, String result) {
super(cmd, success, result);
}
public String getPath() {
return _path;
}

View File

@ -67,6 +67,7 @@ import com.cloud.agent.api.CheckVirtualMachineAnswer;
import com.cloud.agent.api.CheckVirtualMachineCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
import com.cloud.agent.api.DeleteSnapshotBackupAnswer;
@ -138,7 +139,7 @@ import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.storage.CreatePrivateTemplateCommand;
import com.cloud.agent.api.storage.DestroyCommand;
import com.cloud.agent.api.storage.DownloadAnswer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
@ -607,8 +608,6 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
return execute((AttachVolumeCommand) cmd);
} else if (cmd instanceof AttachIsoCommand) {
return execute((AttachIsoCommand) cmd);
} else if (cmd instanceof ValidateSnapshotCommand) {
return execute((ValidateSnapshotCommand) cmd);
} else if (cmd instanceof ManageSnapshotCommand) {
return execute((ManageSnapshotCommand) cmd);
} else if (cmd instanceof BackupSnapshotCommand) {
@ -619,8 +618,8 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
return execute((CreateVolumeFromSnapshotCommand) cmd);
} else if (cmd instanceof DeleteSnapshotsDirCommand) {
return execute((DeleteSnapshotsDirCommand) cmd);
} else if (cmd instanceof CreatePrivateTemplateCommand) {
return execute((CreatePrivateTemplateCommand) cmd);
} else if (cmd instanceof CreatePrivateTemplateFromVolumeCommand) {
return execute((CreatePrivateTemplateFromVolumeCommand) cmd);
} else if (cmd instanceof CreatePrivateTemplateFromSnapshotCommand) {
return execute((CreatePrivateTemplateFromSnapshotCommand) cmd);
} else if (cmd instanceof GetStorageStatsCommand) {
@ -891,7 +890,6 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
Pair<VM, String> v = createVmFromTemplate(conn, vmSpec, host);
vm = v.first();
String vmUuid = v.second();
for (VolumeTO disk : vmSpec.getDisks()) {
createVbd(conn, vmName, vm, disk, disk.getType() == VolumeType.ROOT && vmSpec.getType() != VirtualMachine.Type.User);
@ -3943,7 +3941,6 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
try {
Host myself = Host.getByUuid(conn, _host.uuid);
boolean findsystemvmiso = false;
Set<SR> srs = SR.getByNameLabel(conn, "XenServer Tools");
if( srs.size() != 1 ) {
throw new CloudRuntimeException("There are " + srs.size() + " SRs with name XenServer Tools");
@ -4812,7 +4809,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
throw new Exception("no attached PBD");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(logX(sr, "Created a SR; UUID is " + sr.getUuid(conn)));
s_logger.debug(logX(sr, "Created a SR; UUID is " + sr.getUuid(conn) + " device config is " + deviceConfig));
}
sr.scan(conn);
return sr;
@ -5412,84 +5409,8 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
}
}
protected ValidateSnapshotAnswer execute(final ValidateSnapshotCommand cmd) {
String primaryStoragePoolNameLabel = cmd.getPrimaryStoragePoolNameLabel();
String volumeUuid = cmd.getVolumeUuid(); // Precondition: not null
String firstBackupUuid = cmd.getFirstBackupUuid();
String previousSnapshotUuid = cmd.getPreviousSnapshotUuid();
String templateUuid = cmd.getTemplateUuid();
// By default assume failure
String details = "Could not validate previous snapshot backup UUID " + "because the primary Storage SR could not be created from the name label: "
+ primaryStoragePoolNameLabel;
boolean success = false;
String expectedSnapshotBackupUuid = null;
String actualSnapshotBackupUuid = null;
String actualSnapshotUuid = null;
Boolean isISCSI = false;
String primaryStorageSRUuid = null;
Connection conn = getConnection();
try {
SR primaryStorageSR = getSRByNameLabelandHost(primaryStoragePoolNameLabel);
if (primaryStorageSR != null) {
primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
}
} catch (BadServerResponse e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
} catch (XenAPIException e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
} catch (XmlRpcException e) {
details += ", reason: " + e.getMessage();
s_logger.error(details, e);
}
if (primaryStorageSRUuid != null) {
if (templateUuid == null) {
templateUuid = "";
}
if (firstBackupUuid == null) {
firstBackupUuid = "";
}
if (previousSnapshotUuid == null) {
previousSnapshotUuid = "";
}
String result = callHostPlugin("vmopsSnapshot", "validateSnapshot", "primaryStorageSRUuid", primaryStorageSRUuid, "volumeUuid", volumeUuid, "firstBackupUuid", firstBackupUuid,
"previousSnapshotUuid", previousSnapshotUuid, "templateUuid", templateUuid, "isISCSI", isISCSI.toString());
if (result == null || result.isEmpty()) {
details = "Validating snapshot backup for volume with UUID: " + volumeUuid + " failed because there was an exception in the plugin";
// callHostPlugin exception which has been logged already
} else {
String[] uuids = result.split("#", -1);
if (uuids.length >= 3) {
expectedSnapshotBackupUuid = uuids[1];
actualSnapshotBackupUuid = uuids[2];
}
if (uuids.length >= 4) {
actualSnapshotUuid = uuids[3];
} else {
actualSnapshotUuid = "";
}
if (uuids[0].equals("1")) {
success = true;
details = null;
} else {
details = "Previous snapshot backup on the primary storage is invalid. " + "Expected: " + expectedSnapshotBackupUuid + " Actual: " + actualSnapshotBackupUuid;
// success is still false
}
s_logger.debug("ValidatePreviousSnapshotBackup returned " + " success: " + success + " details: " + details + " expectedSnapshotBackupUuid: "
+ expectedSnapshotBackupUuid + " actualSnapshotBackupUuid: " + actualSnapshotBackupUuid + " actualSnapshotUuid: " + actualSnapshotUuid);
}
}
return new ValidateSnapshotAnswer(cmd, success, details, expectedSnapshotBackupUuid, actualSnapshotBackupUuid, actualSnapshotUuid);
}
protected ManageSnapshotAnswer execute(final ManageSnapshotCommand cmd) {
long snapshotId = cmd.getSnapshotId();
String snapshotName = cmd.getSnapshotName();
@ -5510,8 +5431,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
if (cmdSwitch.equals(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
// Look up the volume
String volumeUUID = cmd.getVolumePath();
VDI volume = getVDIbyUuid(volumeUUID);
VDI volume = VDI.getByUuid(conn, volumeUUID);
// Create a snapshot
VDI snapshot = volume.snapshot(conn, new HashMap<String, String>());
@ -5519,10 +5439,26 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
if (snapshotName != null) {
snapshot.setNameLabel(conn, snapshotName);
}
// Determine the UUID of the snapshot
VDI.Record vdir = snapshot.getRecord(conn);
snapshotUUID = vdir.uuid;
snapshotUUID = snapshot.getUuid(conn);
String preSnapshotUUID = cmd.getSnapshotPath();
//check if it is a empty snapshot
if( preSnapshotUUID != null) {
SR sr = volume.getSR(conn);
String srUUID = sr.getUuid(conn);
String type = sr.getType(conn);
Boolean isISCSI = SRType.LVMOISCSI.equals(type);
String snapshotParentUUID = getVhdParent(srUUID, snapshotUUID, isISCSI);
String preSnapshotParentUUID = getVhdParent(srUUID, preSnapshotUUID, isISCSI);
if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) {
// this is empty snapshot, remove it
snapshot.destroy(conn);
snapshotUUID = preSnapshotUUID;
}
}
success = true;
details = null;
@ -5547,74 +5483,63 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
return new ManageSnapshotAnswer(cmd, snapshotId, snapshotUUID, success, details);
}
protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateCommand cmd) {
String secondaryStorageURL = cmd.getSecondaryStorageURL();
String snapshotUUID = cmd.getSnapshotPath();
protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateFromVolumeCommand cmd) {
String secondaryStoragePoolURL = cmd.getSecondaryStorageURL();
String volumeUUID = cmd.getVolumePath();
Long accountId = cmd.getAccountId();
String userSpecifiedName = cmd.getTemplateName();
Long templateId = cmd.getTemplateId();
SR secondaryStorage = null;
VDI privateTemplate = null;
Connection conn = getConnection();
String details = null;
SR tmpltSR = null;
boolean result = false;
try {
URI uri = new URI(secondaryStorageURL);
String remoteTemplateMountPath = uri.getHost() + ":" + uri.getPath() + "/template/";
String templateFolder = cmd.getAccountId() + "/" + cmd.getTemplateId() + "/";
String templateDownloadFolder = createTemplateDownloadFolder(remoteTemplateMountPath, templateFolder);
String templateInstallFolder = "tmpl/" + templateFolder;
// Create a SR for the secondary storage download folder
secondaryStorage = createNfsSRbyURI(new URI(secondaryStorageURL + "/template/" + templateDownloadFolder), false);
URI uri = new URI(secondaryStoragePoolURL);
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
String installPath = "template/tmpl/" + accountId + "/" + templateId;
if( !createSecondaryStorageFolder(secondaryStorageMountPath, installPath)) {
details = " Filed to create folder " + installPath + " in secondary storage";
s_logger.warn(details);
return new CreatePrivateTemplateAnswer(cmd, false, details);
}
Connection conn = getConnection();
VDI volume = getVDIbyUuid(volumeUUID);
// create template SR
URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath);
tmpltSR = createNfsSRbyURI(tmpltURI, false);
// Look up the snapshot and copy it to secondary storage
VDI snapshot = getVDIbyUuid(snapshotUUID);
privateTemplate = cloudVDIcopy(snapshot, secondaryStorage);
// copy volume to template SR
VDI tmpltVDI = cloudVDIcopy(volume, tmpltSR);
if (userSpecifiedName != null) {
privateTemplate.setNameLabel(conn, userSpecifiedName);
tmpltVDI.setNameLabel(conn, userSpecifiedName);
}
// Determine the template file name and install path
VDI.Record vdir = privateTemplate.getRecord(conn);
String templateName = vdir.uuid;
String templateFilename = templateName + ".vhd";
String installPath = "template/" + templateInstallFolder + templateFilename;
// Determine the template's virtual size and then forget the VDI
long virtualSize = privateTemplate.getVirtualSize(conn);
// Create the template.properties file in the download folder, move
// the template and the template.properties file
// to the install folder, and then delete the download folder
if (!postCreatePrivateTemplate(remoteTemplateMountPath, templateDownloadFolder, templateInstallFolder, templateFilename, templateName, userSpecifiedName, null,
virtualSize, cmd.getTemplateId())) {
throw new InternalErrorException("Failed to create the template.properties file.");
String tmpltSrUUID = tmpltSR.getUuid(conn);
String tmpltUUID = tmpltVDI.getUuid(conn);
String tmpltFilename = tmpltUUID + ".vhd";
long virtualSize = tmpltVDI.getVirtualSize(conn);
long size = tmpltVDI.getPhysicalUtilisation(conn);
// create the template.properties file
result = postCreatePrivateTemplate(tmpltSrUUID, tmpltFilename, tmpltUUID, userSpecifiedName, null, size, virtualSize, templateId);
if (!result) {
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI);
}
return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, templateName, ImageFormat.VHD);
return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, tmpltUUID, ImageFormat.VHD);
} catch (XenAPIException e) {
if (privateTemplate != null) {
destroyVDI(privateTemplate);
}
s_logger.warn("CreatePrivateTemplate Failed due to " + e.toString(), e);
return new CreatePrivateTemplateAnswer(cmd, false, e.toString(), null, 0, null, null);
details = "Creating template from volume " + volumeUUID + " failed due to " + e.getMessage();
s_logger.error(details, e);
} catch (Exception e) {
s_logger.warn("CreatePrivateTemplate Failed due to " + e.getMessage(), e);
return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage(), null, 0, null, null);
details = "Creating template from volume " + volumeUUID + " failed due to " + e.getMessage();
s_logger.error(details, e);
} finally {
// Remove the secondary storage SR
removeSR(secondaryStorage);
removeSR(tmpltSR);
}
return new CreatePrivateTemplateAnswer(cmd, result, details);
}
private String createTemplateDownloadFolder(String remoteTemplateMountPath, String templateFolder) throws InternalErrorException, URISyntaxException {
String templateDownloadFolder = "download/" + _host.uuid + "/" + templateFolder;
// Create the download folder
if (!createSecondaryStorageFolder(remoteTemplateMountPath, templateDownloadFolder)) {
throw new InternalErrorException("Failed to create the template download folder.");
}
return templateDownloadFolder;
}
protected CreatePrivateTemplateAnswer execute(final CreatePrivateTemplateFromSnapshotCommand cmd) {
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
@ -5623,59 +5548,61 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String backedUpSnapshotUuid = cmd.getSnapshotUuid();
String origTemplateInstallPath = cmd.getOrigTemplateInstallPath();
Long newTemplateId = cmd.getNewTemplateId();
String userSpecifiedName = cmd.getTemplateName();
// By default, assume failure
String details = "Failed to create private template " + newTemplateId + " from snapshot for volume: " + volumeId + " with backupUuid: " + backedUpSnapshotUuid;
String newTemplatePath = null;
String templateName = null;
String details = null;
SR snapshotSR = null;
SR tmpltSR = null;
boolean result = false;
long virtualSize = 0;
try {
URI uri = new URI(secondaryStoragePoolURL);
String remoteTemplateMountPath = uri.getHost() + ":" + uri.getPath() + "/template/";
String templateFolder = cmd.getAccountId() + "/" + newTemplateId + "/";
String templateDownloadFolder = createTemplateDownloadFolder(remoteTemplateMountPath, templateFolder);
String templateInstallFolder = "tmpl/" + templateFolder;
// Yes, create a template vhd
Pair<VHDInfo, String> vhdDetails = createVHDFromSnapshot(primaryStorageNameLabel, dcId, accountId, volumeId, secondaryStoragePoolURL, backedUpSnapshotUuid,
origTemplateInstallPath, templateDownloadFolder);
VHDInfo vhdInfo = vhdDetails.first();
String failureDetails = vhdDetails.second();
if (vhdInfo == null) {
if (failureDetails != null) {
details += failureDetails;
}
} else {
templateName = vhdInfo.getUuid();
String templateFilename = templateName + ".vhd";
String templateInstallPath = templateInstallFolder + "/" + templateFilename;
newTemplatePath = "template" + "/" + templateInstallPath;
virtualSize = vhdInfo.getVirtualSize();
// create the template.properties file
result = postCreatePrivateTemplate(remoteTemplateMountPath, templateDownloadFolder, templateInstallFolder, templateFilename, templateName, userSpecifiedName, null,
virtualSize, newTemplateId);
if (!result) {
details += ", reason: Could not create the template.properties file on secondary storage dir: " + templateInstallFolder;
} else {
// Aaah, success.
details = null;
}
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
String installPath = "template/tmpl/" + accountId + "/" + newTemplateId;
if( !createSecondaryStorageFolder(secondaryStorageMountPath, installPath)) {
details = " Filed to create folder " + installPath + " in secondary storage";
s_logger.warn(details);
return new CreatePrivateTemplateAnswer(cmd, false, details);
}
Connection conn = getConnection();
// create snapshot SR
URI snapshotURI = new URI(secondaryStoragePoolURL + "/snapshots/" + accountId + "/" + volumeId );
snapshotSR = createNfsSRbyURI(snapshotURI, false);
snapshotSR.scan(conn);
VDI snapshotVDI = getVDIbyUuid(backedUpSnapshotUuid);
// create template SR
URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath);
tmpltSR = createNfsSRbyURI(tmpltURI, false);
// copy snapshotVDI to template SR
VDI tmpltVDI = cloudVDIcopy(snapshotVDI, tmpltSR);
String tmpltSrUUID = tmpltSR.getUuid(conn);
String tmpltUUID = tmpltVDI.getUuid(conn);
String tmpltFilename = tmpltUUID + ".vhd";
long virtualSize = tmpltVDI.getVirtualSize(conn);
long size = tmpltVDI.getPhysicalUtilisation(conn);
// create the template.properties file
result = postCreatePrivateTemplate(tmpltSrUUID, tmpltFilename, tmpltUUID, userSpecifiedName, null, size, virtualSize, newTemplateId);
if (!result) {
throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI);
}
return new CreatePrivateTemplateAnswer(cmd, true, null, installPath, virtualSize, tmpltUUID, ImageFormat.VHD);
} catch (XenAPIException e) {
details += ", reason: " + e.getMessage();
details = "Creating template from snapshot " + backedUpSnapshotUuid + " failed due to " + e.getMessage();
s_logger.error(details, e);
} catch (Exception e) {
details += ", reason: " + e.getMessage();
details = "Creating template from snapshot " + backedUpSnapshotUuid + " failed due to " + e.getMessage();
s_logger.error(details, e);
} finally {
// Remove the secondary storage SR
removeSR(snapshotSR);
removeSR(tmpltSR);
}
return new CreatePrivateTemplateAnswer(cmd, result, details, newTemplatePath, virtualSize, templateName, ImageFormat.VHD);
return new CreatePrivateTemplateAnswer(cmd, result, details);
}
protected BackupSnapshotAnswer execute(final BackupSnapshotCommand cmd) {
@ -5687,7 +5614,6 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
String snapshotUuid = cmd.getSnapshotUuid(); // not null: Precondition.
String prevSnapshotUuid = cmd.getPrevSnapshotUuid();
String prevBackupUuid = cmd.getPrevBackupUuid();
boolean isFirstSnapshotOfRootVolume = cmd.isFirstSnapshotOfRootVolume();
// By default assume failure
String details = null;
boolean success = false;
@ -5704,27 +5630,45 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
URI uri = new URI(secondaryStoragePoolURL);
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
if (secondaryStorageMountPath == null) {
details = "Couldn't backup snapshot because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
} else {
boolean gcHappened = true;
if (gcHappened) {
snapshotBackupUuid = backupSnapshot(primaryStorageSRUuid, dcId, accountId, volumeId, secondaryStorageMountPath, snapshotUuid, prevSnapshotUuid, prevBackupUuid,
isFirstSnapshotOfRootVolume, isISCSI);
success = (snapshotBackupUuid != null);
} else {
s_logger.warn("GC hasn't happened yet for previousSnapshotUuid: " + prevSnapshotUuid + ". Will retry again after 1 min");
if (prevBackupUuid == null) {
// the first snapshot is always a full snapshot
String folder = "snapshots/" + accountId + "/" + volumeId;
if( !createSecondaryStorageFolder(secondaryStorageMountPath, folder)) {
details = " Filed to create folder " + folder + " in secondary storage";
s_logger.warn(details);
return new BackupSnapshotAnswer(cmd, success, details, snapshotBackupUuid);
}
String snapshotMountpoint = secondaryStoragePoolURL + "/" + folder;
SR snapshotSr = null;
try {
snapshotSr = createNfsSRbyURI(new URI(snapshotMountpoint), false);
VDI snapshotVdi = getVDIbyUuid(snapshotUuid);
VDI backedVdi = snapshotVdi.copy(conn, snapshotSr);
snapshotBackupUuid = backedVdi.getUuid(conn);
success = true;
} finally {
if( snapshotSr != null) {
removeSR(snapshotSr);
}
}
} else {
snapshotBackupUuid = backupSnapshot(primaryStorageSRUuid, dcId, accountId, volumeId, secondaryStorageMountPath,
snapshotUuid, prevSnapshotUuid, prevBackupUuid, isISCSI);
success = (snapshotBackupUuid != null);
}
if (!success) {
if (success) {
details = "Successfully backedUp the snapshotUuid: " + snapshotUuid + " to secondary storage.";
// Mark the snapshot as removed in the database.
// When the next snapshot is taken, it will be
// 1) deleted from the DB 2) The snapshotUuid will be deleted from the primary
// 3) the snapshotBackupUuid will be copied to secondary
// 4) if possible it will be coalesced with the next snapshot.
} else if (prevSnapshotUuid != null && !isFirstSnapshotOfRootVolume) {
if (prevSnapshotUuid != null) {
// Destroy the previous snapshot, if it exists.
// We destroy the previous snapshot only if the current snapshot
// backup succeeds.
@ -5732,8 +5676,9 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
// so that it doesn't get merged with the
// new one
// and muddle the vhd chain on the secondary storage.
details = "Successfully backedUp the snapshotUuid: " + snapshotUuid + " to secondary storage.";
destroySnapshotOnPrimaryStorage(prevSnapshotUuid);
destroySnapshotOnPrimaryStorage(prevSnapshotUuid);
}
}
} catch (XenAPIException e) {
@ -5749,93 +5694,44 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
protected CreateVolumeFromSnapshotAnswer execute(final CreateVolumeFromSnapshotCommand cmd) {
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
Long dcId = cmd.getDataCenterId();
Long accountId = cmd.getAccountId();
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String backedUpSnapshotUuid = cmd.getSnapshotUuid();
String templatePath = cmd.getTemplatePath();
// 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 = "Failed to create volume from snapshot for volume: " + volumeId + " with backupUuid: " + backedUpSnapshotUuid;
String vhdUUID = null;
SR temporarySROnSecondaryStorage = null;
String mountPointOfTemporaryDirOnSecondaryStorage = null;
String details = null;
String volumeUUID = null;
SR snapshotSR = null;
if (secondaryStoragePoolURL == null) {
details += " because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
return new CreateVolumeFromSnapshotAnswer(cmd, result, details, volumeUUID);
}
try {
VDI vdi = null;
Connection conn = getConnection();
SR primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: "
+ primaryStorageNameLabel);
}
// Get the absolute path of the snapshot on the secondary storage.
URI snapshotURI = new URI(secondaryStoragePoolURL + "/snapshots/" + accountId + "/" + volumeId );
Boolean isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
snapshotSR = createNfsSRbyURI(snapshotURI, false);
snapshotSR.scan(conn);
VDI snapshotVDI = getVDIbyUuid(backedUpSnapshotUuid);
// Get the absolute path of the template on the secondary storage.
URI uri = new URI(secondaryStoragePoolURL);
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
VDI volumeVDI = cloudVDIcopy(snapshotVDI, primaryStorageSR);
if (secondaryStorageMountPath == null) {
details += " because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
return new CreateVolumeFromSnapshotAnswer(cmd, result, details, vhdUUID);
}
volumeUUID = volumeVDI.getUuid(conn);
// Create a volume and not a template
String templateDownloadFolder = "";
VHDInfo vhdInfo = createVHDFromSnapshot(dcId, accountId, volumeId, secondaryStorageMountPath, backedUpSnapshotUuid, templatePath, templateDownloadFolder, isISCSI);
if (vhdInfo == null) {
details += " because the vmops plugin on XenServer failed at some point";
} else {
vhdUUID = vhdInfo.getUuid();
String tempDirRelativePath = "snapshots" + File.separator + accountId + File.separator + volumeId + "_temp";
mountPointOfTemporaryDirOnSecondaryStorage = secondaryStorageMountPath + File.separator + tempDirRelativePath;
result = true;
uri = new URI("nfs://" + mountPointOfTemporaryDirOnSecondaryStorage);
// No need to check if the SR already exists. It's a temporary
// SR destroyed when this method exits.
// And two createVolumeFromSnapshot operations cannot proceed at
// the same time.
temporarySROnSecondaryStorage = createNfsSRbyURI(uri, false);
if (temporarySROnSecondaryStorage == null) {
details += "because SR couldn't be created on " + mountPointOfTemporaryDirOnSecondaryStorage;
} else {
s_logger.debug("Successfully created temporary SR on secondary storage " + temporarySROnSecondaryStorage.getNameLabel(conn) + "with uuid "
+ temporarySROnSecondaryStorage.getUuid(conn) + " and scanned it");
// createNFSSRbyURI also scans the SR and introduces the VDI
vdi = getVDIbyUuid(vhdUUID);
if (vdi != null) {
s_logger.debug("Successfully created VDI on secondary storage SR " + temporarySROnSecondaryStorage.getNameLabel(conn) + " with uuid " + vhdUUID);
s_logger.debug("Copying VDI: " + vdi.getLocation(conn) + " from secondary to primary");
VDI vdiOnPrimaryStorage = cloudVDIcopy(vdi, primaryStorageSR);
// vdi.copy introduces the vdi into the database. Don't
// need to do a scan on the primary
// storage.
if (vdiOnPrimaryStorage != null) {
vhdUUID = vdiOnPrimaryStorage.getUuid(conn);
s_logger.debug("Successfully copied and introduced VDI on primary storage with path " + vdiOnPrimaryStorage.getLocation(conn) + " and uuid " + vhdUUID);
result = true;
details = null;
} else {
details += ". Could not copy the vdi " + vhdUUID + " to primary storage";
}
// The VHD on temporary was scanned and introduced as a VDI
// destroy it as we don't need it anymore.
vdi.destroy(conn);
} else {
details += ". Could not scan and introduce vdi with uuid: " + vhdUUID;
}
}
}
} catch (XenAPIException e) {
details += " due to " + e.toString();
s_logger.warn(details, e);
@ -5844,13 +5740,8 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
s_logger.warn(details, e);
} finally {
// In all cases, if the temporary SR was created, forget it.
if (temporarySROnSecondaryStorage != null) {
removeSR(temporarySROnSecondaryStorage);
// Delete the temporary directory created.
File folderPath = new File(mountPointOfTemporaryDirOnSecondaryStorage);
String remoteMountPath = folderPath.getParent();
String folder = folderPath.getName();
deleteSecondaryStorageFolder(remoteMountPath, folder);
if (snapshotSR != null) {
removeSR(snapshotSR);
}
}
if (!result) {
@ -5859,7 +5750,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
}
// In all cases return something.
return new CreateVolumeFromSnapshotAnswer(cmd, result, details, vhdUUID);
return new CreateVolumeFromSnapshotAnswer(cmd, result, details, volumeUUID);
}
protected DeleteSnapshotBackupAnswer execute(final DeleteSnapshotBackupCommand cmd) {
@ -5868,31 +5759,10 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
Long volumeId = cmd.getVolumeId();
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
String backupUUID = cmd.getSnapshotUuid();
String childUUID = cmd.getChildUUID();
String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
String details = null;
boolean success = false;
SR primaryStorageSR = null;
Boolean isISCSI = false;
try {
Connection conn = getConnection();
primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
details = "Primary Storage SR could not be created from the name label: " + primaryStorageNameLabel;
throw new InternalErrorException(details);
}
isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
} catch (XenAPIException e) {
details = "Couldn't determine primary SR type " + e.getMessage();
s_logger.error(details, e);
} catch (Exception e) {
details = "Couldn't determine primary SR type " + e.getMessage();
s_logger.error(details, e);
}
if (primaryStorageSR != null) {
URI uri = null;
try {
uri = new URI(secondaryStoragePoolURL);
@ -5906,14 +5776,13 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
if (secondaryStorageMountPath == null) {
details = "Couldn't delete snapshot because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
} else {
details = deleteSnapshotBackup(dcId, accountId, volumeId, secondaryStorageMountPath, backupUUID, childUUID, isISCSI);
details = deleteSnapshotBackup(dcId, accountId, volumeId, secondaryStorageMountPath, backupUUID);
success = (details != null && details.equals("1"));
if (success) {
s_logger.debug("Successfully deleted snapshot backup " + backupUUID);
}
}
}
}
return new DeleteSnapshotBackupAnswer(cmd, success, details);
}
@ -6134,8 +6003,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
return (result != null);
}
protected boolean postCreatePrivateTemplate(String remoteTemplateMountPath, String templateDownloadFolder, String templateInstallFolder, String templateFilename,
String templateName, String templateDescription, String checksum, long virtualSize, long templateId) {
protected boolean postCreatePrivateTemplate(String tmpltSrUUID,String tmpltFilename, String templateName, String templateDescription, String checksum, long size, long virtualSize, long templateId) {
if (templateDescription == null) {
templateDescription = "";
@ -6145,23 +6013,18 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
checksum = "";
}
String result = callHostPluginWithTimeOut("vmopsSnapshot", "post_create_private_template", 110*60, "remoteTemplateMountPath", remoteTemplateMountPath, "templateDownloadFolder", templateDownloadFolder,
"templateInstallFolder", templateInstallFolder, "templateFilename", templateFilename, "templateName", templateName, "templateDescription", templateDescription,
"checksum", checksum, "virtualSize", String.valueOf(virtualSize), "templateId", String.valueOf(templateId));
String result = callHostPluginWithTimeOut("vmopsSnapshot", "post_create_private_template", 110*60, "tmpltSrUUID", tmpltSrUUID, "templateFilename", tmpltFilename, "templateName", templateName, "templateDescription", templateDescription,
"checksum", checksum, "size", String.valueOf(size), "virtualSize", String.valueOf(virtualSize), "templateId", String.valueOf(templateId));
boolean success = false;
if (result != null && !result.isEmpty()) {
// Else, command threw an exception which has already been logged.
String[] tmp = result.split("#");
String status = tmp[0];
if (status != null && status.equalsIgnoreCase("1")) {
s_logger.debug("Successfully created template.properties file on secondary storage dir: " + templateInstallFolder);
if (result.equalsIgnoreCase("1")) {
s_logger.debug("Successfully created template.properties file on secondary storage for " + tmpltFilename);
success = true;
} else {
s_logger.warn("Could not create template.properties file on secondary storage dir: " + templateInstallFolder + " for templateId: " + templateId
+ ". Failed with status " + status);
s_logger.warn("Could not create template.properties file on secondary storage for " + tmpltFilename + " for templateId: " + templateId);
}
}
@ -6170,8 +6033,8 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
// Each argument is put in a separate line for readability.
// Using more lines does not harm the environment.
protected String backupSnapshot(String primaryStorageSRUuid, Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String snapshotUuid,
String prevSnapshotUuid, String prevBackupUuid, Boolean isFirstSnapshotOfRootVolume, Boolean isISCSI) {
protected String backupSnapshot(String primaryStorageSRUuid, Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath,
String snapshotUuid, String prevSnapshotUuid, String prevBackupUuid, Boolean isISCSI) {
String backupSnapshotUuid = null;
if (prevSnapshotUuid == null) {
@ -6185,7 +6048,7 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
// Using more lines does not harm the environment.
String results = callHostPluginWithTimeOut("vmopsSnapshot", "backupSnapshot", 110*60, "primaryStorageSRUuid", primaryStorageSRUuid, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId",
volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath, "snapshotUuid", snapshotUuid, "prevSnapshotUuid", prevSnapshotUuid, "prevBackupUuid",
prevBackupUuid, "isFirstSnapshotOfRootVolume", isFirstSnapshotOfRootVolume.toString(), "isISCSI", isISCSI.toString());
prevBackupUuid, "isISCSI", isISCSI.toString());
if (results == null || results.isEmpty()) {
// errString is already logged.
@ -6210,6 +6073,19 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
return backupSnapshotUuid;
}
protected String getVhdParent(String primaryStorageSRUuid, String snapshotUuid, Boolean isISCSI) {
String parentUuid = callHostPlugin("vmopsSnapshot", "getVhdParent", "primaryStorageSRUuid", primaryStorageSRUuid,
"snapshotUuid", snapshotUuid, "isISCSI", isISCSI.toString());
if (parentUuid == null || parentUuid.isEmpty()) {
s_logger.debug("Unable to get parent of VHD " + snapshotUuid + " in SR " + primaryStorageSRUuid);
// errString is already logged.
return null;
}
return parentUuid;
}
protected boolean destroySnapshotOnPrimaryStorage(String snapshotUuid) {
// Precondition snapshotUuid != null
try {
@ -6232,11 +6108,11 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
return false;
}
protected String deleteSnapshotBackup(Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String backupUUID, String childUUID, Boolean isISCSI) {
protected String deleteSnapshotBackup(Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String backupUUID) {
// If anybody modifies the formatting below again, I'll skin them
String result = callHostPlugin("vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "childUUID", childUUID, "dcId", dcId.toString(), "accountId", accountId.toString(),
"volumeId", volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath, "isISCSI", isISCSI.toString());
String result = callHostPlugin("vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "dcId", dcId.toString(), "accountId", accountId.toString(),
"volumeId", volumeId.toString(), "secondaryStorageMountPath", secondaryStorageMountPath);
return result;
}
@ -6249,70 +6125,6 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
return result;
}
// If anybody messes up with the formatting, I'll skin them
protected Pair<VHDInfo, String> createVHDFromSnapshot(String primaryStorageNameLabel, Long dcId, Long accountId, Long volumeId, String secondaryStoragePoolURL,
String backedUpSnapshotUuid, String templatePath, String templateDownloadFolder) throws XenAPIException, IOException, XmlRpcException, InternalErrorException,
URISyntaxException {
// Return values
String details = null;
Connection conn = getConnection();
SR primaryStorageSR = getSRByNameLabelandHost(primaryStorageNameLabel);
if (primaryStorageSR == null) {
throw new InternalErrorException("Could not create volume from snapshot " + "because the primary Storage SR could not be created from the name label: "
+ primaryStorageNameLabel);
}
Boolean isISCSI = SRType.LVMOISCSI.equals(primaryStorageSR.getType(conn));
// Get the absolute path of the template on the secondary storage.
URI uri = new URI(secondaryStoragePoolURL);
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
VHDInfo vhdInfo = null;
if (secondaryStorageMountPath == null) {
details = " because the URL passed: " + secondaryStoragePoolURL + " is invalid.";
} else {
vhdInfo = createVHDFromSnapshot(dcId, accountId, volumeId, secondaryStorageMountPath, backedUpSnapshotUuid, templatePath, templateDownloadFolder, isISCSI);
if (vhdInfo == null) {
details = " because the vmops plugin on XenServer failed at some point";
}
}
return new Pair<VHDInfo, String>(vhdInfo, details);
}
protected VHDInfo createVHDFromSnapshot(Long dcId, Long accountId, Long volumeId, String secondaryStorageMountPath, String backedUpSnapshotUuid, String templatePath,
String templateDownloadFolder, Boolean isISCSI) {
String vdiUUID = null;
String failureString = "Could not create volume from " + backedUpSnapshotUuid;
templatePath = (templatePath == null) ? "" : templatePath;
String results = callHostPluginWithTimeOut("vmopsSnapshot","createVolumeFromSnapshot", 110*60, "dcId", dcId.toString(), "accountId", accountId.toString(), "volumeId", volumeId.toString(),
"secondaryStorageMountPath", secondaryStorageMountPath, "backedUpSnapshotUuid", backedUpSnapshotUuid, "templatePath", templatePath, "templateDownloadFolder",
templateDownloadFolder, "isISCSI", isISCSI.toString());
if (results == null || results.isEmpty()) {
// Command threw an exception which has already been logged.
return null;
}
String[] tmp = results.split("#");
String status = tmp[0];
vdiUUID = tmp[1];
Long virtualSizeInMB = 0L;
if (tmp.length == 3) {
virtualSizeInMB = Long.valueOf(tmp[2]);
}
// status == "1" if and only if vdiUUID != null
// So we don't rely on status value but return vdiUUID as an indicator
// of success.
if (status != null && status.equalsIgnoreCase("1") && vdiUUID != null) {
s_logger.debug("Successfully created vhd file with all data on secondary storage : " + vdiUUID);
} else {
s_logger.debug(failureString + ". Failed with status " + status + " with vdiUuid " + vdiUUID);
}
return new VHDInfo(vdiUUID, virtualSizeInMB * MB);
}
@Override
public boolean start() {
@ -6417,30 +6229,6 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
public String pool;
}
private class VHDInfo {
private final String uuid;
private final Long virtualSize;
public VHDInfo(String uuid, Long virtualSize) {
this.uuid = uuid;
this.virtualSize = virtualSize;
}
/**
* @return the uuid
*/
public String getUuid() {
return uuid;
}
/**
* @return the virtualSize
*/
public Long getVirtualSize() {
return virtualSize;
}
}
protected String getGuestOsType(String stdType) {
return CitrixHelper.getGuestOsType(stdType);
}

View File

@ -1716,12 +1716,6 @@ public interface ManagementServer {
ResourceAllocationException,
InternalErrorException;
/**
* @param userId The Id of the user who invoked this operation.
* @param volumeId The volume for which this snapshot is being taken
* @return The properties of the snapshot taken
*/
SnapshotVO createTemplateSnapshot(Long userId, long volumeId);
/**
* Destroy a snapshot
@ -1761,7 +1755,7 @@ public interface ManagementServer {
* @return valid template if success, null otherwise
* @throws InvalidParameterValueException, ResourceAllocationException
*/
VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, long snapshotId, String name, String description) throws InvalidParameterValueException;
VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, Long snapshotId, Long volumeId, String name, String description) throws InvalidParameterValueException;
long createPrivateTemplateAsync(Long userId, long vmId, String name, String description, long guestOSId, Boolean requiresHvm, Integer bits, Boolean passwordEnabled, boolean isPublic, boolean featured, Long snapshotId) throws InvalidParameterValueException, ResourceAllocationException, InternalErrorException;

View File

@ -39,7 +39,8 @@ public interface Snapshot {
Creating,
CreatedOnPrimary,
BackingUp,
BackedUp;
BackedUp,
EmptySnapshot;
public String toString() {
return this.name();

View File

@ -79,6 +79,10 @@ public class SnapshotPolicyVO {
return schedule;
}
public void setInterval(short interval) {
this.interval = interval;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}

View File

@ -77,14 +77,22 @@ public class SnapshotScheduleVO {
return policyId;
}
/**
public void setPolicyId(long policyId) {
this.policyId = policyId;
}
/**
* @return the scheduledTimestamp
*/
public Date getScheduledTimestamp() {
return scheduledTimestamp;
}
public Long getAsyncJobId() {
public void setScheduledTimestamp(Date scheduledTimestamp) {
this.scheduledTimestamp = scheduledTimestamp;
}
public Long getAsyncJobId() {
return asyncJobId;
}

View File

@ -157,7 +157,7 @@ public class SnapshotVO implements Snapshot {
return backupSnapshotId;
}
public long getPrevSnapshotId(){
public long getPrevSnapshotId(){
return prevSnapshotId;
}
@ -169,13 +169,12 @@ public class SnapshotVO implements Snapshot {
this.prevSnapshotId = prevSnapshotId;
}
public static SnapshotType getSnapshotType(List<Long> policyIds) {
assert policyIds != null && !policyIds.isEmpty();
SnapshotType snapshotType = SnapshotType.RECURRING;
if (policyIds.contains(MANUAL_POLICY_ID)) {
snapshotType = SnapshotType.MANUAL;
public static SnapshotType getSnapshotType(Long policyId) {
if (policyId.equals(MANUAL_POLICY_ID)) {
return SnapshotType.MANUAL;
} else {
return SnapshotType.RECURRING;
}
return snapshotType;
}
public static SnapshotType getSnapshotType(String snapshotType) {

View File

@ -32,4 +32,5 @@ public interface SnapshotPolicyDao extends GenericDao<SnapshotPolicyVO, Long> {
List<SnapshotPolicyVO> listByVolumeId(long volumeId, Filter filter);
SnapshotPolicyVO findOneByVolumeInterval(long volumeId, short interval);
List<SnapshotPolicyVO> listActivePolicies();
SnapshotPolicyVO findOneByVolume(long volumeId);
}

View File

@ -43,6 +43,14 @@ public class SnapshotPolicyDaoImpl extends GenericDaoBase<SnapshotPolicyVO, Long
return findOneIncludingRemovedBy(sc);
}
@Override
public SnapshotPolicyVO findOneByVolume(long volumeId) {
SearchCriteria<SnapshotPolicyVO> sc = VolumeIdSearch.create();
sc.setParameters("volumeId", volumeId);
sc.setParameters("active", true);
return findOneBy(sc);
}
@Override
public List<SnapshotPolicyVO> listByVolumeId(long volumeId) {
return listByVolumeId(volumeId, null);

View File

@ -22,6 +22,7 @@ package com.cloud.storage.dao;
import java.util.Date;
import java.util.List;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.utils.db.GenericDao;
@ -36,4 +37,6 @@ public interface SnapshotScheduleDao extends GenericDao<SnapshotScheduleVO, Long
SnapshotScheduleVO getCurrentSchedule(Long volumeId, Long policyId, boolean executing);
SnapshotScheduleVO findOneByVolume(long volumeId);
}

View File

@ -26,6 +26,7 @@ import java.util.List;
import javax.ejb.Local;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
@ -36,6 +37,7 @@ import com.cloud.utils.db.SearchCriteria;
public class SnapshotScheduleDaoImpl extends GenericDaoBase<SnapshotScheduleVO, Long> implements SnapshotScheduleDao {
protected final SearchBuilder<SnapshotScheduleVO> executableSchedulesSearch;
protected final SearchBuilder<SnapshotScheduleVO> coincidingSchedulesSearch;
private final SearchBuilder<SnapshotScheduleVO> VolumeIdSearch;
// DB constraint: For a given volume and policyId, there will only be one entry in this table.
@ -52,6 +54,10 @@ public class SnapshotScheduleDaoImpl extends GenericDaoBase<SnapshotScheduleVO,
coincidingSchedulesSearch.and("asyncJobId", coincidingSchedulesSearch.entity().getAsyncJobId(), SearchCriteria.Op.NULL);
coincidingSchedulesSearch.done();
VolumeIdSearch = createSearchBuilder();
VolumeIdSearch.and("volumeId", VolumeIdSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
VolumeIdSearch.done();
}
/**
@ -67,6 +73,13 @@ public class SnapshotScheduleDaoImpl extends GenericDaoBase<SnapshotScheduleVO,
return listBy(sc);
}
@Override
public SnapshotScheduleVO findOneByVolume(long volumeId) {
SearchCriteria<SnapshotScheduleVO> sc = VolumeIdSearch.create();
sc.setParameters("volumeId", volumeId);
return findOneBy(sc);
}
/**
* {@inheritDoc}
*/

View File

@ -10,19 +10,12 @@ from util import CommandException
import vhdutil
import shutil
import lvhdutil
import subprocess
from lvmcache import LVMCache
from journaler import Journaler
from lock import Lock
import errno
import subprocess
import xs_errors
import cleanup
import hostvmstats
import socket
import stat
import random
import tempfile
VHD_UTIL = '/usr/sbin/vhd-util'
VHD_PREFIX = 'VHD-'
@ -107,85 +100,55 @@ def delete_secondary_storage_folder(session, args):
return "1"
@echo
def execute_script(session, args):
return ""
@echo
def post_create_private_template(session, args):
local_mount_path = None
try:
try:
# Mount the remote templates folder locally
remote_mount_path = args["remoteTemplateMountPath"]
local_mount_path = os.path.join(SR.MOUNT_BASE, "template" + str(int(random.random() * 10000)))
mount(remote_mount_path, local_mount_path)
util.SMlog("Mounted secondary storage template folder")
# 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"]
virtual_size = args["virtualSize"]
template_id = args["templateId"]
# 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_download_folder = local_mount_path + "/" + args["templateDownloadFolder"]
template_download_path = template_download_folder + filename
file_size = os.path.getsize(template_download_path)
util.SMlog("Got template file_size: " + str(file_size))
# 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_download_path = template_download_folder + "template.properties"
f = open(template_properties_download_path, "w")
f.write("filename=" + filename + "\n")
f.write("name=" + filename + "\n")
f.write("vhd=true\n")
f.write("id=" + template_id + "\n")
f.write("vhd.filename=" + filename + "\n")
f.write("uniquename=" + name + "\n")
f.write("vhd.virtualsize=" + virtual_size + "\n")
f.write("vhd.size=" + str(file_size) + "\n")
f.write("virtualsize=" + virtual_size + "\n")
f.write("checksum=" + checksum + "\n")
f.write("hvm=true\n")
f.write("description=" + name + "\n")
f.close()
util.SMlog("Created template.properties file")
# 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("name=" + filename + "\n")
f.write("vhd=true\n")
f.write("id=" + template_id + "\n")
f.write("vhd.filename=" + filename + "\n")
f.write("uniquename=" + name + "\n")
f.write("vhd.virtualsize=" + virtual_size + "\n")
f.write("vhd.size=" + str(file_size) + "\n")
f.write("virtualsize=" + virtual_size + "\n")
f.write("checksum=" + checksum + "\n")
f.write("hvm=true\n")
f.write("description=" + name + "\n")
f.close()
util.SMlog("Created template.properties file")
# Create the template install folder if necessary
template_install_folder = local_mount_path + "/" + args["templateInstallFolder"]
if not os.path.isdir(template_install_folder):
current_umask = os.umask(0)
os.makedirs(template_install_folder)
os.umask(current_umask)
# 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")
# Move the template and the template.properties file to the install folder
os.system("mv " + template_download_folder + "/" + filename + " " + template_install_folder)
os.system("mv " + template_download_folder + "/template.properties " + template_install_folder)
template_install_path = template_install_folder + filename
template_properties_install_path = template_install_folder + "template.properties"
# Set permissions
permissions = stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH
os.chmod(template_install_path, permissions)
os.chmod(template_properties_install_path, permissions)
util.SMlog("Set permissions on template and template.properties")
# Delete the template download folder
os.system("rm -rf " + template_download_folder)
except:
errMsg = "post_create_private_template failed."
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
finally:
if local_mount_path != None:
# Unmount the local templates folder
umount(local_mount_path)
# Remove the local templates folder
os.system("rm -rf " + local_mount_path)
except:
errMsg = "post_create_private_template failed."
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
return "1"
@ -237,19 +200,6 @@ def chdir(path):
util.SMlog("Chdired to " + path)
return
def coalesce(vhdPath):
util.SMlog("Starting to coalesce " + vhdPath + " with its parent")
try :
cmd = [VHD_UTIL, "coalesce", "-n", vhdPath]
txt = util.pread2(cmd)
except:
errMsg = "Unexpected error while trying to coalesce " + vhdPath + " to its parent"
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
util.SMlog("Successfully coalesced " + vhdPath + " with its parent ")
return
def scanParent(path):
# Do a scan for the parent for ISCSI volumes
# Note that the parent need not be visible on the XenServer
@ -313,30 +263,14 @@ def rename(originalVHD, newVHD):
raise xs_errors.XenError(errMsg)
return
def coalesceToChild(backupVHD, childUUID, isISCSI):
# coalesce childVHD with its parent
childVHD = getVHD(childUUID, isISCSI)
util.SMlog("childVHD: " + childVHD)
# check for existence of childVHD
isfile(childVHD, False)
util.SMlog("childVHD " + childVHD + " exists")
# No exception thrown, file exists
coalesce(childVHD)
# rename the existing backupVHD file to childVHD
# childVHD file automatically gets overwritten
rename(backupVHD, childVHD)
# parent of the newly coalesced file still remains the same.
# child of childVHD has it's parent name still set to childVHD.
# So the VHD chain hasn't been broken.
return
def makedirs(path):
if not os.path.isdir(path):
try:
os.makedirs(path)
except OSError, (errno, strerror):
umount(path)
if os.path.isdir(path):
return
errMsg = "OSError while creating " + path + " with errno: " + str(errno) + " and strerr: " + strerror
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
@ -358,42 +292,17 @@ def mount(remoteDir, localDir):
return
def umount(localDir):
success = False
if os.path.isdir(localDir) and os.path.ismount(localDir):
try:
cmd = ['umount', localDir]
util.pread2(cmd)
except CommandException:
errMsg = "CommandException raised while trying to umount " + localDir
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
util.SMlog("Successfully unmounted " + localDir)
success = True
else:
util.SMlog("LocalDir: " + localDir + " doesn't exist or is not a mount point")
try:
cmd = ['umount', localDir]
util.pread2(cmd)
except CommandException:
errMsg = "CommandException raised while trying to umount " + localDir
util.SMlog(errMsg)
return
util.SMlog("Successfully unmounted " + localDir)
return
def mountTemplatesDir(secondaryStorageMountPath, templatePath):
# Aim is to mount <secondaryStorageMountPath>/<templatePath> on
# SR.MOUNT_BASE/<random_uuid>
# It will be unmounted after createVolumeFromSnapshot finishes.
# It should be mounted read-only, but don't know how to do that
# The random-uuid saves us from conflicts while restoring two different root volumes
absoluteTemplatePath = os.path.join(secondaryStorageMountPath, templatePath)
absoluteTemplateDir = os.path.dirname(absoluteTemplatePath)
randomUUID = util.gen_uuid()
localTemplateDir = os.path.join(SR.MOUNT_BASE, randomUUID)
# create the temp dir
makedirs(localTemplateDir)
# mount
mount(absoluteTemplateDir, localTemplateDir)
return localTemplateDir
def mountSnapshotsDir(secondaryStorageMountPath, relativeDir, dcId, accountId, instanceId):
# The aim is to mount secondaryStorageMountPath on
# SR.MOUNT_BASE/<dcId>/<relativeDir>
@ -445,6 +354,9 @@ def getPrimarySRPath(primaryStorageSRUuid, isISCSI):
else:
return os.path.join(SR.MOUNT_BASE, primaryStorageSRUuid)
def getBackupVHD(UUID):
return UUID + '.' + SR.DEFAULT_TAP
def getVHD(UUID, isISCSI):
if isISCSI:
return VHD_PREFIX + UUID
@ -529,122 +441,20 @@ def isVolumeAvailable(path):
return (status == "1")
def getLastSnapshotUuid(volumeUuid, expectedLastSnapshotUuid):
actualLastSnapshotUuid = ''
if volumeUuid:
cmd = ['xe', 'vdi-param-get', 'uuid=' + volumeUuid, 'param-name=snapshots']
stdout = ''
try:
stdout = util.pread2(cmd)
except: #CommandException, (rc, cmdListStr, stderr):
#errMsg = "CommandException thrown while executing: " + cmdListStr + " with return code: " + str(rc) + " and stderr: " + stderr
errMsg = "Unexpected error while executing cmd: " + str(cmd)
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
if stdout:
snapshots = stdout.split(';')
if len(snapshots) == 1:
if snapshots[0] == expectedLastSnapshotUuid:
actualLastSnapshotUuid = expectedLastSnapshotUuid
elif len(snapshots) == 2:
# We expect only 1 snapshot to be present. If there is another that is unexpected and the last one
if (expectedLastSnapshotUuid == snapshots[0].strip()):
actualLastSnapshotUuid = snapshots[1].strip()
else:
# it should be equal to snapshots[1]. Else I have no idea.
actualLastSnapshotUuid = snapshots[0].strip()
else:
# len(snapshots) > 2:
errMsg = "Volume: " + volumeUuid + " has more than 2 snapshots: " + str(snapshots)
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
return actualLastSnapshotUuid
@echo
def validateSnapshot(session, args):
util.SMlog("Called validateSnapshot with " + str(args))
primaryStorageSRUuid = args['primaryStorageSRUuid']
volumeUuid = args['volumeUuid']
firstBackupUuid = args['firstBackupUuid']
previousSnapshotUuid = args['previousSnapshotUuid']
templateUuid = args['templateUuid']
isISCSI = getIsTrueString(args['isISCSI'])
def getVhdParent(session, args):
util.SMlog("getParent with " + str(args))
primaryStorageSRUuid = args['primaryStorageSRUuid']
snapshotUuid = args['snapshotUuid']
isISCSI = getIsTrueString(args['isISCSI'])
primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI)
util.SMlog("primarySRPath: " + primarySRPath)
volumeVHD = getVHD(volumeUuid, isISCSI)
volumePath = os.path.join(primarySRPath, volumeVHD)
util.SMlog("volumePath: " + volumePath)
baseCopyUuid = ''
wasVolumeAvailable = True
if isISCSI:
wasVolumeAvailable = isVolumeAvailable(volumePath)
if not wasVolumeAvailable:
# make it available
checkVolumeAvailablility(volumePath)
baseCopyUuid = scanParent(volumePath)
else:
baseCopyUuid = getParent(volumePath, isISCSI)
baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI)
if baseCopyUuid is None:
# Make it an empty string so that it can be used in the return value
baseCopyUuid = ''
return baseCopyUuid
actualSnapshotUuid = getLastSnapshotUuid(volumeUuid, previousSnapshotUuid)
expectedActual = firstBackupUuid + "#" + baseCopyUuid + "#" + actualSnapshotUuid
if firstBackupUuid:
# This is not the first snapshot
if baseCopyUuid and (baseCopyUuid == firstBackupUuid):
retval = "1#"
else:
retval = "0#"
else:
if templateUuid:
# The DB thinks this is the first snapshot of a ROOT DISK
# The parent of the volume should be the base template, which is also the parent of the given templateUuid.
templateVHD = getVHD(templateUuid, isISCSI)
templatePath = os.path.join(primarySRPath, templateVHD)
baseTemplateUuid = ''
wasTemplateAvailable = True
if isISCSI:
wasTemplateAvailable = isVolumeAvailable(templatePath)
if not wasVolumeAvailable:
# make it available
checkVolumeAvailablility(templatePath)
baseTemplateUuid = scanParent(templatePath)
else:
baseTemplateUuid = getParent(templatePath, isISCSI)
if baseTemplateUuid is None:
# This will never happen.
baseTemplateUuid = ''
expectedActual = baseTemplateUuid + "#" + baseCopyUuid + "#" + actualSnapshotUuid
if baseTemplateUuid and (baseCopyUuid == baseTemplateUuid):
retval = "1#"
else:
retval = "0#"
if isISCSI and not wasTemplateAvailable:
manageAvailability(templatePath, '-an')
else:
# The DB thinks this is the first snapshot of a DATA DISK.
# The volume VDI should not have any parent.
if not baseCopyUuid:
retval = "1#"
else:
retval = "0#"
# Set the volume's visibility back to what it was.
if isISCSI and not wasVolumeAvailable:
manageAvailability(volumePath, '-an')
return retval + expectedActual
@echo
def backupSnapshot(session, args):
util.SMlog("Called backupSnapshot with " + str(args))
primaryStorageSRUuid = args['primaryStorageSRUuid']
@ -655,7 +465,6 @@ def backupSnapshot(session, args):
snapshotUuid = args['snapshotUuid']
prevSnapshotUuid = args['prevSnapshotUuid']
prevBackupUuid = args['prevBackupUuid']
isFirstSnapshotOfRootVolume = getIsTrueString(args['isFirstSnapshotOfRootVolume'])
isISCSI = getIsTrueString(args['isISCSI'])
primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI)
@ -675,28 +484,23 @@ def backupSnapshot(session, args):
# on it.
backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
util.SMlog("Backups dir " + backupsDir)
# chdir to the backupsDir for convenience
chdir(backupsDir)
if baseCopyUuid == prevBaseCopyUuid:
# There has been no change since the last snapshot so no need to backup
util.SMlog("There has been no change since the last snapshot with backup: " + prevBaseCopyUuid)
if isFirstSnapshotOfRootVolume:
# baseCopyUuid is template. That is *NOT* the backup of any
# snapshot. There is no backup. So create an empty dummyVHD representing the empty snapshot.
# This will prevent deleteSnapshotBackup and createVolumeFromSnapshot from breaking.
prevBaseCopyUuid = createDummyVHD(baseCopyPath, backupsDir, isISCSI)
# The backup snapshot is the new dummy VHD created.
# Set the uuid of the current backup to that of last backup
txt = "1#" + prevBaseCopyUuid
return txt
# Check existence of snapshot on primary storage
isfile(baseCopyPath, isISCSI)
# copy baseCopyPath to backupsDir
backupFile = os.path.join(backupsDir, baseCopyVHD)
# copy baseCopyPath to backupsDir with new uuid
backupUuid = util.gen_uuid()
backupVHD = getBackupVHD(backupUuid)
backupFile = os.path.join(backupsDir, backupVHD)
util.SMlog("Back up " + baseCopyUuid + " to Secondary Storage as " + backupUuid)
copyfile(baseCopyPath, backupFile, isISCSI)
vhdutil.setHidden(backupFile, False)
# Now set the availability of the snapshotPath and the baseCopyPath to false
makeUnavailable(snapshotUuid, primarySRPath, isISCSI)
@ -705,44 +509,18 @@ def backupSnapshot(session, args):
makeUnavailable(prevSnapshotUuid, primarySRPath, isISCSI)
makeUnavailable(prevBaseCopyUuid, primarySRPath, isISCSI)
if isFirstSnapshotOfRootVolume:
# First snapshot of the root volume.
# It's parent is not null, but the template vhd.
# Create a dummy empty vhd and set the parent of backupVHD to it.
# This will prevent deleteSnapshotBackup and createVolumeFromSnapshot from breaking
prevBackupUuid = createDummyVHD(baseCopyPath, backupsDir, isISCSI)
# Because the primary storage is always scanned, the parent of this base copy is always the first base copy.
# We don't want that, we want a chain of VHDs each of which is a delta from the previous.
# So set the parent of the current baseCopyVHD to prevBackupVHD
if prevBackupUuid:
# If there was a previous snapshot
prevBackupVHD = getVHD(prevBackupUuid, isISCSI)
setParent(prevBackupVHD, backupFile)
prevBackupVHD = getBackupVHD(prevBackupUuid)
prevBackupFile = os.path.join(backupsDir, prevBackupVHD)
setParent(prevBackupFile, backupFile)
txt = "1#" + baseCopyUuid
txt = "1#" + backupUuid
return txt
def createDummyVHD(baseCopyPath, backupsDir, isISCSI):
dummyUUID = ''
try:
dummyUUID = util.gen_uuid()
dummyVHD = getVHD(dummyUUID, isISCSI)
if isISCSI:
checkVolumeAvailablility(baseCopyPath)
cmd = [VHD_UTIL, 'query', '-v', '-n', baseCopyPath]
virtualSizeInMB = util.pread2(cmd)
util.SMlog("Virtual size of " + baseCopyPath + " is " + virtualSizeInMB)
cmd = [VHD_UTIL, 'create', '-n', dummyVHD, '-s', virtualSizeInMB]
util.pread2(cmd)
except CommandException:
errMsg = "Unexpected error while creating a dummy VHD " + dummyVHD + " on " + backupsDir
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
util.SMlog("Successfully created a new dummy VHD: " + dummyVHD + " on " + backupsDir)
return dummyUUID
@echo
def deleteSnapshotBackup(session, args):
util.SMlog("Calling deleteSnapshotBackup with " + str(args))
@ -751,14 +529,12 @@ def deleteSnapshotBackup(session, args):
volumeId = args['volumeId']
secondaryStorageMountPath = args['secondaryStorageMountPath']
backupUUID = args['backupUUID']
childUUID = args['childUUID']
isISCSI = getIsTrueString(args['isISCSI'])
backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
# chdir to the backupsDir for convenience
chdir(backupsDir)
backupVHD = getVHD(backupUUID, isISCSI)
backupVHD = getBackupVHD(backupUUID)
util.SMlog("checking existence of " + backupVHD)
# The backupVHD is on secondary which is NFS and not ISCSI.
@ -767,211 +543,16 @@ def deleteSnapshotBackup(session, args):
return "1"
util.SMlog("backupVHD " + backupVHD + " exists.")
# Case 1) childUUID exists
if childUUID:
coalesceToChild(backupVHD, childUUID, isISCSI)
else:
# Just delete the backupVHD
try:
os.remove(backupVHD)
except OSError, (errno, strerror):
errMsg = "OSError while removing " + backupVHD + " with errno: " + str(errno) + " and strerr: " + strerror
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
# Just delete the backupVHD
try:
os.remove(backupVHD)
except OSError, (errno, strerror):
errMsg = "OSError while removing " + backupVHD + " with errno: " + str(errno) + " and strerr: " + strerror
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
return "1"
@echo
def createVolumeFromSnapshot(session, args):
util.SMlog("Calling createVolumeFromSnapshot with " + str(args))
dcId = args['dcId']
accountId = args['accountId']
volumeId = args['volumeId']
secondaryStorageMountPath = args['secondaryStorageMountPath']
backedUpSnapshotUuid = args['backedUpSnapshotUuid']
templatePath = args['templatePath']
templateDownloadFolder = args['templateDownloadFolder']
isISCSI = getIsTrueString(args['isISCSI'])
backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
util.SMlog("Backups dir " + backupsDir)
# chdir to the backupsDir for convenience
chdir(backupsDir)
# Get the parent VHD chain of the backupSnapshotVHD
vhdChain = []
uuid = backedUpSnapshotUuid
while uuid is not None:
util.SMlog("Current uuid in parent chain " + uuid)
vhd = getVHD(uuid, isISCSI)
vhdChain.append(vhd)
uuid = getParent(vhd, isISCSI)
util.SMlog("successfully created the parent chain " + str(vhdChain))
destDirParent = ''
destDir = ''
if templateDownloadFolder:
# Copy all the vhds to the final destination templates dir
# It is some random directory on the primary created for templates.
destDirParent = os.path.join(SR.MOUNT_BASE, "mount" + str(int(random.random() * 1000000)))
destDir = os.path.join(destDirParent, templateDownloadFolder)
# create the this directory, if it isn't there
makedirs(destDir)
else:
# Copy all the vhds to a temp directory
# Create a temp directory
destDir = backupsDir + '_temp'
# Delete the temp directory if it already exists (from a previous createVolumeFromSnapshot)
rmtree(destDir)
if templateDownloadFolder:
# The destDir was created in create_secondary_storage_folder but is not mounted on the primary. Mount it again.
remoteMountPoint = os.path.join(secondaryStorageMountPath, "template");
remoteMountPoint = os.path.join(remoteMountPoint, templateDownloadFolder)
mount(remoteMountPoint, destDir)
else:
# The parent of the destDir is the snapshots dir and is mounted on the primary. Just create the directory structure.
makedirs(destDir)
# Copy
for vhd in vhdChain:
vhdPath = os.path.join(backupsDir, vhd)
tempFile = os.path.join(destDir, vhd)
# We are copying files on secondary storage which is NFS. Set isISCSI to false
copyfile(vhdPath, tempFile, False)
util.SMlog("Successfully copied all files")
# coalesce the vhd chains from bottom to top
# chdir to destDir for convenience
chdir(destDir)
# coalesce
i = 0
finalVhd = vhdChain[0]
for vhd in vhdChain:
finalVhd = vhdChain[i]
last = len(vhdChain) - 1
if i == last:
# last vhd, has no parent. Don't coalesce
break
if templatePath and i == (last - 1):
# Hack for root disks, the first Vhd is a dummy one.
# Do not coalesce the actual disk with the dummy one.
# Instead coalesce it with the templateVHD.
break
i = i + 1
# They are arranged from child to parent.
util.SMlog("Starting to coalesce " + vhd + " with its parent")
try:
cmd = [VHD_UTIL, "coalesce", "-n", vhd]
txt = util.pread2(cmd)
except:
errMsg = "Unexpected error while trying to coalesce " + vhd + " to its parent"
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
util.SMlog("Successfully coalesced " + vhd + " with its parent")
# Remove the child vhd
try:
os.remove(vhd)
except OSError, (errno, strerror):
errMsg = "OSError while removing " + vhd + " with errno: " + str(errno) + " and strerr: " + strerror
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
util.SMlog("successfully coalesced all vhds to the parent " + finalVhd)
finalVhdPath = os.path.join(destDir, finalVhd)
# This vhd has to be introduced with a new uuid because of the VDI UUID
# uniqueness constraint
newUUID = ''
try:
newUUID = util.gen_uuid()
except:
errMsg = "Unexpected error while trying to generate a uuid"
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
util.SMlog("generated a uuid " + newUUID)
# Now, at the Java layer an NFS SR is created with mount point destDir and scanned. The vhd
# file is automatically introduced and a vdi.copy is done to move it to
# primary storage.
# new vhd file is created on NFS. So it should have NFS naming convention,
# set isISCSI to false
newVhd = getVHD(newUUID, False)
rename(finalVhd, newVhd)
# For root disk
if templatePath:
# This will create a vhd on secondary storage destDir with name newVhd
mergeTemplateAndSnapshot(secondaryStorageMountPath, templatePath, destDir, newVhd, isISCSI)
# set the hidden flag of the new VHD to false, so that it doesn't get deleted when the SR scan is done.
try:
vhdutil.setHidden(newVhd, False)
except:
errMsg = "Unexpected error while trying to set Hidden flag of " + newVhd
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
util.SMlog("Successfully set hidden flag of " + newVhd)
virtualSizeInMB = 0
try:
cmd = [VHD_UTIL, 'query', '-v', '-n', newVhd]
virtualSizeInMB = util.pread2(cmd)
util.SMlog("Virtual size of " + newVhd + " is " + virtualSizeInMB)
except:
errMsg = "Unexpected error while trying to get the virtual size of " + newVhd
util.SMlog(errMsg)
raise xs_errors.XenError(errMsg)
if templateDownloadFolder:
# We are done with the destDir on the primary, unmount it and delete the random directory.
# Current dir is destDir
# cd to something else before unmounting
chdir(backupsDir) # as good as anything else
# unmount what was mounted.
umount(destDir)
# Remove the tree starting from the mountXXXX part, just the directories
rmtree(destDirParent)
# The coalesced data is still available on the secondary.
return "1#" + newUUID + "#" + virtualSizeInMB
def mergeTemplateAndSnapshot(secondaryStorageMountPath, templatePath, destDir, newVhd, isISCSI):
# Mount the template directory present on the secondary to the primary
templateDirOnPrimary = mountTemplatesDir(secondaryStorageMountPath, templatePath)
# Current dir is destDir
templateVHD = os.path.basename(templatePath)
templatePathOnPrimary = os.path.join(templateDirOnPrimary, templateVHD)
templatePathOnTemp = os.path.join(destDir, templateVHD)
# Copying from secondary to secondary, so set ISCSI to False
copyfile(templatePathOnPrimary, templatePathOnTemp, False)
# unmount the temporary directory created for copying the template
umount(templateDirOnPrimary)
# get the dummyVHD which is the parent of the new Vhd
dummyUUID = getParent(newVhd, isISCSI)
dummyVHD = getVHD(dummyUUID, isISCSI)
# set the parent of the newVhd to the templateVHD on secondary
setParent(templateVHD, newVhd)
# remove the dummyVHD as we don't have any use for it and it wil
# lie around after we do an SR scan
os.remove(dummyVHD)
# coalesce the two VHDs into templateVHD
coalesce(newVhd)
# rename templateVHD to newVhd
rename(templateVHD, newVhd)
return
def rmtree(path):
if os.path.isdir(path):
try:
@ -1000,5 +581,5 @@ def deleteSnapshotsDir(session, args):
return "1"
if __name__ == "__main__":
XenAPIPlugin.dispatch({"create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "createVolumeFromSnapshot": createVolumeFromSnapshot, "unmountSnapshotsDir": unmountSnapshotsDir, "deleteSnapshotsDir": deleteSnapshotsDir, "validateSnapshot" : validateSnapshot})
XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir, "deleteSnapshotsDir": deleteSnapshotsDir})

View File

@ -91,8 +91,7 @@ public class AsyncJobManagerImpl implements AsyncJobManager {
@Override @DB
public long submitAsyncJob(AsyncJobVO job, boolean scheduleJobExecutionInContext) {
if(s_logger.isDebugEnabled())
s_logger.debug("submit async job-" + job.getId() + ", details: " + job.toString());
AsyncJobExecutor executor = getJobExecutor(job);
if(executor == null) {
@ -108,6 +107,9 @@ public class AsyncJobManagerImpl implements AsyncJobManager {
executor.setSyncSource(null);
executor.setJob(job);
scheduleExecution(executor, scheduleJobExecutionInContext);
if(s_logger.isDebugEnabled()) {
s_logger.debug("submit async job-" + job.getId() + ", details: " + job.toString());
}
return job.getId();
} catch(Exception e) {
s_logger.error("Unexpected exception: ", e);

View File

@ -116,49 +116,24 @@ public class CreatePrivateTemplateExecutor extends VolumeOperationExecutor {
asyncMgr.updateAsyncJobAttachment(job.getId(), "vm_template", template.getId());
asyncMgr.updateAsyncJobStatus(job.getId(), BaseCmd.PROGRESS_INSTANCE_CREATED, template.getId());
Snapshot snapshot = null;
if (snapshotId == null) {
// We are create private template from volume. Create a snapshot, copy the vhd chain of the disk to secondary storage.
// For template snapshot, we use a separate snapshot method.
snapshot = vmMgr.createTemplateSnapshot(param.getUserId(), param.getVolumeId());
}
else {
// We are creating a private template from an already present snapshot.
// This snapshot is already backed up on secondary storage.
snapshot = managerServer.findSnapshotById(snapshotId);
}
template = managerServer.createPrivateTemplate(template, param.getUserId(), snapshotId, volumeId, param.getName(), param.getDescription());
if (snapshot == null) {
details += ", reason: Failed to create snapshot for basis of private template";
} else {
param.setSnapshotId(snapshot.getId());
template = managerServer.createPrivateTemplate(template,
param.getUserId(),
param.getSnapshotId(),
param.getName(),
param.getDescription());
if(template != null) {
VMTemplateHostVO templateHostRef = managerServer.findTemplateHostRef(template.getId(), volume.getDataCenterId());
jobStatus = AsyncJobResult.STATUS_SUCCEEDED;
resultCode = 0;
details = null;
String eventParams = "id="+template.getId()+"\nname=" + template.getName() +"\nsize="+volume.getSize()+ "\ndcId="+volume.getDataCenterId();
managerServer.saveEvent(param.getUserId(), param.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_TEMPLATE_CREATE, "Successfully created Template " +param.getName(), eventParams ,param.getEventId());
resultObject = composeResultObject(template, templateHostRef, volume.getDataCenterId());
}
// Irrespective of whether the template was created or not,
// cleanup the snapshot taken for this template. (If this template is created from a volume and not a snapshot)
if(snapshotId == null) {
// Template was created from volume
// and snapshot is not null.
managerServer.destroyTemplateSnapshot(param.getUserId(), snapshot.getId());
}
if (template != null) {
VMTemplateHostVO templateHostRef = managerServer.findTemplateHostRef(template.getId(),
volume.getDataCenterId());
jobStatus = AsyncJobResult.STATUS_SUCCEEDED;
resultCode = 0;
details = null;
String eventParams = "id=" + template.getId() + "\nname=" + template.getName() + "\nsize="
+ volume.getSize() + "\ndcId=" + volume.getDataCenterId();
managerServer.saveEvent(param.getUserId(), param.getAccountId(), EventVO.LEVEL_INFO,
EventTypes.EVENT_TEMPLATE_CREATE, "Successfully created Template "
+ param.getName(), eventParams, param.getEventId());
resultObject = composeResultObject(template, templateHostRef, volume.getDataCenterId());
}
}
}
}
} catch (InvalidParameterValueException e) {
details += ", reason: " + e.getMessage();

View File

@ -33,6 +33,7 @@ import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.Snapshot.SnapshotType;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.user.Account;
import com.google.gson.Gson;
@ -54,8 +55,10 @@ public class CreateSnapshotExecutor extends BaseAsyncJobExecutor {
} else {
SnapshotOperationParam param = gson.fromJson(job.getCmdInfo(), SnapshotOperationParam.class);
SnapshotManager snapshotManager = asyncMgr.getExecutorContext().getSnapshotMgr();
VolumeDao volumeDao = asyncMgr.getExecutorContext().getVolumeDao();
long volumeId = param.getVolumeId();
List<Long> policyIds = param.getPolicyIds();
long policyId = param.getPolicyId();
long snapshotId = 0;
long userId = param.getUserId();
@ -65,34 +68,48 @@ public class CreateSnapshotExecutor extends BaseAsyncJobExecutor {
int result = AsyncJobResult.STATUS_FAILED;
int errorCode = BaseCmd.INTERNAL_ERROR;
Object resultObject = "Failed to create snapshot.";
VolumeVO vol = null;
try {
SnapshotVO snapshot = snapshotManager.createSnapshot(userId, param.getVolumeId(), param.getPolicyIds());
vol = volumeDao.acquire(volumeId, 10);
if( vol != null) {
SnapshotVO snapshot = snapshotManager.createSnapshot(userId, volumeId, policyId);
if (snapshot != null && snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary) {
snapshotId = snapshot.getId();
asyncMgr.updateAsyncJobStatus(jobId, BaseCmd.PROGRESS_INSTANCE_CREATED, snapshotId);
backedUp = snapshotManager.backupSnapshotToSecondaryStorage(userId, snapshot);
if (backedUp) {
result = AsyncJobResult.STATUS_SUCCEEDED;
errorCode = 0; // Success
resultObject = composeResultObject(snapshot);
}
else {
// More specific error
resultObject = "Created snapshot: " + snapshotId + " on primary but failed to backup on secondary";
}
}
if (snapshot != null && snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary) {
snapshotId = snapshot.getId();
asyncMgr.updateAsyncJobStatus(jobId, BaseCmd.PROGRESS_INSTANCE_CREATED, snapshotId);
backedUp = snapshotManager.backupSnapshotToSecondaryStorage(userId, snapshot);
if (backedUp) {
result = AsyncJobResult.STATUS_SUCCEEDED;
errorCode = 0; // Success
resultObject = composeResultObject(snapshot);
}
else {
// More specific error
resultObject = "Created snapshot: " + snapshotId + " on primary but failed to backup on secondary";
}
} else if (snapshot != null && snapshot.getStatus() == Snapshot.Status.EmptySnapshot) {
resultObject ="There is no change since last snapshot, please use last snapshot";
s_logger.warn(resultObject);
}
} else {
resultObject = "Another snapshot is being created for " + volumeId + " try another time ";
s_logger.warn(resultObject);
}
} catch(Exception e) {
resultObject = "Unable to create snapshot: " + e.getMessage();
s_logger.warn(resultObject, e);
} finally {
if( vol != null ){
volumeDao.release(volumeId);
}
}
// In all cases, ensure that we call completeAsyncJob to the asyncMgr.
asyncMgr.completeAsyncJob(jobId, result, errorCode, resultObject);
// Cleanup jobs to do after the snapshot has been created.
snapshotManager.postCreateSnapshot(userId, volumeId, snapshotId, policyIds, backedUp);
snapshotManager.postCreateSnapshot(userId, volumeId, snapshotId, policyId, backedUp);
return true;
}
}

View File

@ -25,7 +25,6 @@ public class SnapshotOperationParam {
private long accountId;
private long userId;
private long snapshotId = 0;
private List<Long> policyIds = null;
private long policyId = 0;
private long volumeId;
private String name = null;
@ -44,11 +43,11 @@ public class SnapshotOperationParam {
}
// Used to create a snapshot
public SnapshotOperationParam(long userId, long accountId, long volumeId, List<Long> policyIds) {
public SnapshotOperationParam(long userId, long accountId, long volumeId, long policyId) {
setUserId(userId);
setAccountId(accountId);
setVolumeId(volumeId);
this.policyIds = policyIds;
this.policyId = policyId;
}
// Used for CreateVolumeFromSnapshot
@ -84,10 +83,6 @@ public class SnapshotOperationParam {
this.snapshotId = snapshotId;
}
public List<Long> getPolicyIds() {
return policyIds;
}
public long getPolicyId() {
return policyId;
}

View File

@ -355,7 +355,6 @@ public class ManagementServerImpl implements ManagementServer {
private final AsyncJobManager _asyncMgr;
private final TemplateManager _tmpltMgr;
private final SnapshotManager _snapMgr;
private final SnapshotScheduler _snapshotScheduler;
private final NetworkGroupManager _networkGroupMgr;
private final int _purgeDelay;
private final boolean _directAttachNetworkExternalIpAllocator;
@ -454,7 +453,6 @@ public class ManagementServerImpl implements ManagementServer {
_asyncMgr = locator.getManager(AsyncJobManager.class);
_tmpltMgr = locator.getManager(TemplateManager.class);
_snapMgr = locator.getManager(SnapshotManager.class);
_snapshotScheduler = locator.getManager(SnapshotScheduler.class);
_networkGroupMgr = locator.getManager(NetworkGroupManager.class);
_uploadMonitor = locator.getManager(UploadMonitor.class);
@ -6862,21 +6860,12 @@ public class ManagementServerImpl implements ManagementServer {
throw new InvalidParameterValueException("Snapshots of volumes attached to System or router VM are not allowed");
}
}
Long jobId = _snapshotScheduler.scheduleManualSnapshot(userId, volumeId);
if (jobId == null) {
throw new InternalErrorException("Snapshot could not be scheduled because there is another snapshot underway for the same volume. " +
"Please wait for some time.");
}
long policyId = Snapshot.MANUAL_POLICY_ID;
long jobId = _snapMgr.createSnapshotAsync(userId, volumeId, policyId);
return jobId;
}
@Override
public SnapshotVO createTemplateSnapshot(Long userId, long volumeId) {
return _vmMgr.createTemplateSnapshot(userId, volumeId);
}
@Override
public boolean destroyTemplateSnapshot(Long userId, long snapshotId) {
return _vmMgr.destroyTemplateSnapshot(userId, snapshotId);
@ -6963,7 +6952,7 @@ public class ManagementServerImpl implements ManagementServer {
}
@Override
public Snapshot findSnapshotById(long snapshotId) {
public SnapshotVO findSnapshotById(long snapshotId) {
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
if (snapshot != null && snapshot.getRemoved() == null && snapshot.getStatus() == Snapshot.Status.BackedUp) {
return snapshot;
@ -6974,9 +6963,9 @@ public class ManagementServerImpl implements ManagementServer {
}
@Override
public VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, long snapshotId, String name, String description) throws InvalidParameterValueException {
public VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, Long snapshotId, Long volumeId, String name, String description) throws InvalidParameterValueException {
return _vmMgr.createPrivateTemplate(template, userId, snapshotId, name, description);
return _vmMgr.createPrivateTemplate(template, userId, snapshotId, volumeId, name, description);
}
@Override

View File

@ -490,7 +490,7 @@ public class StorageManagerImpl implements StorageManager {
}
@DB
protected Pair<VolumeVO, String> createVolumeFromSnapshot(long userId, long accountId, String userSpecifiedName, DataCenterVO dc, DiskOfferingVO diskOffering, SnapshotVO snapshot, String templatePath, Long originalVolumeSize, VMTemplateVO template) {
protected Pair<VolumeVO, String> createVolumeFromSnapshot(long userId, long accountId, String userSpecifiedName, DataCenterVO dc, SnapshotVO snapshot, long virtualsize) {
VolumeVO createdVolume = null;
Long volumeId = null;
@ -506,10 +506,7 @@ public class StorageManagerImpl implements StorageManager {
volume.setAccountId(accountId);
volume.setDomainId(account.getDomainId());
volume.setMirrorState(MirrorState.NOT_MIRRORED);
if (diskOffering != null) {
volume.setDiskOfferingId(diskOffering.getId());
}
volume.setSize(originalVolumeSize);
volume.setSize(virtualsize);
volume.setStorageResourceType(Storage.StorageResourceType.STORAGE_POOL);
volume.setInstanceId(null);
volume.setUpdated(new Date());
@ -538,8 +535,7 @@ public class StorageManagerImpl implements StorageManager {
String volumeUUID = null;
String details = null;
DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
DiskProfile dskCh = new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), 0, virtualsize, null, false, false, null);
// Determine what pod to store the volume in
while ((pod = _agentMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) {
@ -552,7 +548,7 @@ public class StorageManagerImpl implements StorageManager {
// Get the newly created VDI from the snapshot.
// This will return a null volumePath if it could not be created
Pair<String, String> volumeDetails = createVDIFromSnapshot(userId, snapshot, pool, templatePath);
Pair<String, String> volumeDetails = createVDIFromSnapshot(userId, snapshot, pool);
volumeUUID = volumeDetails.first();
details = volumeDetails.second();
@ -621,69 +617,18 @@ public class StorageManagerImpl implements StorageManager {
SnapshotVO snapshot = _snapshotDao.findById(snapshotId); // Precondition: snapshot is not null and not removed.
Long origVolumeId = snapshot.getVolumeId();
VolumeVO originalVolume = _volsDao.findById(origVolumeId); // NOTE: Original volume could be destroyed and removed.
String templatePath = null;
VMTemplateVO template = null;
if(originalVolume.getVolumeType().equals(Volume.VolumeType.ROOT)){
if(originalVolume.getTemplateId() == null){
details = "Null Template Id for Root Volume Id: " + origVolumeId + ". Cannot create volume from snapshot of root disk.";
s_logger.error(details);
}
else {
Long templateId = originalVolume.getTemplateId();
template = _templateDao.findById(templateId);
if(template == null) {
details = "Unable find template id: " + templateId + " to create volume from root disk";
s_logger.error(details);
}
else if (template.getFormat() != ImageFormat.ISO) {
// For ISOs there is no base template VHD file. The root disk itself is the base template.
// Creating a volume from an ISO Root Disk is the same as creating a volume for a Data Disk.
// Absolute crappy way of getting the template path on secondary storage.
// Why is the secondary storage a host? It's just an NFS mount point. Why do we need to look into the templateHostVO?
HostVO secondaryStorageHost = getSecondaryStorageHost(originalVolume.getDataCenterId());
VMTemplateHostVO templateHostVO = _templateHostDao.findByHostTemplate(secondaryStorageHost.getId(), templateId);
if (templateHostVO == null ||
templateHostVO.getDownloadState() != VMTemplateStorageResourceAssoc.Status.DOWNLOADED ||
(templatePath = templateHostVO.getInstallPath()) == null)
{
details = "Template id: " + templateId + " is not present on secondaryStorageHost Id: " + secondaryStorageHost.getId() + ". Can't create volume from ROOT DISK";
}
}
}
}
if (details == null) {
// everything went well till now
DataCenterVO dc = _dcDao.findById(originalVolume.getDataCenterId());
DiskOfferingVO diskOffering = null;
// everything went well till now
DataCenterVO dc = _dcDao.findById(originalVolume.getDataCenterId());
if (originalVolume.getVolumeType() == VolumeType.DATADISK || originalVolume.getVolumeType() == VolumeType.ROOT) {
Long diskOfferingId = originalVolume.getDiskOfferingId();
if (diskOfferingId != null) {
diskOffering = _diskOfferingDao.findById(diskOfferingId);
}
}
// else if (originalVolume.getVolumeType() == VolumeType.ROOT) {
// // Create a temporary disk offering with the same size as the ROOT DISK
// Long rootDiskSize = originalVolume.getSize();
// Long rootDiskSizeInMB = rootDiskSize/(1024*1024);
// Long sizeInGB = rootDiskSizeInMB/1024;
// String name = "Root Disk Offering";
// String displayText = "Temporary Disk Offering for Snapshot from Root Disk: " + originalVolume.getId() + "[" + sizeInGB + "GB Disk]";
// diskOffering = new DiskOfferingVO(originalVolume.getDomainId(), name, displayText, rootDiskSizeInMB, false, null);
// }
else {
// The code never reaches here.
s_logger.error("Original volume must have been a ROOT DISK or a DATA DISK");
return null;
}
Pair<VolumeVO, String> volumeDetails = createVolumeFromSnapshot(userId, accountId, volumeName, dc, diskOffering, snapshot, templatePath, originalVolume.getSize(), template);
createdVolume = volumeDetails.first();
if (createdVolume != null) {
volumeId = createdVolume.getId();
}
details = volumeDetails.second();
Pair<VolumeVO, String> volumeDetails = createVolumeFromSnapshot(userId, accountId, volumeName, dc,
snapshot, originalVolume.getSize());
createdVolume = volumeDetails.first();
if (createdVolume != null) {
volumeId = createdVolume.getId();
}
details = volumeDetails.second();
Transaction txn = Transaction.currentTxn();
txn.start();
@ -719,7 +664,7 @@ public class StorageManagerImpl implements StorageManager {
return createdVolume;
}
protected Pair<String, String> createVDIFromSnapshot(long userId, SnapshotVO snapshot, StoragePoolVO pool, String templatePath) {
protected Pair<String, String> createVDIFromSnapshot(long userId, SnapshotVO snapshot, StoragePoolVO pool) {
String vdiUUID = null;
Long volumeId = snapshot.getVolumeId();
@ -738,8 +683,7 @@ public class StorageManagerImpl implements StorageManager {
accountId,
volumeId,
backedUpSnapshotUuid,
snapshot.getName(),
templatePath);
snapshot.getName());
String basicErrMsg = "Failed to create volume from " + snapshot.getName() + " for volume: " + volume.getId();
CreateVolumeFromSnapshotAnswer answer = (CreateVolumeFromSnapshotAnswer) sendToHostsOnStoragePool(pool.getId(),

View File

@ -47,12 +47,12 @@ public interface SnapshotManager extends Manager {
* @throws ResourceAllocationException
* @throws InvalidParameterValueException
*/
SnapshotVO createSnapshot(long userId, long volumeId, List<Long> policies) throws InvalidParameterValueException, ResourceAllocationException;
SnapshotVO createSnapshot(long userId, long volumeId, long policyId) throws InvalidParameterValueException, ResourceAllocationException;
/**
* Creates a snapshot for the given volume
*/
long createSnapshotAsync(long userId, long volumeId, List<Long> policies);
long createSnapshotAsync(long userId, long volumeId, long policyId);
/**
* After successfully creating a snapshot of a volume, copy the snapshot to the secondary storage for
@ -75,7 +75,7 @@ public interface SnapshotManager extends Manager {
* @param policyIds The list of policyIds to which this snapshot belongs to
* @param backedUp If true, the snapshot has been successfully created.
*/
void postCreateSnapshot(long userId, long volumeId, long snapshotId, List<Long> policyIds, boolean backedUp);
void postCreateSnapshot(long userId, long volumeId, long snapshotId, long policyId, boolean backedUp);
/**
* Creates a volume from the specified snapshot. A new volume is returned which is not attached to any VM Instance
@ -158,4 +158,8 @@ public interface SnapshotManager extends Manager {
ImageFormat getImageFormat(Long volumeId);
SnapshotPolicyVO getPolicyForVolume(long volumeId);
boolean destroySnapshotBackUp(long userId, long snapshotId, long policyId);
}

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,4 @@ public interface SnapshotScheduler extends Manager, Scheduler {
*/
boolean removeSchedule(Long volumeId, Long policyId);
Long scheduleManualSnapshot(Long userId, Long volumeId);
}

View File

@ -28,6 +28,7 @@ import java.util.TimerTask;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import javax.persistence.EntityExistsException;
import org.apache.log4j.Logger;
@ -35,6 +36,7 @@ import com.cloud.async.AsyncJobResult;
import com.cloud.async.AsyncJobVO;
import com.cloud.async.dao.AsyncJobDao;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.event.EventTypes;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotPolicyVO;
import com.cloud.storage.SnapshotScheduleVO;
@ -194,36 +196,6 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler {
}
}
/**
* {@inheritDoc}
*/
@Override
@DB
public Long scheduleManualSnapshot(Long userId, Long volumeId) {
// Check if there is another manual snapshot scheduled which hasn't been executed yet.
SearchCriteria<SnapshotScheduleVO> sc = _snapshotScheduleDao.createSearchCriteria();
sc.addAnd("volumeId", SearchCriteria.Op.EQ, volumeId);
sc.addAnd("policyId", SearchCriteria.Op.EQ, Snapshot.MANUAL_POLICY_ID);
List<SnapshotScheduleVO> snapshotSchedules = _snapshotScheduleDao.search(sc, null);
if (!snapshotSchedules.isEmpty()) {
Date scheduledTimestamp = snapshotSchedules.get(0).getScheduledTimestamp();
String dateDisplay = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, scheduledTimestamp);
s_logger.error("Can't execute another manual snapshot for volume: " + volumeId +
" while another manual snapshot for the same volume is being created/backed up. " +
"The older snapshot was scheduled at " + dateDisplay);
return null;
}
SnapshotScheduleVO snapshotSchedule = new SnapshotScheduleVO(volumeId, Snapshot.MANUAL_POLICY_ID, _currentTimestamp);
// There is a race condition here. Two threads enter here.
// Both find that there are no manual snapshots for the same volume scheduled.
// Both try to schedule. One fails, which is what we wanted anyway.
_snapshotScheduleDao.persist(snapshotSchedule);
List<Long> policyIds = new ArrayList<Long>();
policyIds.add(Snapshot.MANUAL_POLICY_ID);
return _snapshotManager.createSnapshotAsync(userId, volumeId, policyIds);
}
@DB
protected void scheduleSnapshots() {
@ -237,72 +209,27 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler {
// Hence set user id to that of system
long userId = 1;
// The volumes which are going to be snapshotted now.
// The value contains the list of policies associated with this new snapshot.
// There can be more than one policy for a list if different policies coincide for the same volume.
Map<Long, List<Long>> listOfVolumesSnapshotted = new HashMap<Long, List<Long>>();
Calendar cal = Calendar.getInstance(DateUtil.GMT_TIMEZONE);
cal.add(Calendar.MINUTE, -15);
//Skip any snapshots older than 15mins
Date graceTime = cal.getTime();
for (SnapshotScheduleVO snapshotToBeExecuted : snapshotsToBeExecuted) {
Date scheduleTime = snapshotToBeExecuted.getScheduledTimestamp();
if(scheduleTime.before(graceTime)){
s_logger.info("Snapshot schedule older than 15mins. Skipping snapshot for volume: "+snapshotToBeExecuted.getVolumeId());
scheduleNextSnapshotJob(snapshotToBeExecuted);
continue;
}
long policyId = snapshotToBeExecuted.getPolicyId();
long volumeId = snapshotToBeExecuted.getVolumeId();
List<Long> coincidingPolicies = listOfVolumesSnapshotted.get(volumeId);
if (coincidingPolicies != null) {
s_logger.debug("The snapshot for this volume " + volumeId + " and policy " + policyId + " has already been sent for execution along with " + coincidingPolicies.size() + " policies in total");
// This can happen if this coincided with another schedule with a different policy
// It would have added all the coinciding policies for the volume to the Map
if (coincidingPolicies.contains(snapshotToBeExecuted.getPolicyId())) {
// Don't need to do anything now. The snapshot is already scheduled for execution.
s_logger.debug("coincidingPolicies contains snapshotToBeExecuted id: " + snapshotToBeExecuted.getId() + ". Don't need to do anything now. The snapshot is already scheduled for execution.");
}
else {
// This will not happen
s_logger.warn("Snapshot Schedule " + snapshotToBeExecuted.getId() +
" is ready for execution now at timestamp " + _currentTimestamp +
" but is not coincident with one being executed for volume " + volumeId);
// Add this to the list of policies for the snapshot schedule
coincidingPolicies.add(snapshotToBeExecuted.getPolicyId());
listOfVolumesSnapshotted.put(volumeId, coincidingPolicies);
}
if (s_logger.isDebugEnabled()) {
Date scheduledTimestamp = snapshotToBeExecuted.getScheduledTimestamp();
displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, scheduledTimestamp);
s_logger.debug("Scheduling 1 snapshot for volume " + volumeId + " for schedule id: "
+ snapshotToBeExecuted.getId() + " at " + displayTime);
}
else {
coincidingPolicies = new ArrayList<Long>();
List<SnapshotScheduleVO> coincidingSchedules = _snapshotScheduleDao.getCoincidingSnapshotSchedules(volumeId, _currentTimestamp);
if (s_logger.isDebugEnabled()) {
Date scheduledTimestamp = snapshotToBeExecuted.getScheduledTimestamp();
displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, scheduledTimestamp);
long snapshotScheId = snapshotToBeExecuted.getId();
SnapshotScheduleVO tmpSnapshotScheduleVO = null;
try {
tmpSnapshotScheduleVO = _snapshotScheduleDao.acquire(snapshotScheId);
long jobId = _snapshotManager.createSnapshotAsync(userId, volumeId, policyId);
tmpSnapshotScheduleVO.setAsyncJobId(jobId);
_snapshotScheduleDao.update(snapshotScheId, tmpSnapshotScheduleVO);
} finally {
if (tmpSnapshotScheduleVO != null) {
_snapshotScheduleDao.release(snapshotScheId);
}
Transaction txn = Transaction.currentTxn();
txn.start();
// There are more snapshots scheduled for this volume at the same time.
// Club all the policies together and append them to the coincidingPolicies List
StringBuilder coincidentSchedules = new StringBuilder();
for (SnapshotScheduleVO coincidingSchedule : coincidingSchedules) {
coincidingPolicies.add(coincidingSchedule.getPolicyId());
coincidentSchedules.append(coincidingSchedule.getId() + ", ");
}
txn.commit();
s_logger.debug("Scheduling 1 snapshot for volume " + volumeId + " for schedule ids: " + coincidentSchedules + " at " + displayTime);
long jobId = _snapshotManager.createSnapshotAsync(userId, volumeId, coincidingPolicies);
// Add this snapshot to the listOfVolumesSnapshotted
// So that the coinciding schedules don't get scheduled again.
listOfVolumesSnapshotted.put(volumeId, coincidingPolicies);
}
}
}
@ -328,10 +255,26 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler {
long policyId = policyInstance.getId();
Date nextSnapshotTimestamp = getNextScheduledTime(policyId, _currentTimestamp);
SnapshotScheduleVO snapshotScheduleVO = new SnapshotScheduleVO(policyInstance.getVolumeId(), policyId, nextSnapshotTimestamp);
_snapshotScheduleDao.persist(snapshotScheduleVO);
try{
_snapshotScheduleDao.persist(snapshotScheduleVO);
} catch (EntityExistsException e ) {
snapshotScheduleVO = _snapshotScheduleDao.findOneByVolume(policyInstance.getVolumeId());
try {
snapshotScheduleVO = _snapshotScheduleDao.acquire(snapshotScheduleVO.getId());
snapshotScheduleVO.setPolicyId(policyId);
snapshotScheduleVO.setScheduledTimestamp(nextSnapshotTimestamp);
_snapshotScheduleDao.update(snapshotScheduleVO.getId(), snapshotScheduleVO);
} finally {
if(snapshotScheduleVO != null ) {
_snapshotScheduleDao.release(snapshotScheduleVO.getId());
}
}
}
return nextSnapshotTimestamp;
}
@Override @DB
public boolean removeSchedule(Long volumeId, Long policyId) {
// We can only remove schedules which are in the future. Not which are already executed in the past.

View File

@ -197,14 +197,8 @@ public interface UserVmManager extends Manager, VirtualMachineManager<UserVmVO>
* @param description the user give description (aka display text) for the template
* @return a template if successfully created, null otherwise
*/
VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, long snapshotId, String name, String description);
VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, Long snapshotId, Long volumeId, String name, String description);
/**
* @param userId The Id of the user who invoked this operation.
* @param volumeId The volume for which this snapshot is being taken
* @return The properties of the snapshot taken
*/
SnapshotVO createTemplateSnapshot(long userId, long volumeId);
boolean destroyTemplateSnapshot(Long userId, long snapshotId);
/**

View File

@ -20,7 +20,6 @@ package com.cloud.vm;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Formatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -48,6 +47,7 @@ import com.cloud.agent.api.CheckVirtualMachineAnswer;
import com.cloud.agent.api.CheckVirtualMachineCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.ManageSnapshotAnswer;
@ -60,7 +60,6 @@ import com.cloud.agent.api.StartCommand;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.storage.CreatePrivateTemplateCommand;
import com.cloud.alert.AlertManager;
import com.cloud.api.BaseCmd;
import com.cloud.async.AsyncJobExecutor;
@ -2232,7 +2231,7 @@ public class UserVmManagerImpl implements UserVmManager {
SnapshotVO snapshot = _snapshotDao.findById(Long.valueOf(snapshotId));
if (snapshot != null) {
VolumeVO volume = _volsDao.findById(snapshot.getVolumeId());
ManageSnapshotCommand cmd = new ManageSnapshotCommand(ManageSnapshotCommand.DESTROY_SNAPSHOT, snapshotId, snapshot.getPath(), snapshot.getName(), null);
ManageSnapshotCommand cmd = new ManageSnapshotCommand(snapshotId, snapshot.getPath());
Answer answer = null;
String basicErrMsg = "Failed to destroy template snapshot: " + snapshot.getName();
@ -2252,60 +2251,6 @@ public class UserVmManagerImpl implements UserVmManager {
return success;
}
@Override @DB
public SnapshotVO createTemplateSnapshot(long userId, long volumeId) {
SnapshotVO createdSnapshot = null;
VolumeVO volume = _volsDao.lock(volumeId, true);
Long id = null;
// Determine the name for this snapshot
String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT);
String snapshotName = volume.getName() + "_" + timeString;
// Create the Snapshot object and save it so we can return it to the user
SnapshotType snapshotType = SnapshotType.TEMPLATE;
SnapshotVO snapshot = new SnapshotVO(volume.getAccountId(), volume.getId(), null, snapshotName, (short)snapshotType.ordinal(), snapshotType.name());
snapshot = _snapshotDao.persist(snapshot);
id = snapshot.getId();
// Send a ManageSnapshotCommand to the agent
ManageSnapshotCommand cmd = new ManageSnapshotCommand(ManageSnapshotCommand.CREATE_SNAPSHOT, id, volume.getPath(), snapshotName, null);
String basicErrMsg = "Failed to create snapshot for volume: " + volume.getId();
// This can be sent to a KVM host too. We are only taking snapshots on primary storage, which doesn't require XenServer.
// So shouldBeSnapshotCapable is set to false.
ManageSnapshotAnswer answer = (ManageSnapshotAnswer) _storageMgr.sendToHostsOnStoragePool(volume.getPoolId(), cmd, basicErrMsg);
// Update the snapshot in the database
if ((answer != null) && answer.getResult()) {
// The snapshot was successfully created
Transaction txn = Transaction.currentTxn();
txn.start();
createdSnapshot = _snapshotDao.findById(id);
createdSnapshot.setPath(answer.getSnapshotPath());
createdSnapshot.setStatus(Snapshot.Status.CreatedOnPrimary);
_snapshotDao.update(id, createdSnapshot);
txn.commit();
// Don't Create an event for Template Snapshots for now.
} else {
if (answer != null) {
s_logger.error(answer.getDetails());
}
// The snapshot was not successfully created
Transaction txn = Transaction.currentTxn();
txn.start();
createdSnapshot = _snapshotDao.findById(id);
_snapshotDao.expunge(id);
txn.commit();
createdSnapshot = null;
}
return createdSnapshot;
}
@Override
public void cleanNetworkRules(long userId, long instanceId) {
@ -2467,133 +2412,137 @@ public class UserVmManagerImpl implements UserVmManager {
}
@Override @DB
public VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, long snapshotId, String name, String description) {
VMTemplateVO privateTemplate = null;
long templateId = template.getId();
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
if (snapshot != null) {
Long volumeId = snapshot.getVolumeId();
VolumeVO volume = _volsDao.findById(volumeId);
StringBuilder userFolder = new StringBuilder();
Formatter userFolderFormat = new Formatter(userFolder);
userFolderFormat.format("u%06d", snapshot.getAccountId());
public VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, Long snapshotId, Long volumeId, String name, String description) {
String uniqueName = getRandomPrivateTemplateName();
VMTemplateVO privateTemplate = null;
long templateId = template.getId();
VolumeVO volume = null;
long zoneId;
HostVO secondaryStorageHost;
String uniqueName = getRandomPrivateTemplateName();
long zoneId = volume.getDataCenterId();
HostVO secondaryStorageHost = _storageMgr.getSecondaryStorageHost(zoneId);
Command cmd = null;
if( snapshotId != null ) {
SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
if( snapshot == null ) {
throw new CloudRuntimeException("Unable to find snapshot for Id " + snapshotId);
}
String backupSnapshotUUID = snapshot.getBackupSnapshotId();
if (backupSnapshotUUID == null) {
throw new CloudRuntimeException("Unable to create private template from snapshot " + snapshotId + " due to there is no backupSnapshotUUID for this snapshot");
}
Long origVolumeId = snapshot.getVolumeId();
volume = _volsDao.findById(volumeId);
zoneId = volume.getDataCenterId();
secondaryStorageHost = _storageMgr.getSecondaryStorageHost(zoneId);
String secondaryStorageURL = _storageMgr.getSecondaryStorageURL(zoneId);
if (secondaryStorageHost == null || secondaryStorageURL == null) {
s_logger.warn("Did not find the secondary storage URL in the database.");
return null;
throw new CloudRuntimeException("Did not find the secondary storage URL in the database for zoneId "
+ zoneId);
}
Command cmd = null;
String backupSnapshotUUID = snapshot.getBackupSnapshotId();
if (backupSnapshotUUID != null) {
// We are creating a private template from a snapshot which has been backed up to secondary storage.
Long dcId = volume.getDataCenterId();
Long accountId = volume.getAccountId();
// We are creating a private template from a snapshot which has been
// backed up to secondary storage.
Long dcId = volume.getDataCenterId();
Long accountId = volume.getAccountId();
String origTemplateInstallPath = null;
String origTemplateInstallPath = null;
if (ImageFormat.ISO != _snapshotMgr.getImageFormat(volumeId)) {
Long origTemplateId = volume.getTemplateId();
VMTemplateHostVO vmTemplateHostVO = _templateHostDao.findByHostTemplate(secondaryStorageHost.getId(), origTemplateId);
origTemplateInstallPath = vmTemplateHostVO.getInstallPath();
}
cmd = new CreatePrivateTemplateFromSnapshotCommand(_storageMgr.getPrimaryStorageNameLabel(volume),
secondaryStorageURL,
dcId,
accountId,
volumeId,
backupSnapshotUUID,
snapshot.getName(),
origTemplateInstallPath,
templateId,
name);
cmd = new CreatePrivateTemplateFromSnapshotCommand(_storageMgr.getPrimaryStorageNameLabel(volume),
secondaryStorageURL, dcId, accountId, origVolumeId, backupSnapshotUUID, snapshot.getName(),
origTemplateInstallPath, templateId, name);
} else if( volumeId != null ) {
volume = _volsDao.findById(volumeId);
if( volume == null ) {
throw new CloudRuntimeException("Unable to find volume for Id " + volumeId);
}
else {
cmd = new CreatePrivateTemplateCommand(secondaryStorageURL,
templateId,
volume.getAccountId(),
name,
uniqueName,
_storageMgr.getPrimaryStorageNameLabel(volume),
snapshot.getPath(),
snapshot.getName(),
userFolder.toString());
long instanceId = volume.getInstanceId();
VMInstanceVO vm = _vmDao.findById(instanceId);
State vmState = vm.getState();
if( !vmState.equals(State.Stopped) && !vmState.equals(State.Destroyed)) {
throw new CloudRuntimeException("Please put VM " + vm.getName() + " into Stopped state first");
}
// FIXME: before sending the command, check if there's enough capacity on the storage server to create the template
zoneId = volume.getDataCenterId();
secondaryStorageHost = _storageMgr.getSecondaryStorageHost(zoneId);
String secondaryStorageURL = _storageMgr.getSecondaryStorageURL(zoneId);
String basicErrMsg = "Failed to create template from snapshot: " + snapshot.getName();
// This can be sent to a KVM host too.
CreatePrivateTemplateAnswer answer = (CreatePrivateTemplateAnswer) _storageMgr.sendToHostsOnStoragePool(volume.getPoolId(), cmd, basicErrMsg);
if ((answer != null) && answer.getResult()) {
privateTemplate = _templateDao.findById(templateId);
Long origTemplateId = volume.getTemplateId();
VMTemplateVO origTemplate = null;
if (origTemplateId != null) {
origTemplate = _templateDao.findById(origTemplateId);
}
if ((origTemplate != null) && !Storage.ImageFormat.ISO.equals(origTemplate.getFormat())) {
// We made a template from a root volume that was cloned from a template
privateTemplate.setFileSystem(origTemplate.getFileSystem());
privateTemplate.setRequiresHvm(origTemplate.requiresHvm());
privateTemplate.setBits(origTemplate.getBits());
} else {
// We made a template from a root volume that was not cloned from a template, or a data volume
privateTemplate.setFileSystem(Storage.FileSystem.Unknown);
privateTemplate.setRequiresHvm(true);
privateTemplate.setBits(64);
}
String answerUniqueName = answer.getUniqueName();
if (answerUniqueName != null) {
privateTemplate.setUniqueName(answerUniqueName);
} else {
privateTemplate.setUniqueName(uniqueName);
}
ImageFormat format = answer.getImageFormat();
if (format != null) {
privateTemplate.setFormat(format);
}
else {
// This never occurs.
// Specify RAW format makes it unusable for snapshots.
privateTemplate.setFormat(ImageFormat.RAW);
}
_templateDao.update(templateId, privateTemplate);
// add template zone ref for this template
_templateDao.addTemplateToZone(privateTemplate, zoneId);
VMTemplateHostVO templateHostVO = new VMTemplateHostVO(secondaryStorageHost.getId(), templateId);
templateHostVO.setDownloadPercent(100);
templateHostVO.setDownloadState(Status.DOWNLOADED);
templateHostVO.setInstallPath(answer.getPath());
templateHostVO.setLastUpdated(new Date());
templateHostVO.setSize(answer.getVirtualSize());
_templateHostDao.persist(templateHostVO);
// Increment the number of templates
_accountMgr.incrementResourceCount(volume.getAccountId(), ResourceType.template);
} else {
// Remove the template record
_templateDao.remove(templateId);
if (secondaryStorageHost == null || secondaryStorageURL == null) {
throw new CloudRuntimeException("Did not find the secondary storage URL in the database for zoneId " + zoneId);
}
cmd = new CreatePrivateTemplateFromVolumeCommand(secondaryStorageURL, templateId, volume.getAccountId(),
name, uniqueName, volume.getPath());
} else {
throw new CloudRuntimeException("Creating private Template need to specify snapshotId or volumeId");
}
// FIXME: before sending the command, check if there's enough capacity
// on the storage server to create the template
// This can be sent to a KVM host too.
CreatePrivateTemplateAnswer answer = (CreatePrivateTemplateAnswer) _storageMgr.sendToHostsOnStoragePool(volume
.getPoolId(), cmd, null);
if ((answer != null) && answer.getResult()) {
privateTemplate = _templateDao.findById(templateId);
Long origTemplateId = volume.getTemplateId();
VMTemplateVO origTemplate = null;
if (origTemplateId != null) {
origTemplate = _templateDao.findById(origTemplateId);
}
if ((origTemplate != null) && !Storage.ImageFormat.ISO.equals(origTemplate.getFormat())) {
// We made a template from a root volume that was cloned from a
// template
privateTemplate.setFileSystem(origTemplate.getFileSystem());
privateTemplate.setRequiresHvm(origTemplate.requiresHvm());
privateTemplate.setBits(origTemplate.getBits());
} else {
// We made a template from a root volume that was not cloned
// from a template, or a data volume
privateTemplate.setFileSystem(Storage.FileSystem.Unknown);
privateTemplate.setRequiresHvm(true);
privateTemplate.setBits(64);
}
String answerUniqueName = answer.getUniqueName();
if (answerUniqueName != null) {
privateTemplate.setUniqueName(answerUniqueName);
} else {
privateTemplate.setUniqueName(uniqueName);
}
ImageFormat format = answer.getImageFormat();
if (format != null) {
privateTemplate.setFormat(format);
} else {
// This never occurs.
// Specify RAW format makes it unusable for snapshots.
privateTemplate.setFormat(ImageFormat.RAW);
}
_templateDao.update(templateId, privateTemplate);
// add template zone ref for this template
_templateDao.addTemplateToZone(privateTemplate, zoneId);
VMTemplateHostVO templateHostVO = new VMTemplateHostVO(secondaryStorageHost.getId(), templateId);
templateHostVO.setDownloadPercent(100);
templateHostVO.setDownloadState(Status.DOWNLOADED);
templateHostVO.setInstallPath(answer.getPath());
templateHostVO.setLastUpdated(new Date());
templateHostVO.setSize(answer.getVirtualSize());
_templateHostDao.persist(templateHostVO);
// Increment the number of templates
_accountMgr.incrementResourceCount(volume.getAccountId(), ResourceType.template);
} else {
// Remove the template record
_templateDao.remove(templateId);
throw new CloudRuntimeException("Creating private Template failed due to " + answer.getDetails());
}
return privateTemplate;
}

View File

@ -998,7 +998,7 @@ CREATE TABLE `cloud`.`launch_permission` (
CREATE TABLE `cloud`.`snapshot_policy` (
`id` bigint unsigned NOT NULL auto_increment,
`volume_id` bigint unsigned NOT NULL,
`volume_id` bigint unsigned NOT NULL unique,
`schedule` varchar(100) NOT NULL COMMENT 'schedule time of execution',
`timezone` varchar(100) NOT NULL COMMENT 'the timezone in which the schedule time is specified',
`interval` int(4) NOT NULL default 4 COMMENT 'backup schedule, e.g. hourly, daily, etc.',
@ -1016,12 +1016,11 @@ CREATE TABLE `cloud`.`snapshot_policy_ref` (
CREATE TABLE `cloud`.`snapshot_schedule` (
`id` bigint unsigned NOT NULL auto_increment,
`volume_id` bigint unsigned NOT NULL COMMENT 'The volume for which this snapshot is being taken',
`volume_id` bigint unsigned NOT NULL unique COMMENT 'The volume for which this snapshot is being taken',
`policy_id` bigint unsigned NOT NULL COMMENT 'One of the policyIds for which this snapshot was taken',
`scheduled_timestamp` datetime NOT NULL COMMENT 'Time at which the snapshot was scheduled for execution',
`async_job_id` bigint unsigned COMMENT 'If this schedule is being executed, it is the id of the create aysnc_job. Before that it is null',
`snapshot_id` bigint unsigned COMMENT 'If this schedule is being executed, then the corresponding snapshot has this id. Before that it is null',
UNIQUE (volume_id, policy_id),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;