Adding support for SolidFire snapshots

This commit is contained in:
Mike Tutkowski 2014-08-25 16:15:04 -06:00
parent 659eafffe1
commit 1d2f3300ad
10 changed files with 405 additions and 60 deletions

View File

@ -32,7 +32,14 @@ public interface PrimaryDataStoreDriver extends DataStoreDriver {
public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore);
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool); // intended for managed storage (cloud.storage_pool.managed = true)
// if not managed, return volume.getSize()
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool storagePool);
// intended for managed storage (cloud.storage_pool.managed = true)
// if managed storage, return the total number of bytes currently in use for the storage pool in question
// if not managed storage, return 0
public long getUsedBytes(StoragePool storagePool);
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback); public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);

View File

@ -54,6 +54,11 @@ public class FakePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
@Override @Override
public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {}
@Override
public long getUsedBytes(StoragePool storagePool) {
return 0;
}
@Override @Override
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
return volume.getSize(); return volume.getSize();

View File

@ -316,10 +316,10 @@ public class SnapshotServiceImpl implements SnapshotService {
} }
try { try {
CopyCmdAnswer answer = (CopyCmdAnswer)result.getAnswer(); CopyCmdAnswer copyCmdAnswer = (CopyCmdAnswer)result.getAnswer();
destSnapshot.processEvent(Event.OperationSuccessed, result.getAnswer()); destSnapshot.processEvent(Event.OperationSuccessed, copyCmdAnswer);
srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded); srcSnapshot.processEvent(Snapshot.Event.OperationSucceeded);
snapResult = new SnapshotResult(_snapshotFactory.getSnapshot(destSnapshot.getId(), destSnapshot.getDataStore()), answer); snapResult = new SnapshotResult(_snapshotFactory.getSnapshot(destSnapshot.getId(), destSnapshot.getDataStore()), copyCmdAnswer);
future.complete(snapResult); future.complete(snapResult);
} catch (Exception e) { } catch (Exception e) {
s_logger.debug("Failed to update snapshot state", e); s_logger.debug("Failed to update snapshot state", e);

View File

@ -157,6 +157,11 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {
} }
@Override
public long getUsedBytes(StoragePool storagePool) {
return 0;
}
@Override @Override
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
return volume.getSize(); return volume.getSize();

View File

@ -67,6 +67,11 @@ public class NexentaPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
//To change body of implemented methods use File | Settings | File Templates. //To change body of implemented methods use File | Settings | File Templates.
} }
@Override
public long getUsedBytes(StoragePool storagePool) {
return 0;
}
@Override @Override
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
return 0; //To change body of implemented methods use File | Settings | File Templates. return 0; //To change body of implemented methods use File | Settings | File Templates.

View File

@ -87,6 +87,11 @@ public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
@Override @Override
public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {} public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) {}
@Override
public long getUsedBytes(StoragePool storagePool) {
return 0;
}
@Override @Override
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
return volume.getSize(); return volume.getSize();

View File

@ -32,11 +32,15 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.CommandResult;
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import org.apache.cloudstack.storage.datastore.util.SolidFireUtil;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataObjectType;
@ -46,7 +50,6 @@ import com.cloud.capacity.CapacityManager;
import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVO;
import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterDetailsVO;
import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.ClusterDao;
import com.cloud.host.Host; import com.cloud.host.Host;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
@ -55,8 +58,14 @@ import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.ResizeVolumePayload; import com.cloud.storage.ResizeVolumePayload;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume; import com.cloud.storage.Volume;
import com.cloud.storage.VolumeDetailVO;
import com.cloud.storage.VolumeVO; import com.cloud.storage.VolumeVO;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.SnapshotDetailsDao;
import com.cloud.storage.dao.SnapshotDetailsVO;
import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.dao.VolumeDetailsDao;
import com.cloud.user.AccountDetailVO; import com.cloud.user.AccountDetailVO;
import com.cloud.user.AccountDetailsDao; import com.cloud.user.AccountDetailsDao;
import com.cloud.user.AccountVO; import com.cloud.user.AccountVO;
@ -64,16 +73,20 @@ import com.cloud.user.dao.AccountDao;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class);
@Inject private AccountDao _accountDao; @Inject private AccountDao _accountDao;
@Inject private AccountDetailsDao _accountDetailsDao; @Inject private AccountDetailsDao _accountDetailsDao;
@Inject private CapacityManager _capacityMgr; @Inject private CapacityManager _capacityMgr;
@Inject private ClusterDao _clusterDao; @Inject private ClusterDao _clusterDao;
@Inject private ClusterDetailsDao _clusterDetailsDao; @Inject private ClusterDetailsDao _clusterDetailsDao;
@Inject private DataCenterDao _zoneDao;
@Inject private HostDao _hostDao; @Inject private HostDao _hostDao;
@Inject private SnapshotDao _snapshotDao;
@Inject private SnapshotDetailsDao _snapshotDetailsDao;
@Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private PrimaryDataStoreDao _storagePoolDao;
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao; @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
@Inject private VolumeDao _volumeDao; @Inject private VolumeDao _volumeDao;
@Inject private VolumeDetailsDao _volumeDetailsDao;
@Override @Override
public Map<String, String> getCapabilities() { public Map<String, String> getCapabilities() {
@ -228,14 +241,54 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
} }
@Override
public long getUsedBytes(StoragePool storagePool) {
long usedSpace = 0;
List<VolumeVO> lstVolumes = _volumeDao.findByPoolId(storagePool.getId(), null);
if (lstVolumes != null) {
for (VolumeVO volume : lstVolumes) {
VolumeDetailVO volumeDetail = _volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE);
if (volumeDetail != null && volumeDetail.getValue() != null) {
long volumeSize = Long.parseLong(volumeDetail.getValue());
usedSpace += volumeSize;
}
}
}
List<SnapshotVO> lstSnapshots = _snapshotDao.listAll();
if (lstSnapshots != null) {
for (SnapshotVO snapshot : lstSnapshots) {
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.SNAPSHOT_STORAGE_POOL_ID);
// if this snapshot belong to the storagePool that was passed in
if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePool.getId()) {
snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.SNAPSHOT_SIZE);
if (snapshotDetails != null && snapshotDetails.getValue() != null) {
long snapshotSize = Long.parseLong(snapshotDetails.getValue());
usedSpace += snapshotSize;
}
}
}
}
return usedSpace;
}
@Override @Override
public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
long volumeSize = volume.getSize(); long volumeSize = volume.getSize();
Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve();
if (hypervisorSnapshotReserve != null) { if (hypervisorSnapshotReserve != null) {
if (hypervisorSnapshotReserve < 25) { if (hypervisorSnapshotReserve < 50) {
hypervisorSnapshotReserve = 25; hypervisorSnapshotReserve = 50;
} }
volumeSize += volumeSize * (hypervisorSnapshotReserve / 100f); volumeSize += volumeSize * (hypervisorSnapshotReserve / 100f);
@ -280,17 +333,17 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
} }
} }
private SolidFireUtil.SolidFireVolume deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo) private void deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo)
{ {
Long storagePoolId = volumeInfo.getPoolId(); Long storagePoolId = volumeInfo.getPoolId();
if (storagePoolId == null) { if (storagePoolId == null) {
return null; // this volume was never assigned to a storage pool, so no SAN volume should exist for it return; // this volume was never assigned to a storage pool, so no SAN volume should exist for it
} }
long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
return SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
} }
@Override @Override
@ -327,7 +380,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
iqn = sfVolume.getIqn(); iqn = sfVolume.getIqn();
VolumeVO volume = this._volumeDao.findById(volumeInfo.getId()); VolumeVO volume = _volumeDao.findById(volumeInfo.getId());
volume.set_iScsiName(iqn); volume.set_iScsiName(iqn);
volume.setFolder(String.valueOf(sfVolume.getId())); volume.setFolder(String.valueOf(sfVolume.getId()));
@ -336,12 +389,14 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
_volumeDao.update(volume.getId(), volume); _volumeDao.update(volume.getId(), volume);
updateVolumeDetails(volume.getId(), sfVolume.getTotalSize());
StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId()); StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId());
long capacityBytes = storagePool.getCapacityBytes(); long capacityBytes = storagePool.getCapacityBytes();
long usedBytes = storagePool.getUsedBytes(); // getUsedBytes(StoragePool) will include the bytes of the newly created volume because
// updateVolumeDetails(long, long) has already been called for this volume
usedBytes += sfVolume.getTotalSize(); long usedBytes = getUsedBytes(storagePool);
storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes);
@ -359,29 +414,52 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
callback.complete(result); callback.complete(result);
} }
private void updateVolumeDetails(long volumeId, long sfVolumeSize) {
VolumeDetailVO volumeDetailVo = _volumeDetailsDao.findDetail(volumeId, SolidFireUtil.VOLUME_SIZE);
if (volumeDetailVo == null || volumeDetailVo.getValue() == null) {
volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false);
_volumeDetailsDao.persist(volumeDetailVo);
}
}
@Override @Override
public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) { public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
String errMsg = null; String errMsg = null;
if (dataObject.getType() == DataObjectType.VOLUME) { if (dataObject.getType() == DataObjectType.VOLUME) {
VolumeInfo volumeInfo = (VolumeInfo)dataObject; try {
VolumeInfo volumeInfo = (VolumeInfo)dataObject;
long volumeId = volumeInfo.getId();
long storagePoolId = dataStore.getId(); long storagePoolId = dataStore.getId();
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
SolidFireUtil.SolidFireVolume sfVolume = deleteSolidFireVolume(sfConnection, volumeInfo); SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
_volumeDao.deleteVolumesByInstance(volumeInfo.getId()); deleteSolidFireVolume(sfConnection, volumeInfo);
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); _volumeDetailsDao.removeDetails(volumeId);
long usedBytes = storagePool.getUsedBytes(); _volumeDao.deleteVolumesByInstance(volumeId);
usedBytes -= sfVolume != null ? sfVolume.getTotalSize() : 0; StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); // getUsedBytes(StoragePool) will not include the volume to delete because it has already been deleted by this point
long usedBytes = getUsedBytes(storagePool);
_storagePoolDao.update(storagePoolId, storagePool); storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes);
_storagePoolDao.update(storagePoolId, storagePool);
}
catch (Exception ex) {
s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume", ex);
errMsg = ex.getMessage();
}
} else if (dataObject.getType() == DataObjectType.SNAPSHOT) {
// should return null when no error message
errMsg = deleteSnapshot((SnapshotInfo)dataObject, dataStore.getId());
} else { } else {
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync"; errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync";
} }
@ -394,15 +472,145 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
} }
@Override @Override
public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) { public void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
if (srcData.getType() == DataObjectType.SNAPSHOT && destData.getType() == DataObjectType.SNAPSHOT) {
// in this situation, we don't want to copy the snapshot anywhere
CopyCmdAnswer copyCmdAnswer = new CopyCmdAnswer(destData.getTO());
CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
result.setResult(null);
callback.complete(result);
return;
}
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public boolean canCopy(DataObject srcData, DataObject destData) { public boolean canCopy(DataObject srcData, DataObject destData) {
if (srcData.getType() == DataObjectType.SNAPSHOT && destData.getType() == DataObjectType.SNAPSHOT) {
return true;
}
return false; return false;
} }
@Override
public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<CreateCmdResult> callback) {
CreateCmdResult result = null;
try {
VolumeInfo volumeInfo = snapshotInfo.getBaseVolume();
VolumeVO volume = _volumeDao.findById(volumeInfo.getId());
long sfVolumeId = Long.parseLong(volume.getFolder());
long storagePoolId = volume.getPoolId();
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
long capacityBytes = storagePool.getCapacityBytes();
// getUsedBytes(StoragePool) will not include the bytes of the proposed snapshot because
// updateSnapshotDetails(long, long, long, long) has not yet been called for this snapshot
long usedBytes = getUsedBytes(storagePool);
long sfVolumeSize = sfVolume.getTotalSize();
usedBytes += sfVolumeSize;
// For taking a snapshot, we need to check to make sure a sufficient amount of space remains in the primary storage.
// For the purpose of "charging" these bytes against storage_pool.capacityBytes, we take the full size of the SolidFire volume.
// Generally snapshots take up much less space than the size of the volume, but the easiest way to track this space usage
// is to take the full size of the volume (you can always increase the amount of bytes you give to the primary storage).
if (usedBytes > capacityBytes) {
throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage to take a snapshot");
}
storagePool.setUsedBytes(usedBytes);
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).
_storagePoolDao.update(storagePoolId, storagePool);
updateSnapshotDetails(snapshotInfo.getId(), sfSnapshotId, storagePoolId, sfVolumeSize);
SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
snapshotObjectTo.setPath(String.valueOf(sfSnapshotId));
CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer(snapshotObjectTo);
result = new CreateCmdResult(null, createObjectAnswer);
result.setResult(null);
}
catch (Exception ex) {
s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to take CloudStack snapshot: " + snapshotInfo.getId(), ex);
result = new CreateCmdResult(null, new CreateObjectAnswer(ex.toString()));
result.setResult(ex.toString());
}
callback.complete(result);
}
private void updateSnapshotDetails(long csSnapshotId, long sfSnapshotId, long storagePoolId, long sfSnapshotSize) {
SnapshotDetailsVO accountDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.SNAPSHOT_ID,
String.valueOf(sfSnapshotId),
false);
_snapshotDetailsDao.persist(accountDetail);
accountDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.SNAPSHOT_STORAGE_POOL_ID,
String.valueOf(storagePoolId),
false);
_snapshotDetailsDao.persist(accountDetail);
accountDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.SNAPSHOT_SIZE,
String.valueOf(sfSnapshotSize),
false);
_snapshotDetailsDao.persist(accountDetail);
}
// return null for no error message
private String deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) {
String errMsg = null;
try {
SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
SolidFireUtil.deleteSolidFireSnapshot(sfConnection, getSolidFireSnapshotId(snapshotInfo.getId()));
_snapshotDetailsDao.removeDetails(snapshotInfo.getId());
}
catch (Exception ex) {
s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire snapshot: " + snapshotInfo.getId(), ex);
errMsg = ex.getMessage();
}
return errMsg;
}
private long getSolidFireSnapshotId(long csSnapshotId) {
SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID);
return Long.parseLong(snapshotDetails.getValue());
}
@Override @Override
public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback) { public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@ -434,6 +642,12 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
volume.setMaxIops(payload.newMaxIops); volume.setMaxIops(payload.newMaxIops);
_volumeDao.update(volume.getId(), volume); _volumeDao.update(volume.getId(), volume);
// SolidFireUtil.VOLUME_SIZE was introduced in 4.5.
// To be backward compatible with releases prior to 4.5, call updateVolumeDetails here.
// That way if SolidFireUtil.VOLUME_SIZE wasn't put in the volume_details table when the
// volume was initially created, it can be placed in volume_details if the volume is resized.
updateVolumeDetails(volume.getId(), sfVolume.getTotalSize());
} else { } else {
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to resize"; errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to resize";
} }
@ -462,9 +676,4 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
} }
} }
} }
@Override
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback) {
throw new UnsupportedOperationException();
}
} }

View File

@ -69,6 +69,8 @@ public class SolidFireUtil {
public static final String PROVIDER_NAME = "SolidFire"; public static final String PROVIDER_NAME = "SolidFire";
public static final String SHARED_PROVIDER_NAME = "SolidFireShared"; public static final String SHARED_PROVIDER_NAME = "SolidFireShared";
public static final String LOG_PREFIX = "SolidFire: ";
public static final String MANAGEMENT_VIP = "mVip"; public static final String MANAGEMENT_VIP = "mVip";
public static final String STORAGE_VIP = "sVip"; public static final String STORAGE_VIP = "sVip";
@ -90,6 +92,13 @@ public class SolidFireUtil {
public static final String ACCOUNT_ID = "accountId"; public static final String ACCOUNT_ID = "accountId";
public static final String VOLUME_ID = "volumeId"; public static final String VOLUME_ID = "volumeId";
public static final String SNAPSHOT_ID = "snapshotId";
public static final String CLONE_ID = "cloneId";
public static final String VOLUME_SIZE = "sfVolumeSize";
public static final String SNAPSHOT_SIZE = "sfSnapshotSize";
public static final String SNAPSHOT_STORAGE_POOL_ID = "sfSnapshotStoragePoolId";
public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername"; public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret"; public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
@ -554,10 +563,8 @@ public class SolidFireUtil {
return deletedVolumes; return deletedVolumes;
} }
public static SolidFireVolume deleteSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) public static void deleteSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
{ {
SolidFireVolume sfVolume = getSolidFireVolume(sfConnection, lVolumeId);
final Gson gson = new GsonBuilder().create(); final Gson gson = new GsonBuilder().create();
VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId); VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId);
@ -565,8 +572,6 @@ public class SolidFireUtil {
String strVolumeToDeleteJson = gson.toJson(volumeToDelete); String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
executeJsonRpc(sfConnection, strVolumeToDeleteJson); executeJsonRpc(sfConnection, strVolumeToDeleteJson);
return sfVolume;
} }
public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
@ -657,6 +662,49 @@ public class SolidFireUtil {
} }
} }
public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName) {
final Gson gson = new GsonBuilder().create();
SnapshotToCreate snapshotToCreate = new SnapshotToCreate(lVolumeId, snapshotName);
String strSnapshotToCreateJson = gson.toJson(snapshotToCreate);
String strSnapshotCreateResultJson = executeJsonRpc(sfConnection, strSnapshotToCreateJson);
SnapshotCreateResult snapshotCreateResult = gson.fromJson(strSnapshotCreateResultJson, SnapshotCreateResult.class);
verifyResult(snapshotCreateResult.result, strSnapshotCreateResultJson, gson);
return snapshotCreateResult.result.snapshotID;
}
public static void deleteSolidFireSnapshot(SolidFireConnection sfConnection, long lSnapshotId)
{
final Gson gson = new GsonBuilder().create();
SnapshotToDelete snapshotToDelete = new SnapshotToDelete(lSnapshotId);
String strSnapshotToDeleteJson = gson.toJson(snapshotToDelete);
executeJsonRpc(sfConnection, strSnapshotToDeleteJson);
}
public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, String cloneName) {
final Gson gson = new GsonBuilder().create();
CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, cloneName);
String strCloneToCreateJson = gson.toJson(cloneToCreate);
String strCloneCreateResultJson = executeJsonRpc(sfConnection, strCloneToCreateJson);
CloneCreateResult cloneCreateResult = gson.fromJson(strCloneCreateResultJson, CloneCreateResult.class);
verifyResult(cloneCreateResult.result, strCloneCreateResultJson, gson);
return cloneCreateResult.result.cloneID;
}
public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName) public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName)
{ {
final Gson gson = new GsonBuilder().create(); final Gson gson = new GsonBuilder().create();
@ -1206,6 +1254,65 @@ public class SolidFireUtil {
} }
} }
@SuppressWarnings("unused")
private static final class SnapshotToCreate {
private final String method = "CreateSnapshot";
private final SnapshotToCreateParams params;
private SnapshotToCreate(final long lVolumeId, final String snapshotName) {
params = new SnapshotToCreateParams(lVolumeId, snapshotName);
}
private static final class SnapshotToCreateParams {
private long volumeID;
private String name;
private SnapshotToCreateParams(final long lVolumeId, final String snapshotName) {
volumeID = lVolumeId;
name = snapshotName;
}
}
}
@SuppressWarnings("unused")
private static final class SnapshotToDelete
{
private final String method = "DeleteSnapshot";
private final SnapshotToDeleteParams params;
private SnapshotToDelete(final long lSnapshotId) {
params = new SnapshotToDeleteParams(lSnapshotId);
}
private static final class SnapshotToDeleteParams {
private long snapshotID;
private SnapshotToDeleteParams(final long lSnapshotId) {
snapshotID = lSnapshotId;
}
}
}
@SuppressWarnings("unused")
private static final class CloneToCreate {
private final String method = "CloneVolume";
private final CloneToCreateParams params;
private CloneToCreate(final long lVolumeId, final String cloneName) {
params = new CloneToCreateParams(lVolumeId, cloneName);
}
private static final class CloneToCreateParams {
private long volumeID;
private String name;
private CloneToCreateParams(final long lVolumeId, final String cloneName) {
volumeID = lVolumeId;
name = cloneName;
}
}
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final class AccountToAdd private static final class AccountToAdd
{ {
@ -1424,6 +1531,22 @@ public class SolidFireUtil {
} }
} }
private static final class SnapshotCreateResult {
private Result result;
private static final class Result {
private long snapshotID;
}
}
private static final class CloneCreateResult {
private Result result;
private static final class Result {
private long cloneID;
}
}
private static final class AccountAddResult { private static final class AccountAddResult {
private Result result; private Result result;
@ -1528,7 +1651,7 @@ public class SolidFireUtil {
httpClient = getHttpClient(sfConnection.getManagementPort()); httpClient = getHttpClient(sfConnection.getManagementPort());
URI uri = new URI("https://" + sfConnection.getManagementVip() + ":" + sfConnection.getManagementPort() + "/json-rpc/5.0"); URI uri = new URI("https://" + sfConnection.getManagementVip() + ":" + sfConnection.getManagementPort() + "/json-rpc/6.0");
AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME); AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword()); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword());

View File

@ -516,30 +516,16 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
@Override @Override
public long getUsedBytes(StoragePoolVO pool) { public long getUsedBytes(StoragePoolVO pool) {
long usedBytes = 0; DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId(), null); if (storeDriver instanceof PrimaryDataStoreDriver) {
PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver;
if (volumes != null && volumes.size() > 0) { return primaryStoreDriver.getUsedBytes(pool);
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();
PrimaryDataStoreDriver primaryStoreDriver = null;
if (storeDriver instanceof PrimaryDataStoreDriver) {
primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver;
}
for (VolumeVO volume : volumes) {
if (primaryStoreDriver != null) {
usedBytes += primaryStoreDriver.getVolumeSizeIncludingHypervisorSnapshotReserve(volume, pool);
}
else {
usedBytes += volume.getSize();
}
}
} }
return usedBytes; throw new CloudRuntimeException("Storage driver in CapacityManagerImpl.getUsedBytes(StoragePoolVO) is not a PrimaryDataStoreDriver.");
} }
@Override @Override
@ -548,7 +534,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId(), null); List<VolumeVO> volumes = _volumeDao.findByPoolId(pool.getId(), null);
if (volumes != null && volumes.size() > 0) { if (volumes != null) {
for (VolumeVO volume : volumes) { for (VolumeVO volume : volumes) {
usedIops += volume.getMinIops() != null ? volume.getMinIops() : 0; usedIops += volume.getMinIops() != null ? volume.getMinIops() : 0;
} }

View File

@ -1578,7 +1578,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
} }
} }
if (volume.getState() != Volume.State.Ready) { if (volume.getState() != Volume.State.Ready) {
totalAskingSize = totalAskingSize + getVolumeSizeIncludingHvSsReserve(volume, pool); totalAskingSize = totalAskingSize + getVolumeSizeIncludingHypervisorSnapshotReserve(volume, pool);
} }
} }
@ -1623,7 +1623,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
return true; return true;
} }
private long getVolumeSizeIncludingHvSsReserve(Volume volume, StoragePool pool) { private long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) {
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName()); DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName());
DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); DataStoreDriver storeDriver = storeProvider.getDataStoreDriver();