mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Snapshot support
This commit is contained in:
parent
45611a0f83
commit
06f6b00cd1
@ -26,6 +26,9 @@ import com.cloud.agent.api.to.VirtualMachineTO;
|
|||||||
import com.cloud.host.Host;
|
import com.cloud.host.Host;
|
||||||
|
|
||||||
public interface DataMotionStrategy {
|
public interface DataMotionStrategy {
|
||||||
|
// IQN is used by the StorageSystemDataMotionStrategy to create a template from a snapshot or clone that resides on a storage system
|
||||||
|
public static final String IQN = "iqn";
|
||||||
|
|
||||||
StrategyPriority canHandle(DataObject srcData, DataObject destData);
|
StrategyPriority canHandle(DataObject srcData, DataObject destData);
|
||||||
|
|
||||||
StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
|
StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
|
||||||
|
|||||||
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.motion;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||||
|
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.VirtualMachineTO;
|
||||||
|
import com.cloud.host.Host;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
|
||||||
|
private static final Logger s_logger = Logger.getLogger(StorageSystemDataMotionStrategy.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StrategyPriority canHandle(DataObject srcData, DataObject destData) {
|
||||||
|
return StrategyPriority.DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
|
||||||
|
return StrategyPriority.CANT_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||||
|
return copyAsync(srcData, destData, null, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
|
||||||
|
CopyCommandResult result = new CopyCommandResult(null, null);
|
||||||
|
|
||||||
|
result.setResult("Unsupported operation requested for copying data.");
|
||||||
|
|
||||||
|
callback.complete(result);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,6 +26,7 @@ import javax.inject.Inject;
|
|||||||
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
|
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.CreateCmdResult;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
@ -523,11 +524,27 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
|
|
||||||
long sfSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, snapshotInfo.getUuid());
|
long sfSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, snapshotInfo.getUuid());
|
||||||
|
|
||||||
// Now that we have successfully taken a snapshot, update the space usage in the storage_pool table (even
|
long sfCloneId;
|
||||||
// though storage_pool.used_bytes is likely no longer in use).
|
String sfCloneIqn;
|
||||||
|
|
||||||
|
try {
|
||||||
|
sfCloneId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, snapshotInfo.getUuid());
|
||||||
|
|
||||||
|
SolidFireUtil.SolidFireVolume sfClonedVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfCloneId);
|
||||||
|
|
||||||
|
sfCloneIqn = sfClonedVolume.getIqn();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, sfSnapshotId);
|
||||||
|
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we have successfully taken a snapshot (for the purpose of reverting) and a clone (for the purpose of creating a template
|
||||||
|
// and a volume), update the space usage in the storage_pool table (even though storage_pool.used_bytes is likely no longer in use).
|
||||||
_storagePoolDao.update(storagePoolId, storagePool);
|
_storagePoolDao.update(storagePoolId, storagePool);
|
||||||
|
|
||||||
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize);
|
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize, sfCloneId, sfCloneIqn);
|
||||||
|
|
||||||
SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
|
SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
|
||||||
|
|
||||||
@ -550,7 +567,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
callback.complete(result);
|
callback.complete(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSnapshotDetails(long csSnapshotId, long sfSnapshotId, long storagePoolId, long sfSnapshotSize) {
|
private void updateSnapshotDetails(long csSnapshotId, long sfSnapshotId, long storagePoolId, long sfSnapshotSize, long sfCloneId, String sfCloneIqn) {
|
||||||
SnapshotDetailsVO accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
SnapshotDetailsVO accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||||
SolidFireUtil.SNAPSHOT_ID,
|
SolidFireUtil.SNAPSHOT_ID,
|
||||||
String.valueOf(sfSnapshotId),
|
String.valueOf(sfSnapshotId),
|
||||||
@ -571,6 +588,20 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
false);
|
false);
|
||||||
|
|
||||||
_snapshotDetailsDao.persist(accountDetail);
|
_snapshotDetailsDao.persist(accountDetail);
|
||||||
|
|
||||||
|
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||||
|
SolidFireUtil.CLONE_ID,
|
||||||
|
String.valueOf(sfCloneId),
|
||||||
|
false);
|
||||||
|
|
||||||
|
_snapshotDetailsDao.persist(accountDetail);
|
||||||
|
|
||||||
|
accountDetail = new SnapshotDetailsVO(csSnapshotId,
|
||||||
|
DataMotionStrategy.IQN,
|
||||||
|
sfCloneIqn,
|
||||||
|
false);
|
||||||
|
|
||||||
|
_snapshotDetailsDao.persist(accountDetail);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return null for no error message
|
// return null for no error message
|
||||||
@ -581,6 +612,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||||
|
|
||||||
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, getSolidFireSnapshotId(snapshotInfo.getId()));
|
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, getSolidFireSnapshotId(snapshotInfo.getId()));
|
||||||
|
SolidFireUtil.deleteSolidFireVolume(sfConnection, getSolidFireCloneId(snapshotInfo.getId()));
|
||||||
|
|
||||||
_snapshotDetailsDao.removeDetails(snapshotInfo.getId());
|
_snapshotDetailsDao.removeDetails(snapshotInfo.getId());
|
||||||
|
|
||||||
@ -608,6 +640,12 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
return Long.parseLong(snapshotDetails.getValue());
|
return Long.parseLong(snapshotDetails.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getSolidFireCloneId(long csSnapshotId) {
|
||||||
|
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.CLONE_ID);
|
||||||
|
|
||||||
|
return Long.parseLong(snapshotDetails.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void revertSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<CommandResult> callback) {
|
public void revertSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<CommandResult> callback) {
|
||||||
String errMsg = null;
|
String errMsg = null;
|
||||||
|
|||||||
@ -703,10 +703,10 @@ public class SolidFireUtil {
|
|||||||
verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson);
|
verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, String cloneName) {
|
public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, String cloneName) {
|
||||||
final Gson gson = new GsonBuilder().create();
|
final Gson gson = new GsonBuilder().create();
|
||||||
|
|
||||||
CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, cloneName);
|
CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, lSnapshotId, cloneName);
|
||||||
|
|
||||||
String strCloneToCreateJson = gson.toJson(cloneToCreate);
|
String strCloneToCreateJson = gson.toJson(cloneToCreate);
|
||||||
|
|
||||||
@ -1332,16 +1332,18 @@ public class SolidFireUtil {
|
|||||||
private final String method = "CloneVolume";
|
private final String method = "CloneVolume";
|
||||||
private final CloneToCreateParams params;
|
private final CloneToCreateParams params;
|
||||||
|
|
||||||
private CloneToCreate(final long lVolumeId, final String cloneName) {
|
private CloneToCreate(final long lVolumeId, final long lSnapshotId, final String cloneName) {
|
||||||
params = new CloneToCreateParams(lVolumeId, cloneName);
|
params = new CloneToCreateParams(lVolumeId, lSnapshotId, cloneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class CloneToCreateParams {
|
private static final class CloneToCreateParams {
|
||||||
private long volumeID;
|
private long volumeID;
|
||||||
|
private long snapshotID;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private CloneToCreateParams(final long lVolumeId, final String cloneName) {
|
private CloneToCreateParams(final long lVolumeId, final long lSnapshotId, final String cloneName) {
|
||||||
volumeID = lVolumeId;
|
volumeID = lVolumeId;
|
||||||
|
snapshotID = lSnapshotId;
|
||||||
name = cloneName;
|
name = cloneName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,7 @@ import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissions
|
|||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
|
||||||
@ -1376,12 +1377,20 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||||||
throw new CloudRuntimeException("cannot find an image store for zone " + zoneId);
|
throw new CloudRuntimeException("cannot find an image store for zone " + zoneId);
|
||||||
}
|
}
|
||||||
AsyncCallFuture<TemplateApiResult> future = null;
|
AsyncCallFuture<TemplateApiResult> future = null;
|
||||||
|
|
||||||
if (snapshotId != null) {
|
if (snapshotId != null) {
|
||||||
SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
|
DataStoreRole dataStoreRole = getDataStoreRole(snapshot);
|
||||||
|
|
||||||
|
SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole);
|
||||||
|
|
||||||
|
if (dataStoreRole == DataStoreRole.Image) {
|
||||||
DataStore snapStore = snapInfo.getDataStore();
|
DataStore snapStore = snapInfo.getDataStore();
|
||||||
|
|
||||||
if (snapStore != null) {
|
if (snapStore != null) {
|
||||||
store = snapStore; // pick snapshot image store to create template
|
store = snapStore; // pick snapshot image store to create template
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store);
|
future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store);
|
||||||
} else if (volumeId != null) {
|
} else if (volumeId != null) {
|
||||||
VolumeInfo volInfo = _volFactory.getVolume(volumeId);
|
VolumeInfo volInfo = _volFactory.getVolume(volumeId);
|
||||||
@ -1465,6 +1474,25 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataStoreRole getDataStoreRole(Snapshot snapshot) {
|
||||||
|
long volumeId = snapshot.getVolumeId();
|
||||||
|
VolumeVO volumeVO = _volumeDao.findById(volumeId);
|
||||||
|
|
||||||
|
long storagePoolId = volumeVO.getPoolId();
|
||||||
|
DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
|
||||||
|
|
||||||
|
Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities();
|
||||||
|
|
||||||
|
String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString());
|
||||||
|
Boolean supportsStorageSystemSnapshots = new Boolean(value);
|
||||||
|
|
||||||
|
if (supportsStorageSystemSnapshots) {
|
||||||
|
return DataStoreRole.Primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataStoreRole.Image;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true)
|
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true)
|
||||||
public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException {
|
public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user