mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +01:00
Refactoring createSnapshot to new API framework.
This commit is contained in:
parent
39038721a8
commit
037f1ff327
@ -18,26 +18,18 @@
|
||||
|
||||
package com.cloud.api.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.api.BaseAsyncCreateCmd;
|
||||
import com.cloud.api.BaseCmd;
|
||||
import com.cloud.api.BaseCmd.Manager;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.ServerApiException;
|
||||
import com.cloud.async.AsyncJobResult;
|
||||
import com.cloud.async.AsyncJobVO;
|
||||
import com.cloud.async.executor.CreateSnapshotResultObject;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.api.response.SnapshotResponse;
|
||||
import com.cloud.serializer.SerializerHelper;
|
||||
import com.cloud.server.ManagementServer;
|
||||
import com.cloud.storage.Snapshot.SnapshotType;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
@Implementation(createMethod="createSnapshotDB", method="createSnapshot", manager=Manager.SnapshotManager)
|
||||
public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
|
||||
@ -88,128 +80,27 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
|
||||
|
||||
@Override
|
||||
public String getResponse() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pair<String, Object>> execute(Map<String, Object> params) {
|
||||
// Long volumeId = (Long) params.get(BaseCmd.Properties.VOLUME_ID.getName());
|
||||
// Long userId = (Long) params.get(BaseCmd.Properties.USER_ID.getName());
|
||||
SnapshotVO snapshot = (SnapshotVO)getResponseObject();
|
||||
|
||||
ManagementServer managementServer = getManagementServer();
|
||||
// Verify that a volume exists with a specified volume ID
|
||||
VolumeVO volume = managementServer.findVolumeById(volumeId);
|
||||
if (volume == null) {
|
||||
throw new ServerApiException (BaseCmd.PARAM_ERROR, "Unable to find a volume with id " + volumeId);
|
||||
}
|
||||
|
||||
// If an account was passed in, make sure that it matches the account of the volume
|
||||
// FIXME: permission checks go in business logic
|
||||
checkAccountPermissions(params, volume.getAccountId(), volume.getDomainId(), "volume", volumeId);
|
||||
SnapshotResponse response = new SnapshotResponse();
|
||||
response.setId(snapshot.getId());
|
||||
|
||||
// If command is executed via 8096 port, set userId to the id of System account (1)
|
||||
if (userId == null) {
|
||||
userId = Long.valueOf(1);
|
||||
Account account = getAsyncJobMgr().getExecutorContext().getAccountDao().findById(snapshot.getAccountId());
|
||||
if (account != null) {
|
||||
response.setAccountName(account.getAccountName());
|
||||
response.setDomainId(account.getDomainId());
|
||||
response.setDomainName(getAsyncJobMgr().getExecutorContext().getManagementServer().findDomainIdById(account.getDomainId()).getName());
|
||||
}
|
||||
|
||||
try {
|
||||
long jobId = managementServer.createSnapshotAsync(userId, volumeId.longValue());
|
||||
if (jobId == 0) {
|
||||
s_logger.warn("Unable to schedule async-job for CreateSnapshot comamnd");
|
||||
} else {
|
||||
if (s_logger.isDebugEnabled())
|
||||
s_logger.debug("CreateSnapshot command has been accepted, job id: " + jobId);
|
||||
}
|
||||
|
||||
long snapshotId = waitInstanceCreation(jobId);
|
||||
|
||||
List<Pair<String, Object>> returnValues = new ArrayList<Pair<String, Object>>();
|
||||
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.SNAPSHOT_ID.getName(), Long.valueOf(snapshotId)));
|
||||
returnValues.add(new Pair<String, Object>(BaseCmd.Properties.JOB_ID.getName(), Long.valueOf(jobId)));
|
||||
|
||||
return returnValues;
|
||||
} catch (ResourceAllocationException rae) {
|
||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Unable to create a snapshot for volume with id " + volumeId + ": " + rae.getMessage());
|
||||
} catch (ServerApiException apiEx) {
|
||||
throw apiEx;
|
||||
} catch (Exception ex) {
|
||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Unable to create a snapshot for volume with id " + volumeId + " because of: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected long waitInstanceCreation(long jobId) {
|
||||
ManagementServer mgr = getManagementServer();
|
||||
VolumeVO volume = managementServer.findVolumeById(snapshot.getVolumeId());
|
||||
String snapshotTypeStr = SnapshotType.values()[snapshot.getSnapshotType()].name();
|
||||
response.setSnapshotType(snapshotTypeStr);
|
||||
response.setVolumeId(snapshot.getVolumeId());
|
||||
response.setVolumeName(volume.getName());
|
||||
response.setVolumeType(volume.getVolumeType().toString());
|
||||
response.setCreated(snapshot.getCreated());
|
||||
response.setName(snapshot.getName());
|
||||
|
||||
long snapshotId = 0;
|
||||
AsyncJobVO job = null;
|
||||
boolean interruped = false;
|
||||
|
||||
// as job may be executed in other management server, we need to do a database polling here
|
||||
try {
|
||||
boolean quit = false;
|
||||
while(!quit) {
|
||||
job = mgr.findAsyncJobById(jobId);
|
||||
if(job == null) {
|
||||
s_logger.error("CreateSnapshotAsync.waitInstanceCreation error: job-" + jobId + " no longer exists");
|
||||
break;
|
||||
}
|
||||
|
||||
switch(job.getStatus()) {
|
||||
case AsyncJobResult.STATUS_IN_PROGRESS :
|
||||
if(job.getProcessStatus() == BaseCmd.PROGRESS_INSTANCE_CREATED) {
|
||||
Long id = (Long)SerializerHelper.fromSerializedString(job.getResult());
|
||||
if(id != null) {
|
||||
snapshotId = id.longValue();
|
||||
if(s_logger.isDebugEnabled())
|
||||
s_logger.debug("CreateSnapshotAsync succeeded in taking snapshot on primary, snapshotId: " + snapshotId);
|
||||
} else {
|
||||
s_logger.warn("CreateSnapshotAsync succeeded in taking snapshot on primary, but value as null?");
|
||||
}
|
||||
quit = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case AsyncJobResult.STATUS_SUCCEEDED :
|
||||
{
|
||||
CreateSnapshotResultObject resultObject = (CreateSnapshotResultObject)SerializerHelper.fromSerializedString(job.getResult());
|
||||
if(resultObject != null) {
|
||||
snapshotId = resultObject.getId();
|
||||
|
||||
if(s_logger.isDebugEnabled())
|
||||
s_logger.debug("CreateSnapshotAsync succeeded in backing up snapshot to secondary, snapshotId: " + snapshotId);
|
||||
} else {
|
||||
s_logger.warn("CreateSnapshotAsync successfully completed, but result object is null?");
|
||||
}
|
||||
}
|
||||
quit = true;
|
||||
break;
|
||||
|
||||
case AsyncJobResult.STATUS_FAILED :
|
||||
s_logger.error("CreateSnapshotAsync job-" + jobId + " failed, result: " + job.getResult());
|
||||
quit = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(quit)
|
||||
break;
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
interruped = true;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if(interruped)
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return snapshotId;
|
||||
}
|
||||
|
||||
protected long getInstanceIdFromJobSuccessResult(String result) {
|
||||
CreateSnapshotResultObject resultObject = (CreateSnapshotResultObject)SerializerHelper.fromSerializedString(result);
|
||||
if(resultObject != null) {
|
||||
return resultObject.getId();
|
||||
}
|
||||
return 0;
|
||||
return SerializerHelper.toSerializedString(response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import com.cloud.api.commands.AssignPortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.CreateDomainCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceRuleCmd;
|
||||
import com.cloud.api.commands.CreateSnapshotCmd;
|
||||
import com.cloud.api.commands.CreateUserCmd;
|
||||
import com.cloud.api.commands.DeletePortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.DeleteUserCmd;
|
||||
@ -1113,18 +1114,6 @@ public interface ManagementServer {
|
||||
List<CapacityVO> listCapacities(ListCapacityCmd cmd);
|
||||
|
||||
public long getMemoryUsagebyHost(Long hostId);
|
||||
|
||||
/**
|
||||
* Create a snapshot of a volume
|
||||
* @param userId the user for whom this snapshot is being created
|
||||
* @param volumeId the id of the volume
|
||||
* @return the Snapshot that was created
|
||||
* @throws InternalErrorException
|
||||
*/
|
||||
long createSnapshotAsync(long userId, long volumeId)
|
||||
throws InvalidParameterValueException,
|
||||
ResourceAllocationException,
|
||||
InternalErrorException;
|
||||
|
||||
/**
|
||||
* @param userId The Id of the user who invoked this operation.
|
||||
|
||||
@ -58,6 +58,7 @@ import com.cloud.api.commands.AssignPortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.CreateDomainCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceCmd;
|
||||
import com.cloud.api.commands.CreatePortForwardingServiceRuleCmd;
|
||||
import com.cloud.api.commands.CreateSnapshotCmd;
|
||||
import com.cloud.api.commands.CreateUserCmd;
|
||||
import com.cloud.api.commands.CreateVolumeCmd;
|
||||
import com.cloud.api.commands.DeletePortForwardingServiceCmd;
|
||||
@ -207,6 +208,7 @@ import com.cloud.storage.LaunchPermissionVO;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.storage.Snapshot.SnapshotType;
|
||||
import com.cloud.storage.SnapshotPolicyVO;
|
||||
import com.cloud.storage.SnapshotScheduleVO;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
@ -5270,42 +5272,6 @@ public class ManagementServerImpl implements ManagementServer {
|
||||
return mem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long createSnapshotAsync(long userId, long volumeId)
|
||||
throws InvalidParameterValueException,
|
||||
ResourceAllocationException,
|
||||
InternalErrorException
|
||||
{
|
||||
VolumeVO volume = findVolumeById(volumeId); // not null, precondition.
|
||||
if (volume.getStatus() != AsyncInstanceCreateStatus.Created) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in Created state but " + volume.getStatus() + ". Cannot take snapshot.");
|
||||
}
|
||||
StoragePoolVO storagePoolVO = findPoolById(volume.getPoolId());
|
||||
if (storagePoolVO == null) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " does not have a valid storage pool. Is it destroyed?");
|
||||
}
|
||||
if (storagePoolVO.isLocal()) {
|
||||
throw new InvalidParameterValueException("Cannot create a snapshot from a volume residing on a local storage pool, poolId: " + volume.getPoolId());
|
||||
}
|
||||
|
||||
Long instanceId = volume.getInstanceId();
|
||||
if (instanceId != null) {
|
||||
// It is not detached, but attached to a VM
|
||||
if (findUserVMInstanceById(instanceId) == null) {
|
||||
// It is not a UserVM but a SystemVM or DomR
|
||||
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.");
|
||||
}
|
||||
|
||||
return jobId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotVO createTemplateSnapshot(Long userId, long volumeId) {
|
||||
return _vmMgr.createTemplateSnapshot(userId, volumeId);
|
||||
|
||||
@ -19,6 +19,7 @@ package com.cloud.storage.snapshot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.api.commands.CreateSnapshotCmd;
|
||||
import com.cloud.api.commands.CreateSnapshotPolicyCmd;
|
||||
import com.cloud.api.commands.DeleteSnapshotCmd;
|
||||
import com.cloud.api.commands.DeleteSnapshotPoliciesCmd;
|
||||
@ -46,51 +47,38 @@ public interface SnapshotManager extends Manager {
|
||||
public static final int WEEKLYMAX = 8;
|
||||
public static final int MONTHLYMAX = 8;
|
||||
|
||||
/**
|
||||
* This is the synchronous version of the below command.
|
||||
* @throws ResourceAllocationException
|
||||
* @throws InvalidParameterValueException
|
||||
/**
|
||||
* 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
|
||||
* @throws InternalErrorException
|
||||
*/
|
||||
SnapshotVO createSnapshot(long userId, long volumeId, List<Long> policies) throws InvalidParameterValueException, ResourceAllocationException;
|
||||
SnapshotVO createSnapshotDB(CreateSnapshotCmd cmd) throws InvalidParameterValueException, ResourceAllocationException, InternalErrorException;
|
||||
|
||||
/**
|
||||
* Creates a snapshot for the given volume
|
||||
* 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
|
||||
* @throws InternalErrorException
|
||||
*/
|
||||
long createSnapshotAsync(long userId, long volumeId, List<Long> policies);
|
||||
SnapshotVO createSnapshot(CreateSnapshotCmd cmd) throws InvalidParameterValueException, ResourceAllocationException, InternalErrorException;
|
||||
|
||||
/**
|
||||
* After successfully creating a snapshot of a volume, copy the snapshot to the secondary storage for
|
||||
* 1) reliability
|
||||
* 2) So that storage space on Primary is conserved.
|
||||
* @param userId The user who invoked this command.
|
||||
* @param snapshot Info about the created snapshot on primary storage.
|
||||
* @return True if the snapshot was successfully backed up.
|
||||
* 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
|
||||
* @throws InternalErrorException
|
||||
*/
|
||||
public boolean backupSnapshotToSecondaryStorage(long userId, SnapshotVO snapshot);
|
||||
|
||||
/**
|
||||
* Once a snapshot has completed,
|
||||
* 1) If success, update the database entries
|
||||
* 2) If success and there are excess snapshots for any of the policies given, delete the oldest one.
|
||||
* 3) Schedule the next recurring snapshot.
|
||||
* @param userId The user who executed this command
|
||||
* @param volumeId The volume for which the snapshot is being taken
|
||||
* @param snapshotId The snapshot which has just completed
|
||||
* @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);
|
||||
|
||||
SnapshotVO createSnapshotImpl(long volumeId, List<Long> policyIds) throws InvalidParameterValueException, ResourceAllocationException, InternalErrorException;
|
||||
|
||||
/**
|
||||
* Creates a volume from the specified snapshot. A new volume is returned which is not attached to any VM Instance
|
||||
*/
|
||||
//VolumeVO createVolumeFromSnapshot(long userId, long accountId, long snapshotId, String volumeName);
|
||||
long createVolumeFromSnapshotAsync(long userId, long accountId, long snapshotId, String volumeName) throws InternalErrorException;
|
||||
|
||||
/**
|
||||
* Destroys the specified snapshot from secondary storage
|
||||
*/
|
||||
// long destroySnapshotAsync(long userId, long volumeId, long snapshotId, long policyId);
|
||||
boolean destroySnapshot(long userId, long snapshotId, long policyId);
|
||||
|
||||
/**
|
||||
|
||||
@ -48,6 +48,7 @@ import com.cloud.api.commands.DeleteSnapshotCmd;
|
||||
import com.cloud.api.commands.DeleteSnapshotPoliciesCmd;
|
||||
import com.cloud.api.commands.ListRecurringSnapshotScheduleCmd;
|
||||
import com.cloud.api.commands.ListSnapshotPoliciesCmd;
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.async.AsyncJobExecutor;
|
||||
import com.cloud.async.AsyncJobManager;
|
||||
import com.cloud.async.AsyncJobVO;
|
||||
@ -149,22 +150,6 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
protected SearchBuilder<SnapshotPolicyVO> PoliciesForSnapSearch;
|
||||
|
||||
private final boolean _shouldBeSnapshotCapable = true; // all methods here should be snapshot capable.
|
||||
|
||||
@Override @DB
|
||||
public long createSnapshotAsync(long userId, long volumeId, List<Long> policies) {
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
SnapshotOperationParam param = new SnapshotOperationParam(userId, volume.getAccountId(), volumeId, policies);
|
||||
Gson gson = GsonHelper.getBuilder().create();
|
||||
|
||||
AsyncJobVO job = new AsyncJobVO();
|
||||
job.setUserId(userId);
|
||||
job.setAccountId(volume.getAccountId());
|
||||
job.setCmd("CreateSnapshot");
|
||||
job.setCmdInfo(gson.toJson(param));
|
||||
job.setCmdOriginator(CreateSnapshotCmd.getResultObjectName());
|
||||
|
||||
return _asyncMgr.submitAsyncJob(job, true);
|
||||
}
|
||||
|
||||
private boolean isVolumeDirty(long volumeId, List<Long> policies) {
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
@ -275,9 +260,48 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
|
||||
return runSnap;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SnapshotVO createSnapshotDB(CreateSnapshotCmd cmd) throws InvalidParameterValueException, ResourceAllocationException, InternalErrorException {
|
||||
// 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.
|
||||
if (volume.getStatus() != AsyncInstanceCreateStatus.Created) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in Created state but " + volume.getStatus() + ". Cannot take snapshot.");
|
||||
}
|
||||
StoragePoolVO storagePoolVO = _storagePoolDao.findById(volume.getPoolId());
|
||||
if (storagePoolVO == null) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " does not have a valid storage pool. Is it destroyed?");
|
||||
}
|
||||
if (storagePoolVO.isLocal()) {
|
||||
throw new InvalidParameterValueException("Cannot create a snapshot from a volume residing on a local storage pool, poolId: " + volume.getPoolId());
|
||||
}
|
||||
|
||||
Long instanceId = volume.getInstanceId();
|
||||
if (instanceId != null) {
|
||||
// It is not detached, but attached to a VM
|
||||
if (_vmDao.findById(instanceId) == null) {
|
||||
// It is not a UserVM but a SystemVM or DomR
|
||||
throw new InvalidParameterValueException("Snapshots of volumes attached to System or router VM are not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
SnapshotScheduleVO schedule = _snapSchedMgr.scheduleManualSnapshot(volumeId);
|
||||
if (schedule == null) {
|
||||
throw new InternalErrorException("Snapshot could not be scheduled because there is another snapshot underway for the same volume. " +
|
||||
"Please wait for some time.");
|
||||
}
|
||||
|
||||
List<Long> policyIds = new ArrayList<Long>();
|
||||
policyIds.add(Snapshot.MANUAL_POLICY_ID);
|
||||
|
||||
return createSnapshotImpl(volumeId, policyIds);
|
||||
}
|
||||
|
||||
@Override @DB
|
||||
public SnapshotVO createSnapshot(long userId, long volumeId, List<Long> policyIds) throws InvalidParameterValueException, ResourceAllocationException {
|
||||
public SnapshotVO createSnapshotImpl(long volumeId, List<Long> policyIds) throws InvalidParameterValueException, ResourceAllocationException {
|
||||
Long userId = UserContext.current().getUserId();
|
||||
// Get the async job id from the context.
|
||||
Long jobId = null;
|
||||
AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor();
|
||||
@ -316,7 +340,7 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
if (prevSnapshot.getRemoved() != null && snapshotStatus != Status.BackedUp) {
|
||||
// The snapshot was deleted and it was deleted not manually but because backing up failed.
|
||||
// Try to back it up again.
|
||||
boolean backedUp = backupSnapshotToSecondaryStorage(userId, prevSnapshot);
|
||||
boolean backedUp = backupSnapshotToSecondaryStorage(prevSnapshot);
|
||||
if (!backedUp) {
|
||||
// If we can't backup this snapshot, there's not much chance that we can't take another one and back it up again.
|
||||
return null;
|
||||
@ -398,6 +422,30 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
return createdSnapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotVO createSnapshot(CreateSnapshotCmd cmd) throws InvalidParameterValueException, ResourceAllocationException, InternalErrorException {
|
||||
SnapshotVO snapshot = _snapshotDao.findById(cmd.getId());
|
||||
Long snapshotId = null;
|
||||
boolean backedUp = false;
|
||||
if (snapshot != null && snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary) {
|
||||
snapshotId = snapshot.getId();
|
||||
backedUp = backupSnapshotToSecondaryStorage(snapshot);
|
||||
if (!backedUp) {
|
||||
throw new InternalErrorException("Created snapshot: " + snapshotId + " on primary but failed to backup on secondary");
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: this is for create snapshot through the API, which is a manual snapshot, is there a better way to keep track of policy ids? Like
|
||||
// add them to the command?
|
||||
List<Long> policyIds = new ArrayList<Long>();
|
||||
policyIds.add(Snapshot.MANUAL_POLICY_ID);
|
||||
|
||||
// Cleanup jobs to do after the snapshot has been created.
|
||||
postCreateSnapshot(cmd.getVolumeId(), snapshotId, policyIds, backedUp);
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private SnapshotVO updateDBOnCreate(Long id, String snapshotPath) {
|
||||
SnapshotVO createdSnapshot = _snapshotDao.findById(id);
|
||||
Long volumeId = createdSnapshot.getVolumeId();
|
||||
@ -473,16 +521,16 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
// It has entered backupSnapshotToSecondaryStorage.
|
||||
// But we have no idea whether it was backed up or not.
|
||||
// So call backupSnapshotToSecondaryStorage again.
|
||||
backupSnapshotToSecondaryStorage(userId, snapshot);
|
||||
backupSnapshotToSecondaryStorage(snapshot);
|
||||
break;
|
||||
case BackedUp:
|
||||
// No need to do anything as snapshot has already been backed up.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public boolean backupSnapshotToSecondaryStorage(long userId, SnapshotVO snapshot) {
|
||||
private boolean backupSnapshotToSecondaryStorage(SnapshotVO snapshot) {
|
||||
Long userId = UserContext.current().getUserId();
|
||||
long id = snapshot.getId();
|
||||
|
||||
snapshot.setStatus(Snapshot.Status.BackingUp);
|
||||
@ -674,9 +722,9 @@ public class SnapshotManagerImpl implements SnapshotManager {
|
||||
return backedUp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public void postCreateSnapshot(long userId, long volumeId, long snapshotId, List<Long> policyIds, boolean backedUp) {
|
||||
private void postCreateSnapshot(long volumeId, long snapshotId, List<Long> policyIds, boolean backedUp) {
|
||||
Long userId = UserContext.current().getUserId();
|
||||
// Update the snapshot_policy_ref table with the created snapshot
|
||||
// Get the list of policies for this snapshot
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
|
||||
@ -20,6 +20,7 @@ package com.cloud.storage.snapshot;
|
||||
import java.util.Date;
|
||||
|
||||
import com.cloud.storage.SnapshotPolicyVO;
|
||||
import com.cloud.storage.SnapshotScheduleVO;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.utils.concurrency.Scheduler;
|
||||
|
||||
@ -45,6 +46,5 @@ public interface SnapshotScheduler extends Manager, Scheduler {
|
||||
*/
|
||||
boolean removeSchedule(Long volumeId, Long policyId);
|
||||
|
||||
Long scheduleManualSnapshot(Long userId, Long volumeId);
|
||||
|
||||
SnapshotScheduleVO scheduleManualSnapshot(Long volumeId);
|
||||
}
|
||||
|
||||
@ -35,6 +35,9 @@ 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.exception.InternalErrorException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.storage.SnapshotPolicyVO;
|
||||
import com.cloud.storage.SnapshotScheduleVO;
|
||||
@ -45,8 +48,8 @@ import com.cloud.storage.dao.SnapshotPolicyRefDao;
|
||||
import com.cloud.storage.dao.SnapshotScheduleDao;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.utils.DateUtil;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.DateUtil.IntervalType;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.component.ComponentLocator;
|
||||
import com.cloud.utils.component.Inject;
|
||||
import com.cloud.utils.concurrency.TestClock;
|
||||
@ -199,7 +202,7 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler {
|
||||
*/
|
||||
@Override
|
||||
@DB
|
||||
public Long scheduleManualSnapshot(Long userId, Long volumeId) {
|
||||
public SnapshotScheduleVO scheduleManualSnapshot(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);
|
||||
@ -219,10 +222,14 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler {
|
||||
// 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);
|
||||
return _snapshotScheduleDao.persist(snapshotSchedule);
|
||||
|
||||
// do this for async?
|
||||
/*
|
||||
List<Long> policyIds = new ArrayList<Long>();
|
||||
policyIds.add(Snapshot.MANUAL_POLICY_ID);
|
||||
return _snapshotManager.createSnapshotAsync(userId, volumeId, policyIds);
|
||||
*/
|
||||
}
|
||||
|
||||
@DB
|
||||
@ -233,10 +240,6 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler {
|
||||
List<SnapshotScheduleVO> snapshotsToBeExecuted = _snapshotScheduleDao.getSchedulesToExecute(_currentTimestamp);
|
||||
s_logger.debug("Got " + snapshotsToBeExecuted.size() + " snapshots to be executed at " + displayTime);
|
||||
|
||||
// This is done for recurring snapshots, which are executed by the system automatically
|
||||
// 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.
|
||||
@ -295,14 +298,24 @@ public class SnapshotSchedulerImpl implements SnapshotScheduler {
|
||||
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);
|
||||
|
||||
try {
|
||||
_snapshotManager.createSnapshotImpl(volumeId, coincidingPolicies);
|
||||
} catch (InternalErrorException ex) {
|
||||
s_logger.warn("Internal error creating a recurring snapshot for volume " + volumeId + "; message: " + ex.getMessage());
|
||||
// TODO: update the schedule w/ an error? error event?
|
||||
} catch (ResourceAllocationException ex) {
|
||||
s_logger.warn("Too many snapshots have been created for volume " + volumeId + "; message: " + ex.getMessage());
|
||||
// TODO: update the schedule w/ an error? error event?
|
||||
} catch (InvalidParameterValueException ex) {
|
||||
s_logger.warn("Invalid parameter creating a snapshot for volume " + volumeId + "; message: " + ex.getMessage());
|
||||
// TODO: update the schedule w/ an error? error event?
|
||||
}
|
||||
|
||||
// Add this snapshot to the listOfVolumesSnapshotted
|
||||
// So that the coinciding schedules don't get scheduled again.
|
||||
listOfVolumesSnapshotted.put(volumeId, coincidingPolicies);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user