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;
|
||||
|
||||
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(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.CopyCommandResult;
|
||||
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.DataObject;
|
||||
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());
|
||||
|
||||
// Now that we have successfully taken a snapshot, update the space usage in the storage_pool table (even
|
||||
// though storage_pool.used_bytes is likely no longer in use).
|
||||
long sfCloneId;
|
||||
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);
|
||||
|
||||
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize);
|
||||
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize, sfCloneId, sfCloneIqn);
|
||||
|
||||
SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
|
||||
|
||||
@ -550,7 +567,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
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,
|
||||
SolidFireUtil.SNAPSHOT_ID,
|
||||
String.valueOf(sfSnapshotId),
|
||||
@ -571,6 +588,20 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
false);
|
||||
|
||||
_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
|
||||
@ -581,6 +612,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
|
||||
|
||||
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, getSolidFireSnapshotId(snapshotInfo.getId()));
|
||||
SolidFireUtil.deleteSolidFireVolume(sfConnection, getSolidFireCloneId(snapshotInfo.getId()));
|
||||
|
||||
_snapshotDetailsDao.removeDetails(snapshotInfo.getId());
|
||||
|
||||
@ -608,6 +640,12 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
||||
return Long.parseLong(snapshotDetails.getValue());
|
||||
}
|
||||
|
||||
private long getSolidFireCloneId(long csSnapshotId) {
|
||||
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.CLONE_ID);
|
||||
|
||||
return Long.parseLong(snapshotDetails.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revertSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<CommandResult> callback) {
|
||||
String errMsg = null;
|
||||
|
||||
@ -703,10 +703,10 @@ public class SolidFireUtil {
|
||||
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();
|
||||
|
||||
CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, cloneName);
|
||||
CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, lSnapshotId, cloneName);
|
||||
|
||||
String strCloneToCreateJson = gson.toJson(cloneToCreate);
|
||||
|
||||
@ -1332,16 +1332,18 @@ public class SolidFireUtil {
|
||||
private final String method = "CloneVolume";
|
||||
private final CloneToCreateParams params;
|
||||
|
||||
private CloneToCreate(final long lVolumeId, final String cloneName) {
|
||||
params = new CloneToCreateParams(lVolumeId, cloneName);
|
||||
private CloneToCreate(final long lVolumeId, final long lSnapshotId, final String cloneName) {
|
||||
params = new CloneToCreateParams(lVolumeId, lSnapshotId, cloneName);
|
||||
}
|
||||
|
||||
private static final class CloneToCreateParams {
|
||||
private long volumeID;
|
||||
private long snapshotID;
|
||||
private String name;
|
||||
|
||||
private CloneToCreateParams(final long lVolumeId, final String cloneName) {
|
||||
private CloneToCreateParams(final long lVolumeId, final long lSnapshotId, final String cloneName) {
|
||||
volumeID = lVolumeId;
|
||||
snapshotID = lSnapshotId;
|
||||
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.engine.orchestration.service.VolumeOrchestrationService;
|
||||
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.EndPoint;
|
||||
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);
|
||||
}
|
||||
AsyncCallFuture<TemplateApiResult> future = null;
|
||||
|
||||
if (snapshotId != null) {
|
||||
SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
|
||||
DataStore snapStore = snapInfo.getDataStore();
|
||||
if (snapStore != null) {
|
||||
store = snapStore; // pick snapshot image store to create template
|
||||
DataStoreRole dataStoreRole = getDataStoreRole(snapshot);
|
||||
|
||||
SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole);
|
||||
|
||||
if (dataStoreRole == DataStoreRole.Image) {
|
||||
DataStore snapStore = snapInfo.getDataStore();
|
||||
|
||||
if (snapStore != null) {
|
||||
store = snapStore; // pick snapshot image store to create template
|
||||
}
|
||||
}
|
||||
|
||||
future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store);
|
||||
} else if (volumeId != null) {
|
||||
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
|
||||
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true)
|
||||
public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user