mirror of https://github.com/apache/cloudstack.git
several snapshot fixes
This commit is contained in:
parent
bcb53ec363
commit
224da7e775
|
|
@ -28,7 +28,6 @@ public class BackupSnapshotCommand extends SnapshotCommand {
|
|||
private String prevSnapshotUuid;
|
||||
private String prevBackupUuid;
|
||||
private boolean isVolumeInactive;
|
||||
private String firstBackupUuid;
|
||||
private String vmName;
|
||||
|
||||
protected BackupSnapshotCommand() {
|
||||
|
|
@ -55,19 +54,17 @@ public class BackupSnapshotCommand extends SnapshotCommand {
|
|||
String snapshotName,
|
||||
String prevSnapshotUuid,
|
||||
String prevBackupUuid,
|
||||
String firstBackupUuid,
|
||||
boolean isVolumeInactive,
|
||||
String vmName)
|
||||
{
|
||||
super(primaryStoragePoolNameLabel, secondaryStoragePoolURL, snapshotUuid, snapshotName, dcId, accountId, volumeId);
|
||||
this.prevSnapshotUuid = prevSnapshotUuid;
|
||||
this.prevBackupUuid = prevBackupUuid;
|
||||
this.firstBackupUuid = firstBackupUuid;
|
||||
this.isVolumeInactive = isVolumeInactive;
|
||||
this.vmName = vmName;
|
||||
setVolumePath(volumePath);
|
||||
}
|
||||
|
||||
|
||||
public String getPrevSnapshotUuid() {
|
||||
return prevSnapshotUuid;
|
||||
}
|
||||
|
|
@ -75,11 +72,7 @@ public class BackupSnapshotCommand extends SnapshotCommand {
|
|||
public String getPrevBackupUuid() {
|
||||
return prevBackupUuid;
|
||||
}
|
||||
|
||||
public String getFirstBackupUuid() {
|
||||
return firstBackupUuid;
|
||||
}
|
||||
|
||||
|
||||
public boolean isVolumeInactive() {
|
||||
return isVolumeInactive;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5604,7 +5604,6 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
|
|||
Long volumeId = cmd.getVolumeId();
|
||||
String secondaryStoragePoolURL = cmd.getSecondaryStoragePoolURL();
|
||||
String snapshotUuid = cmd.getSnapshotUuid(); // not null: Precondition.
|
||||
String prevSnapshotUuid = cmd.getPrevSnapshotUuid();
|
||||
String prevBackupUuid = cmd.getPrevBackupUuid();
|
||||
// By default assume failure
|
||||
String details = null;
|
||||
|
|
@ -5647,32 +5646,16 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR
|
|||
}
|
||||
} else {
|
||||
snapshotBackupUuid = backupSnapshot(primaryStorageSRUuid, dcId, accountId, volumeId, secondaryStorageMountPath,
|
||||
snapshotUuid, prevSnapshotUuid, prevBackupUuid, isISCSI);
|
||||
snapshotUuid, prevBackupUuid, isISCSI);
|
||||
success = (snapshotBackupUuid != null);
|
||||
}
|
||||
|
||||
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.
|
||||
String volumeUuid = cmd.getVolumePath();
|
||||
destroySnapshotOnPrimaryStorageExceptThis(volumeUuid, snapshotUuid);
|
||||
|
||||
if (prevSnapshotUuid != null) {
|
||||
// Destroy the previous snapshot, if it exists.
|
||||
// We destroy the previous snapshot only if the current snapshot
|
||||
// backup succeeds.
|
||||
// The aim is to keep the VDI of the last 'successful' snapshot
|
||||
// so that it doesn't get merged with the
|
||||
// new one
|
||||
// and muddle the vhd chain on the secondary storage.
|
||||
|
||||
String volumeUuid = cmd.getVolumePath();
|
||||
destroySnapshotOnPrimaryStorageExceptThis(volumeUuid, snapshotUuid);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch (XenAPIException e) {
|
||||
|
|
@ -6028,21 +6011,18 @@ 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 isISCSI) {
|
||||
String snapshotUuid, String prevBackupUuid, Boolean isISCSI) {
|
||||
String backupSnapshotUuid = null;
|
||||
|
||||
if (prevSnapshotUuid == null) {
|
||||
prevSnapshotUuid = "";
|
||||
}
|
||||
if (prevBackupUuid == null) {
|
||||
prevBackupUuid = "";
|
||||
}
|
||||
|
||||
// Each argument is put in a separate line for readability.
|
||||
// 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, "isISCSI", isISCSI.toString());
|
||||
String results = callHostPluginWithTimeOut("vmopsSnapshot", "backupSnapshot", 110*60, "primaryStorageSRUuid", primaryStorageSRUuid, "dcId",
|
||||
dcId.toString(), "accountId", accountId.toString(), "volumeId", volumeId.toString(), "secondaryStorageMountPath",
|
||||
secondaryStorageMountPath, "snapshotUuid", snapshotUuid, "prevBackupUuid", prevBackupUuid, "isISCSI", isISCSI.toString());
|
||||
|
||||
if (results == null || results.isEmpty()) {
|
||||
// errString is already logged.
|
||||
|
|
|
|||
|
|
@ -463,7 +463,6 @@ def backupSnapshot(session, args):
|
|||
volumeId = args['volumeId']
|
||||
secondaryStorageMountPath = args['secondaryStorageMountPath']
|
||||
snapshotUuid = args['snapshotUuid']
|
||||
prevSnapshotUuid = args['prevSnapshotUuid']
|
||||
prevBackupUuid = args['prevBackupUuid']
|
||||
isISCSI = getIsTrueString(args['isISCSI'])
|
||||
|
||||
|
|
@ -475,9 +474,6 @@ def backupSnapshot(session, args):
|
|||
baseCopyPath = os.path.join(primarySRPath, baseCopyVHD)
|
||||
util.SMlog("Base copy path: " + baseCopyPath)
|
||||
|
||||
prevBaseCopyUuid = ''
|
||||
if prevSnapshotUuid:
|
||||
prevBaseCopyUuid = getParentOfSnapshot(prevSnapshotUuid, primarySRPath, isISCSI)
|
||||
|
||||
# Mount secondary storage mount path on XenServer along the path
|
||||
# /var/run/sr-mount/<dcId>/snapshots/ and create <accountId>/<volumeId> dir
|
||||
|
|
@ -485,13 +481,6 @@ def backupSnapshot(session, args):
|
|||
backupsDir = mountSnapshotsDir(secondaryStorageMountPath, "snapshots", dcId, accountId, volumeId)
|
||||
util.SMlog("Backups dir " + 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)
|
||||
# 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 with new uuid
|
||||
|
|
@ -505,9 +494,6 @@ def backupSnapshot(session, args):
|
|||
# Now set the availability of the snapshotPath and the baseCopyPath to false
|
||||
makeUnavailable(snapshotUuid, primarySRPath, isISCSI)
|
||||
manageAvailability(baseCopyPath, '-an')
|
||||
if prevSnapshotUuid:
|
||||
makeUnavailable(prevSnapshotUuid, primarySRPath, isISCSI)
|
||||
makeUnavailable(prevBaseCopyUuid, primarySRPath, 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.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import org.apache.log4j.Logger;
|
|||
import com.cloud.api.ApiConstants;
|
||||
import com.cloud.api.ApiDBUtils;
|
||||
import com.cloud.api.ApiResponseHelper;
|
||||
import com.cloud.api.BaseAsyncCreateCmd;
|
||||
import com.cloud.api.BaseAsyncCmd;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
|
|
@ -35,8 +35,8 @@ import com.cloud.storage.VolumeVO;
|
|||
import com.cloud.storage.snapshot.SnapshotManager;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
@Implementation(createMethod="createSnapshotDB", method="createSnapshot", manager=SnapshotManager.class, description="Creates an instant snapshot of a volume.")
|
||||
public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
|
||||
@Implementation(method="createSnapshot", manager=SnapshotManager.class, description="Creates an instant snapshot of a volume.")
|
||||
public class CreateSnapshotCmd extends BaseAsyncCmd {
|
||||
public static final Logger s_logger = Logger.getLogger(CreateSnapshotCmd.class.getName());
|
||||
private static final String s_name = "createsnapshotresponse";
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import com.cloud.exception.ResourceAllocationException;
|
|||
import com.cloud.storage.SnapshotPolicyVO;
|
||||
import com.cloud.storage.SnapshotScheduleVO;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.utils.component.Manager;
|
||||
|
||||
|
|
@ -53,13 +54,6 @@ public interface SnapshotManager extends Manager {
|
|||
*/
|
||||
SnapshotVO createSnapshotImpl(long volumeId, long policyId) throws ResourceAllocationException;
|
||||
|
||||
/**
|
||||
* Create a snapshot of a volume
|
||||
* @param cmd the API command wrapping the parameters for creating the snapshot (mainly volumeId)
|
||||
* @return the Snapshot that was created
|
||||
*/
|
||||
SnapshotVO createSnapshotDB(CreateSnapshotCmd cmd) throws ResourceAllocationException;
|
||||
|
||||
/**
|
||||
* Create a snapshot of a volume
|
||||
* @param cmd the API command wrapping the parameters for creating the snapshot (mainly volumeId)
|
||||
|
|
@ -181,4 +175,11 @@ public interface SnapshotManager extends Manager {
|
|||
SnapshotPolicyVO getPolicyForVolume(long volumeId);
|
||||
|
||||
boolean destroySnapshotBackUp(long userId, long snapshotId, long policyId);
|
||||
|
||||
/**
|
||||
* Create a snapshot of a volume
|
||||
* @param cmd the API command wrapping the parameters for creating the snapshot (mainly volumeId)
|
||||
* @return the Snapshot that was created
|
||||
*/
|
||||
SnapshotVO createSnapshotOnPrimary(VolumeVO volume) throws ResourceAllocationException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,11 +206,8 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SnapshotVO createSnapshotDB(CreateSnapshotCmd cmd) throws ResourceAllocationException {
|
||||
// FIXME: When a valid snapshot is returned, the snapshot must have been created on the storage server side so that the caller
|
||||
// knows it is safe to once again resume normal operations on the volume in question.
|
||||
Long volumeId = cmd.getVolumeId();
|
||||
VolumeVO volume = _volsDao.findById(volumeId); // not null, precondition.
|
||||
public SnapshotVO createSnapshotOnPrimary(VolumeVO volume) throws ResourceAllocationException {
|
||||
Long volumeId = volume.getId();
|
||||
if (volume.getStatus() != AsyncInstanceCreateStatus.Created) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in Created state but " + volume.getStatus() + ". Cannot take snapshot.");
|
||||
}
|
||||
|
|
@ -230,7 +227,6 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
throw new InvalidParameterValueException("Snapshots of volumes attached to System or router VM are not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
return createSnapshotImpl(volumeId, Snapshot.MANUAL_POLICY_ID);
|
||||
}
|
||||
|
||||
|
|
@ -365,57 +361,54 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
|
||||
return createdSnapshot;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SnapshotVO createSnapshot(CreateSnapshotCmd cmd) throws ResourceAllocationException {
|
||||
SnapshotVO snapshot = _snapshotDao.findById(cmd.getId());
|
||||
Long snapshotId = null;
|
||||
boolean backedUp = false;
|
||||
if (snapshot != null) {
|
||||
if (snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary) {
|
||||
snapshotId = snapshot.getId();
|
||||
backedUp = backupSnapshotToSecondaryStorage(snapshot, cmd.getStartEventId());
|
||||
if (!backedUp) {
|
||||
throw new CloudRuntimeException("Created snapshot: " + snapshotId + " on primary but failed to backup on secondary");
|
||||
}
|
||||
public SnapshotVO createSnapshotPublic(Long volumeId, Long policyId, Long startEventId) throws ResourceAllocationException {
|
||||
VolumeVO volume = _volsDao.acquireInLockTable(volumeId, 10);
|
||||
if( volume == null ) {
|
||||
volume = _volsDao.findById(volumeId);
|
||||
if( volume == null ){
|
||||
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
|
||||
} else {
|
||||
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " is being used, try it later ");
|
||||
}
|
||||
|
||||
}
|
||||
SnapshotVO snapshot = null;
|
||||
boolean backedUp = false;
|
||||
Long snapshotId = null;
|
||||
try {
|
||||
snapshot = createSnapshotOnPrimary( volume);
|
||||
if (snapshot != null && snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary ) {
|
||||
snapshotId = snapshot.getId();
|
||||
backedUp = backupSnapshotToSecondaryStorage(snapshot, startEventId);
|
||||
if (!backedUp) {
|
||||
throw new CloudRuntimeException("Created snapshot: " + snapshotId + " on primary but failed to backup on secondary");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Cleanup jobs to do after the snapshot has been created.
|
||||
postCreateSnapshot(cmd.getVolumeId(), snapshotId, Snapshot.MANUAL_POLICY_ID, backedUp);
|
||||
postCreateSnapshot(volumeId, snapshotId, policyId, backedUp);
|
||||
_volsDao.releaseFromLockTable(volumeId);
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotVO createSnapshot(CreateSnapshotCmd cmd) throws ResourceAllocationException {
|
||||
Long volumeId = cmd.getVolumeId();
|
||||
Long policyId = Snapshot.MANUAL_POLICY_ID ;
|
||||
Long startEventId = cmd.getStartEventId();
|
||||
return createSnapshotPublic(volumeId, policyId, startEventId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotVO createSnapshotInternal(CreateSnapshotInternalCmd cmd) throws ResourceAllocationException {
|
||||
Long volumeId = cmd.getVolumeId();
|
||||
Long policyId = cmd.getPolicyId();
|
||||
SnapshotVO snapshot = null;
|
||||
Long snapshotId = null;
|
||||
try {
|
||||
snapshot = createSnapshotImpl(volumeId, policyId);
|
||||
} catch (InvalidParameterValueException ex) {
|
||||
s_logger.warn("Received invalid parameter exception creating a recurring snapshot that should've already had validated params: " + ex.getMessage());
|
||||
}
|
||||
|
||||
boolean backedUp = false;
|
||||
if (snapshot != null && snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary) {
|
||||
snapshotId = snapshot.getId();
|
||||
backedUp = backupSnapshotToSecondaryStorage(snapshot, cmd.getStartEventId());
|
||||
if (!backedUp) {
|
||||
throw new CloudRuntimeException("Created snapshot: " + snapshotId + " on primary but failed to backup on secondary");
|
||||
}
|
||||
} else {
|
||||
// if the snapshot wasn't created properly, just return now and avoid problems in the postCreate step
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
// Cleanup jobs to do after the snapshot has been created.
|
||||
postCreateSnapshot(cmd.getVolumeId(), snapshotId, policyId, backedUp);
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
Long startEventId = cmd.getStartEventId();
|
||||
return createSnapshotPublic(volumeId, policyId, startEventId);
|
||||
}
|
||||
|
||||
private SnapshotVO updateDBOnCreate(Long id, String snapshotPath, long preSnapshotId) {
|
||||
SnapshotVO createdSnapshot = _snapshotDao.findById(id);
|
||||
|
|
@ -487,7 +480,6 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
prevBackupUuid = prevSnapshot.getBackupSnapshotId();
|
||||
}
|
||||
|
||||
String firstBackupUuid = volume.getFirstSnapshotBackupUuid();
|
||||
boolean isVolumeInactive = _storageMgr.volumeInactive(volume);
|
||||
String vmName = _storageMgr.getVmNameOnVolume(volume);
|
||||
BackupSnapshotCommand backupSnapshotCommand =
|
||||
|
|
@ -501,7 +493,6 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
snapshot.getName(),
|
||||
prevSnapshotUuid,
|
||||
prevBackupUuid,
|
||||
firstBackupUuid,
|
||||
isVolumeInactive,
|
||||
vmName);
|
||||
|
||||
|
|
@ -737,30 +728,39 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
|||
SnapshotVO lastSnapshot = null;
|
||||
_snapshotDao.remove(snapshotId);
|
||||
long lastId = snapshotId;
|
||||
boolean destroy = false;
|
||||
while( true ) {
|
||||
lastSnapshot = _snapshotDao.findNextSnapshot(lastId);
|
||||
// prevsnapshotId equal 0, means it is a full snapshot
|
||||
if( lastSnapshot == null || lastSnapshot.getPrevSnapshotId() == 0)
|
||||
if( lastSnapshot == null ) {
|
||||
break;
|
||||
}
|
||||
if( lastSnapshot.getPrevSnapshotId() == 0) {
|
||||
// have another full snapshot, then we may delete previous delta snapshots
|
||||
destroy = true;
|
||||
break;
|
||||
}
|
||||
lastId = lastSnapshot.getId();
|
||||
}
|
||||
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
|
||||
while( lastSnapshot.getRemoved() != null ) {
|
||||
String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
|
||||
if( BackupSnapshotId != null ) {
|
||||
if( destroySnapshotBackUp(userId, lastId, policyId) ) {
|
||||
if (destroy) {
|
||||
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
|
||||
while (lastSnapshot.getRemoved() != null) {
|
||||
String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
|
||||
if (BackupSnapshotId != null) {
|
||||
if (destroySnapshotBackUp(userId, lastId, policyId)) {
|
||||
|
||||
} else {
|
||||
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
|
||||
} else {
|
||||
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
postDeleteSnapshot(userId, lastId, policyId);
|
||||
lastId = lastSnapshot.getPrevSnapshotId();
|
||||
if (lastId == 0) {
|
||||
break;
|
||||
}
|
||||
lastSnapshot = _snapshotDao.findById(lastId);
|
||||
}
|
||||
postDeleteSnapshot(userId, lastId, policyId);
|
||||
lastId = lastSnapshot.getPrevSnapshotId();
|
||||
if( lastId == 0 ) {
|
||||
break;
|
||||
}
|
||||
lastSnapshot = _snapshotDao.findById(lastId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue