Rename SnapshotStrategy to SnapshotService to have consistent naming

convention for Template, Snapshot, Volume. Also rename CopyCmd to
CopyCommand to follow internal command naming convention.
This commit is contained in:
Min Chen 2013-04-22 16:15:57 -07:00
parent 5f90aa971a
commit 29687663e8
12 changed files with 617 additions and 715 deletions

View File

@ -31,7 +31,7 @@ import com.cloud.storage.Volume;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
public interface SnapshotService {
public interface SnapshotApiService {
/**
* List all snapshots of a disk volume. Optionally lists snapshots created by specified interval

View File

@ -64,7 +64,7 @@ import com.cloud.server.TaggedResourceService;
import com.cloud.storage.DataStoreProviderApiService;
import com.cloud.storage.StorageService;
import com.cloud.storage.VolumeApiService;
import com.cloud.storage.snapshot.SnapshotService;
import com.cloud.storage.snapshot.SnapshotApiService;
import com.cloud.template.TemplateApiService;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
@ -108,7 +108,7 @@ public abstract class BaseCmd {
@Inject public NetworkService _networkService;
@Inject public TemplateApiService _templateService;
@Inject public SecurityGroupService _securityGroupService;
@Inject public SnapshotService _snapshotService;
@Inject public SnapshotApiService _snapshotService;
@Inject public ConsoleProxyService _consoleProxyService;
@Inject public VpcVirtualNetworkApplianceService _routerService;
@Inject public ResponseGenerator _responseGenerator;

View File

@ -48,7 +48,7 @@ import java.util.concurrent.Callable;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
import org.apache.cloudstack.storage.command.CopyCmd;
import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
@ -215,14 +215,14 @@ SecondaryStorageResource {
return execute((DeleteTemplateFromS3Command) cmd);
} else if (cmd instanceof CleanupSnapshotBackupCommand){
return execute((CleanupSnapshotBackupCommand)cmd);
} else if (cmd instanceof CopyCmd) {
return execute((CopyCmd)cmd);
} else if (cmd instanceof CopyCommand) {
return execute((CopyCommand)cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
}
protected Answer downloadFromS3ToNfs(CopyCmd cmd, DataTO srcData, S3TO s3,
protected Answer downloadFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3,
DataTO destData, NfsTO destImageStore) {
final String storagePath = destImageStore.getUrl();
final String destPath = destData.getPath();
@ -265,12 +265,12 @@ SecondaryStorageResource {
}
}
protected Answer downloadFromSwiftToNfs(CopyCmd cmd, DataTO srcData, SwiftTO srcImageStore,
protected Answer downloadFromSwiftToNfs(CopyCommand cmd, DataTO srcData, SwiftTO srcImageStore,
DataTO destData, NfsTO destImageStore) {
return Answer.createUnsupportedCommandAnswer(cmd);
}
protected Answer execute(CopyCmd cmd) {
protected Answer execute(CopyCommand cmd) {
DataTO srcData = cmd.getSrcTO();
DataTO destData = cmd.getDestTO();
DataStoreTO srcDataStore = srcData.getDataStore();

View File

@ -18,8 +18,7 @@
package org.apache.cloudstack.engine.subsystem.api.storage;
public interface SnapshotStrategy {
public boolean canHandle(SnapshotInfo snapshot);
public interface SnapshotService {
public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId);
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
public boolean deleteSnapshot(SnapshotInfo snapshot);

View File

@ -20,7 +20,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
import com.cloud.agent.api.Command;
public class CopyCmd extends Command implements StorageSubSystemCommand {
public class CopyCommand extends Command implements StorageSubSystemCommand {
private DataTO srcTO;
private DataTO destTO;
private int timeout;
@ -39,7 +39,7 @@ public class CopyCmd extends Command implements StorageSubSystemCommand {
this.timeout = timeout;
}
public CopyCmd(DataTO srcUri, DataTO destUri, int timeout) {
public CopyCommand(DataTO srcUri, DataTO destUri, int timeout) {
super();
this.srcTO = srcUri;
this.destTO = destUri;

View File

@ -35,7 +35,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.storage.command.CopyCmd;
import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.log4j.Logger;
@ -194,13 +194,13 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
//need to copy it to image cache store
DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope());
CopyCmd cmd = new CopyCmd(cacheData.getTO(), destData.getTO(), _primaryStorageDownloadWait);
CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _primaryStorageDownloadWait);
EndPoint ep = selector.select(cacheData, destData);
Answer answer = ep.sendMessage(cmd);
return answer;
} else {
//handle copy it to cache store
CopyCmd cmd = new CopyCmd(srcData.getTO(), destData.getTO(), _primaryStorageDownloadWait);
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _primaryStorageDownloadWait);
EndPoint ep = selector.select(srcData, destData);
Answer answer = ep.sendMessage(cmd);
return answer;

View File

@ -187,19 +187,6 @@ public class DirectAgentManagerSimpleImpl extends ManagerBase implements AgentMa
return null;
}
@Override
public void sendToSecStorage(DataStore ssStore, Command cmd, Listener listener) throws AgentUnavailableException {
// TODO Auto-generated method stub
}
@Override
public Answer sendToSecStorage(DataStore ssStore, Command cmd) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean tapLoadingAgents(Long hostId, TapAgentsAction action) {
// TODO Auto-generated method stub

View File

@ -14,29 +14,571 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.snapshot;
import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcConext;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.resource.ResourceManager;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VolumeManager;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
public class SnapshotServiceImpl implements SnapshotService {
private static final Logger s_logger = Logger.getLogger(SnapshotServiceImpl.class);
@Inject
protected VolumeDao _volsDao;
@Inject
protected UserVmDao _vmDao;
@Inject
protected PrimaryDataStoreDao _storagePoolDao;
@Inject
protected ClusterDao _clusterDao;
@Inject
protected SnapshotDao _snapshotDao;
@Inject
private ResourceManager _resourceMgr;
@Inject
protected SnapshotManager snapshotMgr;
@Inject
protected VolumeManager volumeMgr;
@Inject
private ConfigurationDao _configDao;
@Inject
protected SnapshotStateMachineManager stateMachineManager;
@Inject
private VolumeDao volumeDao;
@Inject
SnapshotDataFactory snapshotfactory;
@Inject
DataStoreManager dataStoreMgr;
@Inject
DataMotionService motionSrv;
@Inject
ObjectInDataStoreManager objInStoreMgr;
@Inject
VMSnapshotDao _vmSnapshotDao;
public SnapshotServiceImpl() {
static private class CreateSnapshotContext<T> extends AsyncRpcConext<T> {
final VolumeInfo volume;
final SnapshotInfo snapshot;
final AsyncCallFuture<SnapshotResult> future;
public CreateSnapshotContext(AsyncCompletionCallback<T> callback, VolumeInfo volume,
SnapshotInfo snapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.volume = volume;
this.snapshot = snapshot;
this.future = future;
}
}
static private class DeleteSnapshotContext<T> extends AsyncRpcConext<T> {
final SnapshotInfo snapshot;
final AsyncCallFuture<SnapshotResult> future;
public DeleteSnapshotContext(AsyncCompletionCallback<T> callback, SnapshotInfo snapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.snapshot = snapshot;
this.future = future;
}
}
static private class CopySnapshotContext<T> extends AsyncRpcConext<T> {
final SnapshotInfo srcSnapshot;
final SnapshotInfo destSnapshot;
final AsyncCallFuture<SnapshotResult> future;
public CopySnapshotContext(AsyncCompletionCallback<T> callback,
SnapshotInfo srcSnapshot,
SnapshotInfo destSnapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.srcSnapshot = srcSnapshot;
this.destSnapshot = destSnapshot;
this.future = future;
}
}
protected Void createSnapshotAsyncCallback(AsyncCallbackDispatcher<SnapshotServiceImpl, CreateCmdResult> callback,
CreateSnapshotContext<CreateCmdResult> context) {
CreateCmdResult result = callback.getResult();
SnapshotObject snapshot = (SnapshotObject)context.snapshot;
VolumeInfo volume = context.volume;
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotResult snapResult = new SnapshotResult(snapshot);
if (result.isFailed()) {
s_logger.debug("create snapshot " + context.snapshot.getName() + " failed: " + result.getResult());
try {
snapshot.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
}
snapResult.setResult(result.getResult());
future.complete(snapResult);
return null;
}
try {
SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot);
String preSnapshotPath = null;
if (preSnapshotVO != null) {
preSnapshotPath = preSnapshotVO.getPath();
}
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshot.getId());
// The snapshot was successfully created
if (preSnapshotPath != null && preSnapshotPath.equals(result.getPath())) {
// empty snapshot
s_logger.debug("CreateSnapshot: this is empty snapshot ");
snapshotVO.setPath(preSnapshotPath);
snapshotVO.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId());
snapshotVO.setSwiftId(preSnapshotVO.getSwiftId());
snapshotVO.setPrevSnapshotId(preSnapshotVO.getId());
snapshotVO.setSecHostId(preSnapshotVO.getSecHostId());
snapshot.processEvent(Snapshot.Event.OperationNotPerformed);
} else {
long preSnapshotId = 0;
if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) {
preSnapshotId = preSnapshotVO.getId();
int _deltaSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("snapshot.delta.max"), SnapshotManager.DELTAMAX);
int deltaSnap = _deltaSnapshotMax;
int i;
for (i = 1; i < deltaSnap; i++) {
String prevBackupUuid = preSnapshotVO.getBackupSnapshotId();
// previous snapshot doesn't have backup, create a full snapshot
if (prevBackupUuid == null) {
preSnapshotId = 0;
break;
}
long preSSId = preSnapshotVO.getPrevSnapshotId();
if (preSSId == 0) {
break;
}
preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preSSId);
}
if (i >= deltaSnap) {
preSnapshotId = 0;
}
}
//If the volume is moved around, backup a full snapshot to secondary storage
if (volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId())) {
preSnapshotId = 0;
//TODO: fix this hack
VolumeVO volumeVO = this.volumeDao.findById(volume.getId());
volumeVO.setLastPoolId(volume.getPoolId());
this.volumeDao.update(volume.getId(), volumeVO);
}
snapshot.setPath(result.getPath());
snapshot.setPrevSnapshotId(preSnapshotId);
snapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(snapshot.getId()));
}
} catch (Exception e) {
s_logger.debug("Failed to create snapshot: ", e);
snapResult.setResult(e.toString());
try {
snapshot.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.debug("Failed to change snapshot state: " + e1.toString());
}
}
future.complete(snapResult);
return null;
}
class SnapshotResult extends CommandResult {
SnapshotInfo snashot;
public SnapshotResult(SnapshotInfo snapshot) {
this.snashot = snapshot;
}
}
protected SnapshotInfo createSnapshotOnPrimary(VolumeInfo volume, Long snapshotId) {
SnapshotObject snapshot = (SnapshotObject)this.snapshotfactory.getSnapshot(snapshotId);
if (snapshot == null) {
throw new CloudRuntimeException("Can not find snapshot " + snapshotId);
}
try {
snapshot.processEvent(Snapshot.Event.CreateRequested);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
throw new CloudRuntimeException("Failed to update snapshot state due to " + nte.getMessage());
}
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
try {
CreateSnapshotContext<CommandResult> context = new CreateSnapshotContext<CommandResult>(
null, volume, snapshot, future);
AsyncCallbackDispatcher<SnapshotServiceImpl, CreateCmdResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().createSnapshotAsyncCallback(null, null))
.setContext(context);
PrimaryDataStoreDriver primaryStore = (PrimaryDataStoreDriver)volume.getDataStore().getDriver();
primaryStore.takeSnapshot(snapshot, caller);
} catch (Exception e) {
s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e);
try {
snapshot.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.debug("Failed to change state for event: OperationFailed" , e);
}
throw new CloudRuntimeException("Failed to take snapshot" + snapshot.getId());
}
SnapshotResult result;
try {
result = future.get();
if (result.isFailed()) {
s_logger.debug("Failed to create snapshot:" + result.getResult());
throw new CloudRuntimeException(result.getResult());
}
return result.snashot;
} catch (InterruptedException e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
} catch (ExecutionException e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
}
}
private boolean hostSupportSnapsthot(HostVO host) {
if (host.getHypervisorType() != HypervisorType.KVM) {
return true;
}
// Determine host capabilities
String caps = host.getCapabilities();
if (caps != null) {
String[] tokens = caps.split(",");
for (String token : tokens) {
if (token.contains("snapshot")) {
return true;
}
}
}
return false;
}
protected boolean supportedByHypervisor(VolumeInfo volume) {
if (volume.getHypervisorType().equals(HypervisorType.KVM)) {
StoragePool storagePool = (StoragePool)volume.getDataStore();
ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId());
List<HostVO> hosts = _resourceMgr.listAllHostsInCluster(cluster.getId());
if (hosts != null && !hosts.isEmpty()) {
HostVO host = hosts.get(0);
if (!hostSupportSnapsthot(host)) {
throw new CloudRuntimeException("KVM Snapshot is not supported on cluster: " + host.getId());
}
}
}
// if volume is attached to a vm in destroyed or expunging state; disallow
if (volume.getInstanceId() != null) {
UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
if (userVm != null) {
if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) {
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volume.getId() + " is associated with vm:" + userVm.getInstanceName() + " is in "
+ userVm.getState().toString() + " state");
}
if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) {
List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
if(activeSnapshots.size() > 1)
throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later");
}
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(),
VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
if (activeVMSnapshots.size() > 0) {
throw new CloudRuntimeException(
"There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
}
}
}
return true;
}
@Override
public SnapshotEntity getSnapshotEntity(long snapshotId) {
// TODO Auto-generated method stub
public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId) {
supportedByHypervisor(volume);
SnapshotInfo snapshot = createSnapshotOnPrimary(volume, snapshotId);
return snapshot;
}
@Override
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) {
SnapshotObject snapObj = (SnapshotObject)snapshot;
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
SnapshotResult result = new SnapshotResult(snapshot);
try {
snapObj.processEvent(Snapshot.Event.BackupToSecondary);
ZoneScope scope = new ZoneScope(snapshot.getDataCenterId());
List<DataStore> stores = this.dataStoreMgr.getImageStoresByScope(scope);
if (stores.size() != 1) {
throw new CloudRuntimeException("find out more than one image stores");
}
DataStore imageStore = stores.get(0);
SnapshotInfo snapshotOnImageStore = (SnapshotInfo)imageStore.create(snapshot);
snapshotOnImageStore.processEvent(Event.CreateOnlyRequested);
CopySnapshotContext<CommandResult> context = new CopySnapshotContext<CommandResult>(null, snapshot,
snapshotOnImageStore, future);
AsyncCallbackDispatcher<SnapshotServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().copySnapshotAsyncCallback(null, null))
.setContext(context);
this.motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller);
} catch (Exception e) {
s_logger.debug("Failed to copy snapshot", e);
result.setResult("Failed to copy snapshot:" +e.toString());
try {
snapObj.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.debug("Failed to change state: " + e1.toString());
}
future.complete(result);
}
try {
SnapshotResult res = future.get();
SnapshotInfo destSnapshot = res.snashot;
return destSnapshot;
} catch (InterruptedException e) {
s_logger.debug("failed copy snapshot", e);
throw new CloudRuntimeException("Failed to copy snapshot" , e);
} catch (ExecutionException e) {
s_logger.debug("Failed to copy snapshot", e);
throw new CloudRuntimeException("Failed to copy snapshot" , e);
}
}
protected Void copySnapshotAsyncCallback(AsyncCallbackDispatcher<SnapshotServiceImpl, CopyCommandResult> callback,
CopySnapshotContext<CommandResult> context) {
CopyCommandResult result = callback.getResult();
SnapshotInfo destSnapshot = context.destSnapshot;
SnapshotObject srcSnapshot = (SnapshotObject)context.srcSnapshot;
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotResult snapResult = new SnapshotResult(destSnapshot);
if (result.isFailed()) {
snapResult.setResult(result.getResult());
future.complete(snapResult);
return null;
}
try {
BackupSnapshotAnswer answer = (BackupSnapshotAnswer)result.getAnswer();
DataObjectInStore dataInStore = objInStoreMgr.findObject(destSnapshot, destSnapshot.getDataStore());
dataInStore.setInstallPath(answer.getBackupSnapshotName());
objInStoreMgr.update(destSnapshot, Event.OperationSuccessed);
srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId()));
future.complete(snapResult);
} catch (Exception e) {
s_logger.debug("Failed to update snapshot state", e);
snapResult.setResult(e.toString());
future.complete(snapResult);
}
return null;
}
@DB
protected boolean destroySnapshotBackUp(SnapshotVO snapshot) {
DataStore store = objInStoreMgr.findStore(snapshot.getId(), DataObjectType.SNAPSHOT, DataStoreRole.Image);
if (store == null) {
s_logger.debug("Can't find snapshot" + snapshot.getId() + " backed up into image store");
return false;
}
try {
SnapshotInfo snapshotInfo = this.snapshotfactory.getSnapshot(snapshot.getId(), store);
snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested);
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
DeleteSnapshotContext<CommandResult> context = new DeleteSnapshotContext<CommandResult>(null,
snapshotInfo, future);
AsyncCallbackDispatcher<SnapshotServiceImpl, CommandResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().deleteSnapshotCallback(null, null))
.setContext(context);
store.getDriver().deleteAsync(snapshotInfo, caller);
SnapshotResult result = future.get();
if (result.isFailed()) {
s_logger.debug("Failed to delete snapsoht: " + result.getResult());
}
return result.isSuccess();
} catch (Exception e) {
s_logger.debug("Failed to delete snapshot", e);
return false;
}
}
protected Void deleteSnapshotCallback(AsyncCallbackDispatcher<SnapshotServiceImpl, CommandResult> callback,
DeleteSnapshotContext<CommandResult> context) {
CommandResult result = callback.getResult();
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotInfo snapshot = context.snapshot;
if (result.isFailed()) {
s_logger.debug("delete snapshot failed" + result.getResult());
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
SnapshotResult res = new SnapshotResult(context.snapshot);
future.complete(res);
return null;
}
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed);
SnapshotResult res = new SnapshotResult(context.snapshot);
future.complete(res);
return null;
}
@Override
public boolean takeSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
public boolean deleteSnapshot(SnapshotInfo snapInfo) {
Long snapshotId = snapInfo.getId();
SnapshotObject snapshot = (SnapshotObject)snapInfo;
if (!Snapshot.State.BackedUp.equals(snapshot.getState())) {
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
}
SnapshotVO lastSnapshot = null;
if (snapshot.getBackupSnapshotId() != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
if (snaps != null && snaps.size() > 1) {
snapshot.setBackupSnapshotId(null);
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
_snapshotDao.update(snapshot.getId(), snapshotVO);
}
}
_snapshotDao.remove(snapshotId);
long lastId = snapshotId;
boolean destroy = false;
while (true) {
lastSnapshot = _snapshotDao.findNextSnapshot(lastId);
if (lastSnapshot == null) {
// if all snapshots after this snapshot in this chain are removed, remove those snapshots.
destroy = true;
break;
}
if (lastSnapshot.getRemoved() == null) {
// if there is one child not removed, then can not remove back up snapshot.
break;
}
lastId = lastSnapshot.getId();
}
if (destroy) {
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
while (lastSnapshot.getRemoved() != null) {
String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
if (BackupSnapshotId != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId);
if (snaps != null && snaps.size() > 1) {
lastSnapshot.setBackupSnapshotId(null);
_snapshotDao.update(lastSnapshot.getId(), lastSnapshot);
} else {
if (destroySnapshotBackUp(lastSnapshot)) {
} else {
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
break;
}
}
}
lastId = lastSnapshot.getPrevSnapshotId();
if (lastId == 0) {
break;
}
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
}
}
return true;
}
@Override
@ -45,12 +587,4 @@ public class SnapshotServiceImpl implements SnapshotService {
return false;
}
@Override
public boolean deleteSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -1,597 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.snapshot.strategy;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcConext;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.snapshot.SnapshotObject;
import org.apache.cloudstack.storage.snapshot.SnapshotStateMachineManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.resource.ResourceManager;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VolumeManager;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
public class AncientSnapshotStrategy implements SnapshotStrategy {
private static final Logger s_logger = Logger.getLogger(AncientSnapshotStrategy.class);
@Inject
protected VolumeDao _volsDao;
@Inject
protected UserVmDao _vmDao;
@Inject
protected PrimaryDataStoreDao _storagePoolDao;
@Inject
protected ClusterDao _clusterDao;
@Inject
protected SnapshotDao snapshotDao;
@Inject
private ResourceManager _resourceMgr;
@Inject
protected SnapshotDao _snapshotDao;
@Inject
protected SnapshotManager snapshotMgr;
@Inject
protected VolumeManager volumeMgr;
@Inject
private ConfigurationDao _configDao;
@Inject
protected SnapshotStateMachineManager stateMachineManager;
@Inject
private VolumeDao volumeDao;
@Inject
SnapshotDataFactory snapshotfactory;
@Inject
DataStoreManager dataStoreMgr;
@Inject
DataMotionService motionSrv;
@Inject
ObjectInDataStoreManager objInStoreMgr;
@Inject
VMSnapshotDao _vmSnapshotDao;
@Override
public boolean canHandle(SnapshotInfo snapshot) {
return true;
}
static private class CreateSnapshotContext<T> extends AsyncRpcConext<T> {
final VolumeInfo volume;
final SnapshotInfo snapshot;
final AsyncCallFuture<SnapshotResult> future;
public CreateSnapshotContext(AsyncCompletionCallback<T> callback, VolumeInfo volume,
SnapshotInfo snapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.volume = volume;
this.snapshot = snapshot;
this.future = future;
}
}
static private class DeleteSnapshotContext<T> extends AsyncRpcConext<T> {
final SnapshotInfo snapshot;
final AsyncCallFuture<SnapshotResult> future;
public DeleteSnapshotContext(AsyncCompletionCallback<T> callback, SnapshotInfo snapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.snapshot = snapshot;
this.future = future;
}
}
static private class CopySnapshotContext<T> extends AsyncRpcConext<T> {
final SnapshotInfo srcSnapshot;
final SnapshotInfo destSnapshot;
final AsyncCallFuture<SnapshotResult> future;
public CopySnapshotContext(AsyncCompletionCallback<T> callback,
SnapshotInfo srcSnapshot,
SnapshotInfo destSnapshot,
AsyncCallFuture<SnapshotResult> future) {
super(callback);
this.srcSnapshot = srcSnapshot;
this.destSnapshot = destSnapshot;
this.future = future;
}
}
protected Void createSnapshotAsyncCallback(AsyncCallbackDispatcher<AncientSnapshotStrategy, CreateCmdResult> callback,
CreateSnapshotContext<CreateCmdResult> context) {
CreateCmdResult result = callback.getResult();
SnapshotObject snapshot = (SnapshotObject)context.snapshot;
VolumeInfo volume = context.volume;
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotResult snapResult = new SnapshotResult(snapshot);
if (result.isFailed()) {
s_logger.debug("create snapshot " + context.snapshot.getName() + " failed: " + result.getResult());
try {
snapshot.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
}
snapResult.setResult(result.getResult());
future.complete(snapResult);
return null;
}
try {
SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot);
String preSnapshotPath = null;
if (preSnapshotVO != null) {
preSnapshotPath = preSnapshotVO.getPath();
}
SnapshotVO snapshotVO = this.snapshotDao.findById(snapshot.getId());
// The snapshot was successfully created
if (preSnapshotPath != null && preSnapshotPath.equals(result.getPath())) {
// empty snapshot
s_logger.debug("CreateSnapshot: this is empty snapshot ");
snapshotVO.setPath(preSnapshotPath);
snapshotVO.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId());
snapshotVO.setSwiftId(preSnapshotVO.getSwiftId());
snapshotVO.setPrevSnapshotId(preSnapshotVO.getId());
snapshotVO.setSecHostId(preSnapshotVO.getSecHostId());
snapshot.processEvent(Snapshot.Event.OperationNotPerformed);
} else {
long preSnapshotId = 0;
if (preSnapshotVO != null && preSnapshotVO.getBackupSnapshotId() != null) {
preSnapshotId = preSnapshotVO.getId();
int _deltaSnapshotMax = NumbersUtil.parseInt(_configDao.getValue("snapshot.delta.max"), SnapshotManager.DELTAMAX);
int deltaSnap = _deltaSnapshotMax;
int i;
for (i = 1; i < deltaSnap; i++) {
String prevBackupUuid = preSnapshotVO.getBackupSnapshotId();
// previous snapshot doesn't have backup, create a full snapshot
if (prevBackupUuid == null) {
preSnapshotId = 0;
break;
}
long preSSId = preSnapshotVO.getPrevSnapshotId();
if (preSSId == 0) {
break;
}
preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preSSId);
}
if (i >= deltaSnap) {
preSnapshotId = 0;
}
}
//If the volume is moved around, backup a full snapshot to secondary storage
if (volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId())) {
preSnapshotId = 0;
//TODO: fix this hack
VolumeVO volumeVO = this.volumeDao.findById(volume.getId());
volumeVO.setLastPoolId(volume.getPoolId());
this.volumeDao.update(volume.getId(), volumeVO);
}
snapshot.setPath(result.getPath());
snapshot.setPrevSnapshotId(preSnapshotId);
snapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(snapshot.getId()));
}
} catch (Exception e) {
s_logger.debug("Failed to create snapshot: ", e);
snapResult.setResult(e.toString());
try {
snapshot.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.debug("Failed to change snapshot state: " + e1.toString());
}
}
future.complete(snapResult);
return null;
}
class SnapshotResult extends CommandResult {
SnapshotInfo snashot;
public SnapshotResult(SnapshotInfo snapshot) {
this.snashot = snapshot;
}
}
protected SnapshotInfo createSnapshotOnPrimary(VolumeInfo volume, Long snapshotId) {
SnapshotObject snapshot = (SnapshotObject)this.snapshotfactory.getSnapshot(snapshotId);
if (snapshot == null) {
throw new CloudRuntimeException("Can not find snapshot " + snapshotId);
}
try {
snapshot.processEvent(Snapshot.Event.CreateRequested);
} catch (NoTransitionException nte) {
s_logger.debug("Failed to update snapshot state due to " + nte.getMessage());
throw new CloudRuntimeException("Failed to update snapshot state due to " + nte.getMessage());
}
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
try {
CreateSnapshotContext<CommandResult> context = new CreateSnapshotContext<CommandResult>(
null, volume, snapshot, future);
AsyncCallbackDispatcher<AncientSnapshotStrategy, CreateCmdResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().createSnapshotAsyncCallback(null, null))
.setContext(context);
PrimaryDataStoreDriver primaryStore = (PrimaryDataStoreDriver)volume.getDataStore().getDriver();
primaryStore.takeSnapshot(snapshot, caller);
} catch (Exception e) {
s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e);
try {
snapshot.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.debug("Failed to change state for event: OperationFailed" , e);
}
throw new CloudRuntimeException("Failed to take snapshot" + snapshot.getId());
}
SnapshotResult result;
try {
result = future.get();
if (result.isFailed()) {
s_logger.debug("Failed to create snapshot:" + result.getResult());
throw new CloudRuntimeException(result.getResult());
}
return result.snashot;
} catch (InterruptedException e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
} catch (ExecutionException e) {
s_logger.debug("Failed to create snapshot", e);
throw new CloudRuntimeException("Failed to create snapshot", e);
}
}
private boolean hostSupportSnapsthot(HostVO host) {
if (host.getHypervisorType() != HypervisorType.KVM) {
return true;
}
// Determine host capabilities
String caps = host.getCapabilities();
if (caps != null) {
String[] tokens = caps.split(",");
for (String token : tokens) {
if (token.contains("snapshot")) {
return true;
}
}
}
return false;
}
protected boolean supportedByHypervisor(VolumeInfo volume) {
if (volume.getHypervisorType().equals(HypervisorType.KVM)) {
StoragePool storagePool = (StoragePool)volume.getDataStore();
ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId());
List<HostVO> hosts = _resourceMgr.listAllHostsInCluster(cluster.getId());
if (hosts != null && !hosts.isEmpty()) {
HostVO host = hosts.get(0);
if (!hostSupportSnapsthot(host)) {
throw new CloudRuntimeException("KVM Snapshot is not supported on cluster: " + host.getId());
}
}
}
// if volume is attached to a vm in destroyed or expunging state; disallow
if (volume.getInstanceId() != null) {
UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
if (userVm != null) {
if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) {
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volume.getId() + " is associated with vm:" + userVm.getInstanceName() + " is in "
+ userVm.getState().toString() + " state");
}
if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) {
List<SnapshotVO> activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
if(activeSnapshots.size() > 1)
throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later");
}
List<VMSnapshotVO> activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(),
VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging);
if (activeVMSnapshots.size() > 0) {
throw new CloudRuntimeException(
"There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
}
}
}
return true;
}
@Override
public SnapshotInfo takeSnapshot(VolumeInfo volume, Long snapshotId) {
supportedByHypervisor(volume);
SnapshotInfo snapshot = createSnapshotOnPrimary(volume, snapshotId);
return snapshot;
}
@Override
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) {
SnapshotObject snapObj = (SnapshotObject)snapshot;
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
SnapshotResult result = new SnapshotResult(snapshot);
try {
snapObj.processEvent(Snapshot.Event.BackupToSecondary);
ZoneScope scope = new ZoneScope(snapshot.getDataCenterId());
List<DataStore> stores = this.dataStoreMgr.getImageStoresByScope(scope);
if (stores.size() != 1) {
throw new CloudRuntimeException("find out more than one image stores");
}
DataStore imageStore = stores.get(0);
SnapshotInfo snapshotOnImageStore = (SnapshotInfo)imageStore.create(snapshot);
snapshotOnImageStore.processEvent(Event.CreateOnlyRequested);
CopySnapshotContext<CommandResult> context = new CopySnapshotContext<CommandResult>(null, snapshot,
snapshotOnImageStore, future);
AsyncCallbackDispatcher<AncientSnapshotStrategy, CopyCommandResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().copySnapshotAsyncCallback(null, null))
.setContext(context);
this.motionSrv.copyAsync(snapshot, snapshotOnImageStore, caller);
} catch (Exception e) {
s_logger.debug("Failed to copy snapshot", e);
result.setResult("Failed to copy snapshot:" +e.toString());
try {
snapObj.processEvent(Snapshot.Event.OperationFailed);
} catch (NoTransitionException e1) {
s_logger.debug("Failed to change state: " + e1.toString());
}
future.complete(result);
}
try {
SnapshotResult res = future.get();
SnapshotInfo destSnapshot = res.snashot;
return destSnapshot;
} catch (InterruptedException e) {
s_logger.debug("failed copy snapshot", e);
throw new CloudRuntimeException("Failed to copy snapshot" , e);
} catch (ExecutionException e) {
s_logger.debug("Failed to copy snapshot", e);
throw new CloudRuntimeException("Failed to copy snapshot" , e);
}
}
protected Void copySnapshotAsyncCallback(AsyncCallbackDispatcher<AncientSnapshotStrategy, CopyCommandResult> callback,
CopySnapshotContext<CommandResult> context) {
CopyCommandResult result = callback.getResult();
SnapshotInfo destSnapshot = context.destSnapshot;
SnapshotObject srcSnapshot = (SnapshotObject)context.srcSnapshot;
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotResult snapResult = new SnapshotResult(destSnapshot);
if (result.isFailed()) {
snapResult.setResult(result.getResult());
future.complete(snapResult);
return null;
}
try {
BackupSnapshotAnswer answer = (BackupSnapshotAnswer)result.getAnswer();
DataObjectInStore dataInStore = objInStoreMgr.findObject(destSnapshot, destSnapshot.getDataStore());
dataInStore.setInstallPath(answer.getBackupSnapshotName());
objInStoreMgr.update(destSnapshot, Event.OperationSuccessed);
srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(this.snapshotfactory.getSnapshot(destSnapshot.getId()));
future.complete(snapResult);
} catch (Exception e) {
s_logger.debug("Failed to update snapshot state", e);
snapResult.setResult(e.toString());
future.complete(snapResult);
}
return null;
}
@DB
protected boolean destroySnapshotBackUp(SnapshotVO snapshot) {
DataStore store = objInStoreMgr.findStore(snapshot.getId(), DataObjectType.SNAPSHOT, DataStoreRole.Image);
if (store == null) {
s_logger.debug("Can't find snapshot" + snapshot.getId() + " backed up into image store");
return false;
}
try {
SnapshotInfo snapshotInfo = this.snapshotfactory.getSnapshot(snapshot.getId(), store);
snapshotInfo.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested);
AsyncCallFuture<SnapshotResult> future = new AsyncCallFuture<SnapshotResult>();
DeleteSnapshotContext<CommandResult> context = new DeleteSnapshotContext<CommandResult>(null,
snapshotInfo, future);
AsyncCallbackDispatcher<AncientSnapshotStrategy, CommandResult> caller = AsyncCallbackDispatcher
.create(this);
caller.setCallback(
caller.getTarget().deleteSnapshotCallback(null, null))
.setContext(context);
store.getDriver().deleteAsync(snapshotInfo, caller);
SnapshotResult result = future.get();
if (result.isFailed()) {
s_logger.debug("Failed to delete snapsoht: " + result.getResult());
}
return result.isSuccess();
} catch (Exception e) {
s_logger.debug("Failed to delete snapshot", e);
return false;
}
}
protected Void deleteSnapshotCallback(AsyncCallbackDispatcher<AncientSnapshotStrategy, CommandResult> callback,
DeleteSnapshotContext<CommandResult> context) {
CommandResult result = callback.getResult();
AsyncCallFuture<SnapshotResult> future = context.future;
SnapshotInfo snapshot = context.snapshot;
if (result.isFailed()) {
s_logger.debug("delete snapshot failed" + result.getResult());
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed);
SnapshotResult res = new SnapshotResult(context.snapshot);
future.complete(res);
return null;
}
snapshot.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed);
SnapshotResult res = new SnapshotResult(context.snapshot);
future.complete(res);
return null;
}
@Override
public boolean deleteSnapshot(SnapshotInfo snapInfo) {
Long snapshotId = snapInfo.getId();
SnapshotObject snapshot = (SnapshotObject)snapInfo;
if (!Snapshot.State.BackedUp.equals(snapshot.getState())) {
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
}
SnapshotVO lastSnapshot = null;
if (snapshot.getBackupSnapshotId() != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
if (snaps != null && snaps.size() > 1) {
snapshot.setBackupSnapshotId(null);
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
_snapshotDao.update(snapshot.getId(), snapshotVO);
}
}
_snapshotDao.remove(snapshotId);
long lastId = snapshotId;
boolean destroy = false;
while (true) {
lastSnapshot = _snapshotDao.findNextSnapshot(lastId);
if (lastSnapshot == null) {
// if all snapshots after this snapshot in this chain are removed, remove those snapshots.
destroy = true;
break;
}
if (lastSnapshot.getRemoved() == null) {
// if there is one child not removed, then can not remove back up snapshot.
break;
}
lastId = lastSnapshot.getId();
}
if (destroy) {
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
while (lastSnapshot.getRemoved() != null) {
String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
if (BackupSnapshotId != null) {
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId);
if (snaps != null && snaps.size() > 1) {
lastSnapshot.setBackupSnapshotId(null);
_snapshotDao.update(lastSnapshot.getId(), lastSnapshot);
} else {
if (destroySnapshotBackUp(lastSnapshot)) {
} else {
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
break;
}
}
}
lastId = lastSnapshot.getPrevSnapshotId();
if (lastId == 0) {
break;
}
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
}
}
return true;
}
@Override
public boolean revertSnapshot(SnapshotInfo snapshot) {
// TODO Auto-generated method stub
return false;
}
}

View File

@ -6,7 +6,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.storage.command.CopyCmd;
import org.apache.cloudstack.storage.command.CopyCommand;
import com.cloud.agent.Listener;
import com.cloud.agent.api.Answer;
@ -32,7 +32,7 @@ public class LocalHostEndpoint implements EndPoint {
@Override
public Answer sendMessage(Command cmd) {
if (cmd instanceof CopyCmd) {
if (cmd instanceof CopyCommand) {
return resource.executeRequest(cmd);
}
// TODO Auto-generated method stub

View File

@ -34,7 +34,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer;
import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd;
import org.apache.cloudstack.storage.command.CopyCmd;
import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
import org.apache.cloudstack.storage.command.CreateObjectCommand;
@ -84,8 +84,8 @@ public class XenServerStorageResource {
}
public Answer handleStorageCommands(StorageSubSystemCommand command) {
if (command instanceof CopyCmd) {
return this.execute((CopyCmd)command);
if (command instanceof CopyCommand) {
return this.execute((CopyCommand)command);
} else if (command instanceof AttachPrimaryDataStoreCmd) {
return this.execute((AttachPrimaryDataStoreCmd)command);
} else if (command instanceof CreatePrimaryDataStoreCmd) {
@ -505,7 +505,7 @@ public class XenServerStorageResource {
}
protected Answer directDownloadHttpTemplate(CopyCmd cmd, DecodedDataObject srcObj, DecodedDataObject destObj) {
protected Answer directDownloadHttpTemplate(CopyCommand cmd, DecodedDataObject srcObj, DecodedDataObject destObj) {
Connection conn = hypervisorResource.getConnection();
SR poolsr = null;
VDI vdi = null;
@ -724,7 +724,7 @@ public class XenServerStorageResource {
}
protected Answer execute(CopyCmd cmd) {
protected Answer execute(CopyCommand cmd) {
DataTO srcData = cmd.getSrcTO();
DataTO destData = cmd.getDestTO();

View File

@ -34,7 +34,7 @@ import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -126,8 +126,8 @@ import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
@Component
@Local(value = { SnapshotManager.class, SnapshotService.class })
public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotService {
@Local(value = { SnapshotManager.class, SnapshotApiService.class })
public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotApiService {
private static final Logger s_logger = Logger.getLogger(SnapshotManagerImpl.class);
@Inject
protected VMTemplateDao _templateDao;
@ -189,7 +189,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
@Inject TemplateManager templateMgr;
@Inject VolumeManager volumeMgr;
@Inject DataStoreManager dataStoreMgr;
@Inject List<SnapshotStrategy> snapshotStrategies;
@Inject SnapshotService snapshotSrv;
@Inject VolumeDataFactory volFactory;
@Inject SnapshotDataFactory snapshotFactory;
@ -276,16 +276,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
SnapshotInfo snap = this.snapshotFactory.getSnapshot(snapshotId);
SnapshotStrategy strategy = null;
for (SnapshotStrategy st : snapshotStrategies) {
if (st.canHandle(snap)) {
strategy = st;
break;
}
}
try {
snapshot = strategy.takeSnapshot(volume, snapshotId);
snapshot = this.snapshotSrv.takeSnapshot(volume, snapshotId);
if (snapshot != null) {
postCreateSnapshot(volumeId, snapshot.getId(), policyId);
//Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event
@ -349,15 +342,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
return snapshot;
}
SnapshotStrategy strategy = null;
for (SnapshotStrategy st : snapshotStrategies) {
if (st.canHandle(snapshot)) {
strategy = st;
break;
}
}
return strategy.backupSnapshot(snapshot);
return this.snapshotSrv.backupSnapshot(snapshot);
}
@Override
@ -518,15 +504,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
_accountMgr.checkAccess(caller, null, true, snapshotCheck);
SnapshotStrategy strategy = null;
for (SnapshotStrategy st : snapshotStrategies) {
if (st.canHandle(snapshotCheck)) {
strategy = st;
break;
}
}
try {
boolean result = strategy.deleteSnapshot(snapshotCheck);
boolean result = this.snapshotSrv.deleteSnapshot(snapshotCheck);
if (result) {
if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(),