Snapshot support

This commit is contained in:
Mike Tutkowski 2014-10-17 14:42:17 -06:00
parent 45611a0f83
commit 06f6b00cd1
5 changed files with 156 additions and 13 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
} }
} }

View File

@ -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 {