mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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:
parent
5f90aa971a
commit
29687663e8
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
public SnapshotServiceImpl() {
|
||||
|
||||
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;
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
@ -171,9 +171,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
private ResourceLimitService _resourceLimitMgr;
|
||||
@Inject
|
||||
private SwiftManager _swiftMgr;
|
||||
@Inject
|
||||
@Inject
|
||||
private S3Manager _s3Mgr;
|
||||
@Inject
|
||||
@Inject
|
||||
private SecondaryStorageVmManager _ssvmMgr;
|
||||
@Inject
|
||||
private DomainManager _domainMgr;
|
||||
@ -182,17 +182,17 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
@Inject
|
||||
private ConfigurationDao _configDao;
|
||||
|
||||
@Inject
|
||||
@Inject
|
||||
private VMSnapshotDao _vmSnapshotDao;
|
||||
String _name;
|
||||
|
||||
@Inject TemplateManager templateMgr;
|
||||
@Inject VolumeManager volumeMgr;
|
||||
@Inject DataStoreManager dataStoreMgr;
|
||||
@Inject List<SnapshotStrategy> snapshotStrategies;
|
||||
@Inject SnapshotService snapshotSrv;
|
||||
@Inject VolumeDataFactory volFactory;
|
||||
@Inject SnapshotDataFactory snapshotFactory;
|
||||
|
||||
|
||||
|
||||
private int _totalRetries;
|
||||
private int _pauseInterval;
|
||||
@ -201,14 +201,14 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
|
||||
protected SearchBuilder<SnapshotVO> PolicySnapshotSearch;
|
||||
protected SearchBuilder<SnapshotPolicyVO> PoliciesForSnapSearch;
|
||||
|
||||
|
||||
@Override
|
||||
public Answer sendToPool(Volume vol, Command cmd) {
|
||||
StoragePool pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(vol.getPoolId());
|
||||
long[] hostIdsToTryFirst = null;
|
||||
|
||||
|
||||
Long vmHostId = getHostIdForSnapshotOperation(vol);
|
||||
|
||||
|
||||
if (vmHostId != null) {
|
||||
hostIdsToTryFirst = new long[] { vmHostId };
|
||||
}
|
||||
@ -263,29 +263,22 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (volume == null) {
|
||||
throw new InvalidParameterValueException("No such volume exist");
|
||||
}
|
||||
|
||||
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new InvalidParameterValueException("Volume is not in ready state");
|
||||
}
|
||||
|
||||
|
||||
SnapshotInfo snapshot = null;
|
||||
|
||||
|
||||
boolean backedUp = false;
|
||||
// does the caller have the authority to act on this volume
|
||||
_accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume);
|
||||
|
||||
|
||||
|
||||
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
|
||||
@ -344,20 +337,13 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (snapshot == null) {
|
||||
throw new CloudRuntimeException("Can't find snapshot:" + snapshotId);
|
||||
}
|
||||
|
||||
|
||||
if (snapshot.getState() == Snapshot.State.BackedUp) {
|
||||
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
|
||||
@ -394,7 +380,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
} catch (Exception e) {
|
||||
throw new CloudRuntimeException("downloadSnapshotsFromSwift failed due to " + e.toString());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private List<String> determineBackupUuids(final SnapshotVO snapshot) {
|
||||
@ -445,7 +431,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SnapshotVO getParentSnapshot(VolumeInfo volume, Snapshot snapshot) {
|
||||
long preId = _snapshotDao.getLastSnapshot(volume.getId(), snapshot.getId());
|
||||
@ -454,7 +440,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) {
|
||||
preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId);
|
||||
}
|
||||
|
||||
|
||||
return preSnapshotVO;
|
||||
}
|
||||
|
||||
@ -475,7 +461,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
snapshotSchedule.setSnapshotId(snapshotId);
|
||||
_snapshotScheduleDao.update(snapshotSchedule.getId(), snapshotSchedule);
|
||||
}
|
||||
|
||||
|
||||
if (snapshot != null && snapshot.isRecursive()) {
|
||||
postCreateRecurringSnapshotForPolicy(userId, volumeId, snapshotId, policyId);
|
||||
}
|
||||
@ -515,18 +501,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (snapshotCheck == null) {
|
||||
throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId);
|
||||
}
|
||||
|
||||
|
||||
_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(),
|
||||
@ -573,7 +552,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
String snapshotTypeStr = cmd.getSnapshotType();
|
||||
String intervalTypeStr = cmd.getIntervalType();
|
||||
Map<String, String> tags = cmd.getTags();
|
||||
|
||||
|
||||
Account caller = UserContext.current().getCaller();
|
||||
List<Long> permittedAccounts = new ArrayList<Long>();
|
||||
|
||||
@ -589,8 +568,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
|
||||
Long domainId = domainIdRecursiveListProject.first();
|
||||
Boolean isRecursive = domainIdRecursiveListProject.second();
|
||||
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
||||
|
||||
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
||||
|
||||
Filter searchFilter = new Filter(SnapshotVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||
SearchBuilder<SnapshotVO> sb = _snapshotDao.createSearchBuilder();
|
||||
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||
@ -601,7 +580,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
|
||||
sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.IN);
|
||||
sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ);
|
||||
|
||||
|
||||
if (tags != null && !tags.isEmpty()) {
|
||||
SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
|
||||
for (int count=0; count < tags.size(); count++) {
|
||||
@ -620,7 +599,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (volumeId != null) {
|
||||
sc.setParameters("volumeId", volumeId);
|
||||
}
|
||||
|
||||
|
||||
if (tags != null && !tags.isEmpty()) {
|
||||
int count = 0;
|
||||
sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.Snapshot.toString());
|
||||
@ -765,9 +744,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (volume == null) {
|
||||
throw new InvalidParameterValueException("Failed to create snapshot policy, unable to find a volume with id " + volumeId);
|
||||
}
|
||||
|
||||
|
||||
_accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume);
|
||||
|
||||
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot.");
|
||||
}
|
||||
@ -823,7 +802,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT) {
|
||||
message = "domain/project";
|
||||
}
|
||||
|
||||
|
||||
throw new InvalidParameterValueException("Max number of snapshots shouldn't exceed the " + message + " level snapshot limit");
|
||||
}
|
||||
|
||||
@ -869,11 +848,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
return new Pair<List<? extends SnapshotPolicy>, Integer>(result.first(), result.second());
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<SnapshotPolicyVO> listPoliciesforVolume(long volumeId) {
|
||||
return _snapshotPolicyDao.listByVolumeId(volumeId);
|
||||
}
|
||||
|
||||
|
||||
private List<SnapshotVO> listSnapsforVolume(long volumeId) {
|
||||
return _snapshotDao.listByVolumeId(volumeId);
|
||||
}
|
||||
@ -961,7 +940,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
@Override
|
||||
public SnapshotVO allocSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException {
|
||||
Account caller = UserContext.current().getCaller();
|
||||
|
||||
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
if (volume == null) {
|
||||
throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
|
||||
@ -970,11 +949,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
if (zone == null) {
|
||||
throw new InvalidParameterValueException("Can't find zone by id " + volume.getDataCenterId());
|
||||
}
|
||||
|
||||
|
||||
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
|
||||
throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zone.getName());
|
||||
}
|
||||
|
||||
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot.");
|
||||
}
|
||||
@ -985,7 +964,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is for System VM , Creating snapshot against System VM volumes is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StoragePoolVO storagePoolVO = _storagePoolDao.findById(volume.getPoolId());
|
||||
if (storagePoolVO == null) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it");
|
||||
@ -1030,7 +1009,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
String snapshotName = vmDisplayName + "_" + volume.getName() + "_" + timeString;
|
||||
|
||||
// Create the Snapshot object and save it so we can return it to the
|
||||
// user
|
||||
// user
|
||||
HypervisorType hypervisorType = this._volsDao.getHypervisorType(volumeId);
|
||||
SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), null, snapshotName,
|
||||
(short) snapshotType.ordinal(), snapshotType.name(), volume.getSize(), hypervisorType);
|
||||
@ -1050,7 +1029,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
|
||||
|
||||
String value = _configDao.getValue(Config.BackupSnapshotWait.toString());
|
||||
_backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
|
||||
backup = Boolean.parseBoolean(this._configDao.getValue(Config.BackupSnapshotAferTakingSnapshot.toString()));
|
||||
@ -1124,7 +1103,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canOperateOnVolume(Volume volume) {
|
||||
List<SnapshotVO> snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user