mirror of https://github.com/apache/cloudstack.git
bug 6332: remove the new snapshot if it is empty
status 6332: resolved fixed
This commit is contained in:
parent
734e9c8a28
commit
25f7d46aed
|
|
@ -37,10 +37,11 @@ public class ManageSnapshotCommand extends Command {
|
|||
|
||||
public ManageSnapshotCommand() {}
|
||||
|
||||
public ManageSnapshotCommand(String commandSwitch, long snapshotId, String path, String snapshotName) {
|
||||
public ManageSnapshotCommand(String commandSwitch, long snapshotId, String path, String preSnapshot, String snapshotName) {
|
||||
_commandSwitch = commandSwitch;
|
||||
if (commandSwitch.equals(ManageSnapshotCommand.CREATE_SNAPSHOT)) {
|
||||
_volumePath = path;
|
||||
_snapshotPath = preSnapshot;
|
||||
}
|
||||
else if (commandSwitch.equals(ManageSnapshotCommand.DESTROY_SNAPSHOT)) {
|
||||
_snapshotPath = path;
|
||||
|
|
|
|||
|
|
@ -5079,6 +5079,20 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
|
|||
return new ValidateSnapshotAnswer(cmd, success, details, expectedSnapshotBackupUuid, actualSnapshotBackupUuid, actualSnapshotUuid);
|
||||
}
|
||||
|
||||
|
||||
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 ManageSnapshotAnswer execute(final ManageSnapshotCommand cmd) {
|
||||
long snapshotId = cmd.getSnapshotId();
|
||||
String snapshotName = cmd.getSnapshotName();
|
||||
|
|
@ -5111,6 +5125,25 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
|
|||
}
|
||||
|
||||
// Determine the UUID of the snapshot
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VDI.Record vdir = snapshot.getRecord(conn);
|
||||
snapshotUUID = vdir.uuid;
|
||||
|
||||
|
|
|
|||
|
|
@ -1734,19 +1734,7 @@ 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
|
||||
* @param snapshotId the id of the snapshot to destroy
|
||||
* @return true if snapshot successfully destroyed, false otherwise
|
||||
*/
|
||||
boolean destroyTemplateSnapshot(Long userId, long snapshotId);
|
||||
long deleteSnapshotAsync(long userId, long snapshotId);
|
||||
|
||||
long createVolumeFromSnapshotAsync(long userId, long accountId, long snapshotId, String volumeName) throws InternalErrorException, ResourceAllocationException;
|
||||
|
|
|
|||
|
|
@ -2103,8 +2103,20 @@ def network_rules(session, args):
|
|||
except:
|
||||
util.SMlog("Failed to network rule !")
|
||||
|
||||
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)
|
||||
|
||||
baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI)
|
||||
|
||||
return baseCopyUuid
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
XenAPIPlugin.dispatch({"pingtest": pingtest, "create_secondary_storage_folder":create_secondary_storage_folder, "setup_iscsi":setup_iscsi, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template": post_create_private_template, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "getnetwork": getnetwork, "preparemigration": preparemigration, "setIptables": setIptables, "patchdomr": patchdomr, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "checkMount": checkMount, "checkIscsi": checkIscsi, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "createVolumeFromSnapshot": createVolumeFromSnapshot, "networkUsage": networkUsage, "unmountSnapshotsDir": unmountSnapshotsDir, "deleteSnapshotsDir": deleteSnapshotsDir, "validatePreviousSnapshotBackup": validatePreviousSnapshotBackup, "validateSnapshot" : validateSnapshot, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP})
|
||||
XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "pingtest": pingtest, "create_secondary_storage_folder":create_secondary_storage_folder, "setup_iscsi":setup_iscsi, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template": post_create_private_template, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "getnetwork": getnetwork, "preparemigration": preparemigration, "setIptables": setIptables, "patchdomr": patchdomr, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "checkMount": checkMount, "checkIscsi": checkIscsi, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "createVolumeFromSnapshot": createVolumeFromSnapshot, "networkUsage": networkUsage, "unmountSnapshotsDir": unmountSnapshotsDir, "deleteSnapshotsDir": deleteSnapshotsDir, "validatePreviousSnapshotBackup": validatePreviousSnapshotBackup, "validateSnapshot" : validateSnapshot, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP})
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
|||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.UserVmManager;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
|
|
@ -118,7 +119,8 @@ public class CreatePrivateTemplateExecutor extends VolumeOperationExecutor {
|
|||
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());
|
||||
//snapshot = vmMgr.createTemplateSnapshot(param.getUserId(), param.getVolumeId());
|
||||
throw new CloudRuntimeException("Do not support create template from volume at this moment");
|
||||
}
|
||||
else {
|
||||
// We are creating a private template from an already present snapshot.
|
||||
|
|
@ -145,13 +147,6 @@ public class CreatePrivateTemplateExecutor extends VolumeOperationExecutor {
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6325,16 +6325,6 @@ public class ManagementServerImpl implements ManagementServer {
|
|||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long deleteSnapshotAsync(long userId, long snapshotId) {
|
||||
Snapshot snapshot = findSnapshotById(snapshotId);
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ import com.cloud.utils.db.GenericDaoBase;
|
|||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
import com.google.gson.Gson;
|
||||
|
|
@ -362,9 +363,19 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
|
||||
}
|
||||
txn.commit();
|
||||
|
||||
// get previous snapshot Path
|
||||
long preId = _snapshotDao.getLastSnapshot(volumeId, id);
|
||||
String preSnapshotPath = null;
|
||||
SnapshotVO preSnapshotVO = null;
|
||||
if( preId != 0) {
|
||||
preSnapshotVO = _snapshotDao.findById(preId);
|
||||
preSnapshotPath = preSnapshotVO.getPath();
|
||||
|
||||
}
|
||||
|
||||
// Send a ManageSnapshotCommand to the agent
|
||||
ManageSnapshotCommand cmd = new ManageSnapshotCommand(ManageSnapshotCommand.CREATE_SNAPSHOT, id, volume.getPath(), snapshotName);
|
||||
ManageSnapshotCommand cmd = new ManageSnapshotCommand(ManageSnapshotCommand.CREATE_SNAPSHOT, id, volume.getPath(), preSnapshotPath, snapshotName);
|
||||
String basicErrMsg = "Failed to create snapshot for volume: " + volume.getId();
|
||||
ManageSnapshotAnswer answer = (ManageSnapshotAnswer) _storageMgr.sendToHostsOnStoragePool(volume.getPoolId(), cmd, basicErrMsg, _totalRetries, _pauseInterval, _shouldBeSnapshotCapable);
|
||||
|
||||
|
|
@ -374,7 +385,16 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
// Update the snapshot in the database
|
||||
if ((answer != null) && answer.getResult()) {
|
||||
// The snapshot was successfully created
|
||||
createdSnapshot = updateDBOnCreate(id, answer.getSnapshotPath());
|
||||
if( preSnapshotPath != null && preSnapshotPath == answer.getSnapshotPath() ){
|
||||
//empty snapshot
|
||||
s_logger.debug("CreateSnapshot: this is empty snapshot, remove it ");
|
||||
// delete from the snapshots table
|
||||
_snapshotDao.delete(id);
|
||||
throw new CloudRuntimeException(" There is no change since last snapshot, please use last snapshot " + preSnapshotPath);
|
||||
|
||||
} else {
|
||||
createdSnapshot = updateDBOnCreate(id, answer.getSnapshotPath());
|
||||
}
|
||||
} else {
|
||||
if (answer != null) {
|
||||
s_logger.error(answer.getDetails());
|
||||
|
|
|
|||
|
|
@ -196,14 +196,6 @@ public interface UserVmManager extends Manager, VirtualMachineManager<UserVmVO>
|
|||
*/
|
||||
VMTemplateVO createPrivateTemplate(VMTemplateVO template, Long userId, long snapshotId, 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);
|
||||
|
||||
/**
|
||||
* Clean the network rules for the given VM
|
||||
* @param userId
|
||||
|
|
|
|||
|
|
@ -2021,87 +2021,7 @@ public class UserVmManagerImpl implements UserVmManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean destroyTemplateSnapshot(Long userId, long snapshotId) {
|
||||
boolean success = false;
|
||||
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());
|
||||
|
||||
Answer answer = null;
|
||||
String basicErrMsg = "Failed to destroy template snapshot: " + snapshot.getName();
|
||||
Long storagePoolId = volume.getPoolId();
|
||||
answer = _storageMgr.sendToHostsOnStoragePool(storagePoolId, cmd, basicErrMsg);
|
||||
|
||||
if ((answer != null) && answer.getResult()) {
|
||||
// delete the snapshot from the database
|
||||
_snapshotDao.delete(snapshotId);
|
||||
success = true;
|
||||
}
|
||||
if (answer != null) {
|
||||
s_logger.error(answer.getDetails());
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override @DB
|
||||
public SnapshotVO createTemplateSnapshot(long userId, long volumeId) {
|
||||
SnapshotVO createdSnapshot = null;
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
|
||||
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);
|
||||
|
||||
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.delete(id);
|
||||
txn.commit();
|
||||
|
||||
createdSnapshot = null;
|
||||
}
|
||||
|
||||
return createdSnapshot;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void cleanNetworkRules(long userId, long instanceId) {
|
||||
UserVmVO vm = _vmDao.findById(instanceId);
|
||||
|
|
|
|||
Loading…
Reference in New Issue