From 06806a6523d4c5b46a0345ad62171ed26e843bb8 Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Sun, 6 Nov 2016 11:22:11 -0700 Subject: [PATCH] CLOUDSTACK-9619: Updates for SAN-assisted snapshots --- .../StorageSystemDataMotionStrategy.java | 138 +++++------------- .../StorageSystemSnapshotStrategy.java | 22 ++- .../storage/volume/VolumeServiceImpl.java | 46 ++++-- .../Xenserver625StorageProcessor.java | 21 ++- .../storage/datastore/util/SolidFireUtil.java | 5 +- .../plugins/solidfire/TestManagedSystemVMs.py | 8 +- .../solidfire/TestVMMigrationWithStorage.py | 2 +- .../plugins/solidfire/TestVMSnapshots.py | 68 --------- .../plugins/solidfire/util/sf_util.py | 4 +- 9 files changed, 110 insertions(+), 204 deletions(-) diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index b63652453975..2b7229060438 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -19,7 +19,6 @@ package org.apache.cloudstack.storage.motion; import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; @@ -37,9 +36,9 @@ import com.cloud.server.ManagementService; import com.cloud.storage.DataStoreRole; import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.Volume; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; @@ -79,15 +78,11 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; -import org.apache.cloudstack.storage.command.DeleteCommand; -import org.apache.cloudstack.storage.command.DettachAnswer; -import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ResignatureAnswer; import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -225,6 +220,7 @@ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, As if (canHandleDest) { handleCreateVolumeFromSnapshotOnSecondaryStorage(snapshotInfo, volumeInfo, callback); + return; } @@ -415,8 +411,14 @@ private void handleCopyDataToSecondaryStorage(SnapshotInfo snapshotInfo, DataObj copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); - if (needCache) { + if (!copyCmdAnswer.getResult()) { + // We were not able to copy. Handle it. + errMsg = copyCmdAnswer.getDetails(); + throw new CloudRuntimeException(errMsg); + } + + if (needCache) { // If cached storage was needed (in case of object store as secondary // storage), at this point, the data has been copied from the primary // to the NFS cache by the hypervisor. We now invoke another copy @@ -430,34 +432,34 @@ private void handleCopyDataToSecondaryStorage(SnapshotInfo snapshotInfo, DataObj if (ep == null) { errMsg = "No remote endpoint to send command, check if host or ssvm is down?"; + LOGGER.error(errMsg); + copyCmdAnswer = new CopyCmdAnswer(errMsg); } else { - copyCmdAnswer = (CopyCmdAnswer) ep.sendMessage(cmd); + copyCmdAnswer = (CopyCmdAnswer)ep.sendMessage(cmd); } // clean up snapshot copied to staging - performCleanupCacheStorage(destOnStore); + cacheMgr.deleteCacheObject(destOnStore); } - } catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) { String msg = "Failed to create template from snapshot (Snapshot ID = " + snapshotInfo.getId() + ") : "; LOGGER.warn(msg, ex); throw new CloudRuntimeException(msg + ex.getMessage()); - } finally { - - // detach and remove access after the volume is created - SnapshotObjectTO snapshotObjectTO = (SnapshotObjectTO) snapshotInfo.getTO(); - DiskTO disk = new DiskTO(snapshotObjectTO, null, snapshotInfo.getPath(), Volume.Type.UNKNOWN); - detachManagedStoreVolume(snapshotInfo, hostVO, getProperty(snapshotInfo.getId(), DiskTO.IQN), srcDataStore.getId(), disk); + _volumeService.revokeAccess(snapshotInfo, hostVO, srcDataStore); if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { errMsg = copyCmdAnswer.getDetails(); + + if (needCache) { + cacheMgr.deleteCacheObject(destOnStore); + } } else { errMsg = "Unable to create template from snapshot"; @@ -497,11 +499,9 @@ private void handleCopyDataToSecondaryStorage(SnapshotInfo snapshotInfo, DataObj * @param callback for async */ private void handleCreateVolumeFromSnapshotOnSecondaryStorage(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback callback) { - // at this point, the snapshotInfo and volumeInfo should have the same disk offering ID (so either one should be OK to get a DiskOfferingVO instance) DiskOfferingVO diskOffering = _diskOfferingDao.findByIdIncludingRemoved(volumeInfo.getDiskOfferingId()); SnapshotVO snapshot = _snapshotDao.findById(snapshotInfo.getId()); - DataStore destDataStore = volumeInfo.getDataStore(); // update the volume's hv_ss_reserve (hypervisor snapshot reserve) from a disk offering (used for managed storage) _volumeService.updateHypervisorSnapshotReserveForVolume(diskOffering, volumeInfo.getId(), snapshot.getHypervisorType()); @@ -510,9 +510,9 @@ private void handleCreateVolumeFromSnapshotOnSecondaryStorage(SnapshotInfo snaps String errMsg = null; HostVO hostVO = null; - try { - //create a volume on the storage + try { + // create a volume on the storage AsyncCallFuture future = _volumeService.createVolumeAsync(volumeInfo, volumeInfo.getDataStore()); VolumeApiResult result = future.get(); @@ -529,7 +529,7 @@ private void handleCreateVolumeFromSnapshotOnSecondaryStorage(SnapshotInfo snaps hostVO = getHost(snapshotInfo.getDataCenterId(), false); - //copy the volume from secondary via the hypervisor + // copy the volume from secondary via the hypervisor copyCmdAnswer = performCopyOfVdi(volumeInfo, snapshotInfo, hostVO); if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { @@ -543,12 +543,6 @@ private void handleCreateVolumeFromSnapshotOnSecondaryStorage(SnapshotInfo snaps } catch (Exception ex) { errMsg = ex.getMessage() != null ? ex.getMessage() : "Copy operation failed in 'StorageSystemDataMotionStrategy.handleCreateVolumeFromSnapshotBothOnStorageSystem'"; - } finally { - - - DiskTO disk = new DiskTO(volumeInfo.getTO(), volumeInfo.getDeviceId(), volumeInfo.getPath(),volumeInfo.getVolumeType()); - long storagePoolId = volumeInfo.getPoolId(); - detachManagedStoreVolume(volumeInfo, hostVO, volumeInfo.get_iScsiName(), storagePoolId, disk); } CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); @@ -556,73 +550,6 @@ private void handleCreateVolumeFromSnapshotOnSecondaryStorage(SnapshotInfo snaps result.setResult(errMsg); callback.complete(result); - - - } - - /** - * Detaches a managed volume from a host - * @param dataObject Volume to be detached - * @param hostVO Host where the volume is currently attached - * @param storagePoolId Storage where volume resides - * @param disk Object which stores disk attributes to send to the agents - */ - private void detachManagedStoreVolume(DataObject dataObject, HostVO hostVO, String iqn, long storagePoolId, DiskTO disk) { - - DataStore destDataStore = dataObject.getDataStore(); - DettachCommand cmd = new DettachCommand(disk, null); - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); - - cmd.setManaged(true); - cmd.setStorageHost(storagePool.getHostAddress()); - cmd.setStoragePort(storagePool.getPort()); - cmd.set_iScsiName(iqn); - - try { - DettachAnswer dettachAnswer = (DettachAnswer) _agentMgr.send(hostVO.getId(), cmd); - - if (!dettachAnswer.getResult()) { - LOGGER.warn("Error detaching DataObject:" + dettachAnswer.getDetails()); - } - - } catch (Exception e) { - LOGGER.warn("Error detaching DataObject " + dataObject.getId() + " Error: " + e.getMessage()); - } - - - try { - _volumeService.revokeAccess(dataObject, hostVO, destDataStore); - } catch (Exception e) { - LOGGER.warn("Error revoking access to DataObject (DataObject ID = " + dataObject.getId() + "): " + e.getMessage(), e); - } - } - - private void performCleanupCacheStorage(DataObject destOnStore) { - destOnStore.processEvent(Event.DestroyRequested); - - DeleteCommand deleteCommand = new DeleteCommand(destOnStore.getTO()); - EndPoint ep = selector.select(destOnStore); - try { - if (ep == null) { - LOGGER.warn("Unable to cleanup staging NFS because no endpoint was found " + - "Object: " + destOnStore.getType() + " ID: " + destOnStore.getId()); - - destOnStore.processEvent(Event.OperationFailed); - } else { - Answer deleteAnswer = ep.sendMessage(deleteCommand); - if (deleteAnswer != null && deleteAnswer.getResult()) { - LOGGER.warn("Unable to cleanup staging NFS " + deleteAnswer.getDetails() + - "Object: " + destOnStore.getType() + " ID: " + destOnStore.getId()); - destOnStore.processEvent(Event.OperationFailed); - } - } - - destOnStore.processEvent(Event.OperationSuccessed); - } catch (Exception e) { - destOnStore.processEvent(Event.OperationFailed); - LOGGER.warn("Unable to clean up staging cache Exception " + e.getMessage() + - "Object: " + destOnStore.getType() + " ID: " + destOnStore.getId()); - } } /** @@ -899,7 +826,7 @@ private Map getVolumeDetails(VolumeInfo volumeInfo) { } private Map getSnapshotDetails(SnapshotInfo snapshotInfo) { - Map snapshotDetails = new HashMap(); + Map snapshotDetails = new HashMap<>(); long storagePoolId = snapshotInfo.getDataStore().getId(); StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); @@ -1066,30 +993,34 @@ protected DataObject cacheSnapshotChain(SnapshotInfo snapshot, Scope scope) { * @return result of the copy */ private CopyCmdAnswer performCopyOfVdi(VolumeInfo volumeInfo, SnapshotInfo snapshotInfo, HostVO hostVO) { + Snapshot.LocationType locationType = snapshotInfo.getLocationType(); + String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); DataObject srcData = snapshotInfo; CopyCmdAnswer copyCmdAnswer = null; DataObject cacheData = null; + boolean needCacheStorage = needCacheStorage(snapshotInfo, volumeInfo); if (needCacheStorage) { cacheData = cacheSnapshotChain(snapshotInfo, new ZoneScope(volumeInfo.getDataCenterId())); srcData = cacheData; - } CopyCommand copyCommand = new CopyCommand(srcData.getTO(), volumeInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); try { + if (Snapshot.LocationType.PRIMARY.equals(locationType)) { + _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); - _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); - _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); + Map srcDetails = getSnapshotDetails(snapshotInfo); - Map srcDetails = getSnapshotDetails(snapshotInfo); + copyCommand.setOptions(srcDetails); + } - copyCommand.setOptions(srcDetails); + _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); Map destDetails = getVolumeDetails(volumeInfo); @@ -1105,11 +1036,14 @@ private CopyCmdAnswer performCopyOfVdi(VolumeInfo volumeInfo, SnapshotInfo snaps throw new CloudRuntimeException(msg + ex.getMessage()); } finally { - _volumeService.revokeAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); + if (Snapshot.LocationType.PRIMARY.equals(locationType)) { + _volumeService.revokeAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); + } + _volumeService.revokeAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); if (needCacheStorage && copyCmdAnswer != null && copyCmdAnswer.getResult()) { - performCleanupCacheStorage(cacheData); + cacheMgr.deleteCacheObject(cacheData); } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java index 591e3a68ae8c..2742da6dc611 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java @@ -90,18 +90,17 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase { @Override public SnapshotInfo backupSnapshot(SnapshotInfo snapshotInfo) { - Preconditions.checkArgument(snapshotInfo != null, "backupSnapshot expects a valid snapshot"); if (snapshotInfo.getLocationType() != Snapshot.LocationType.SECONDARY) { - markAsBackedUp((SnapshotObject)snapshotInfo); + return snapshotInfo; } - // At this point the snapshot is either taken as a native + // At this point, the snapshot is either taken as a native // snapshot on the storage or exists as a volume on the storage (clone). - // If archive flag is passed, we will copy this snapshot to secondary + // If archive flag is passed in, we should copy this snapshot to secondary // storage and delete it from the primary storage. HostVO host = getHost(snapshotInfo.getVolumeId()); @@ -109,15 +108,14 @@ public SnapshotInfo backupSnapshot(SnapshotInfo snapshotInfo) { boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(host.getClusterId()); if (!canStorageSystemCreateVolumeFromSnapshot || !computeClusterSupportsResign) { - String mesg = "Cannot archive snapshot: Either canStorageSystemCreateVolumeFromSnapshot or " + - "computeClusterSupportsResign were false. "; + String msg = "Cannot archive snapshot: canStorageSystemCreateVolumeFromSnapshot and/or computeClusterSupportsResign were false."; + + s_logger.warn(msg); - s_logger.warn(mesg); - throw new CloudRuntimeException(mesg); + throw new CloudRuntimeException(msg); } return snapshotSvr.backupSnapshot(snapshotInfo); - } @Override @@ -255,14 +253,13 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { backedUpSnapshot = backupSnapshot(snapshotOnPrimary); updateLocationTypeInDb(backedUpSnapshot); - } finally { if (result != null && result.isSuccess()) { volumeInfo.stateTransit(Volume.Event.OperationSucceeded); if (snapshotOnPrimary != null && snapshotInfo.getLocationType() == Snapshot.LocationType.SECONDARY) { - // cleanup the snapshot on primary + // remove the snapshot on primary storage try { snapshotSvr.deleteSnapshot(snapshotOnPrimary); } catch (Exception e) { @@ -276,6 +273,7 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { } snapshotDao.releaseFromLockTable(snapshotInfo.getId()); + return backedUpSnapshot; } @@ -586,7 +584,7 @@ public StrategyPriority canHandle(Snapshot snapshot, SnapshotOperation op) { Snapshot.LocationType locationType = snapshot.getLocationType(); - //If the snapshot exisits on Secondary Storage, we can't delete it. + // If the snapshot exists on Secondary Storage, we can't delete it. if (SnapshotOperation.DELETE.equals(op) && Snapshot.LocationType.SECONDARY.equals(locationType)) { return StrategyPriority.CANT_HANDLE; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 05ec7d02706b..eef61a2341bd 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -28,14 +28,6 @@ import javax.inject.Inject; -import com.cloud.dc.dao.ClusterDao; -import com.cloud.offering.DiskOffering; -import com.cloud.org.Cluster; -import com.cloud.org.Grouping.AllocationState; -import com.cloud.resource.ResourceState; -import com.cloud.server.ManagementService; -import com.cloud.storage.RegisterVolumePayload; -import com.cloud.utils.Pair; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; @@ -85,6 +77,7 @@ import com.cloud.alert.AlertManager; import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; +import com.cloud.dc.dao.ClusterDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; import com.cloud.exception.ConcurrentOperationException; @@ -94,7 +87,13 @@ import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.DiskOffering; +import com.cloud.org.Cluster; +import com.cloud.org.Grouping.AllocationState; +import com.cloud.resource.ResourceState; +import com.cloud.server.ManagementService; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.RegisterVolumePayload; import com.cloud.storage.ScopeType; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; @@ -111,6 +110,7 @@ import com.cloud.user.AccountManager; import com.cloud.user.ResourceLimitService; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; import com.cloud.utils.db.DB; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; @@ -317,9 +317,7 @@ public AsyncCallFuture expungeVolumeAsync(VolumeInfo volume) { VolumeVO vol = volDao.findById(volume.getId()); - String volumePath = vol.getPath(); - Long poolId = vol.getPoolId(); - if (poolId == null || volumePath == null || volumePath.trim().isEmpty()) { + if (!volumeExistsOnPrimary(vol)) { // not created on primary store if (volumeStore == null) { // also not created on secondary store @@ -348,6 +346,32 @@ public AsyncCallFuture expungeVolumeAsync(VolumeInfo volume) { return future; } + private boolean volumeExistsOnPrimary(VolumeVO vol) { + Long poolId = vol.getPoolId(); + + if (poolId == null) { + return false; + } + + PrimaryDataStore primaryStore = dataStoreMgr.getPrimaryDataStore(poolId); + + if (primaryStore == null) { + return false; + } + + if (primaryStore.isManaged()) { + return true; + } + + String volumePath = vol.getPath(); + + if (volumePath == null || volumePath.trim().isEmpty()) { + return false; + } + + return true; + } + public Void deleteVolumeCallback(AsyncCallbackDispatcher callback, DeleteVolumeContext context) { CommandResult result = callback.getResult(); VolumeObject vo = context.getVolume(); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java index 5c93cbb83338..1e7b14307c9d 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java @@ -532,6 +532,10 @@ public Answer backupSnapshot(final CopyCommand cmd) { if (snapshotSr != null) { hypervisorResource.removeSR(conn, snapshotSr); } + + if (primaryStore.isManaged()) { + hypervisorResource.removeSR(conn, primaryStorageSR); + } } } else { final String primaryStorageSRUuid = primaryStorageSR.getUuid(conn); @@ -553,9 +557,11 @@ public Answer backupSnapshot(final CopyCommand cmd) { physicalSize = Long.parseLong(tmp[1]); finalPath = folder + File.separator + snapshotBackupUuid + ".vhd"; } + + final String volumeUuid = snapshotTO.getVolume().getPath(); + + destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid); } - final String volumeUuid = snapshotTO.getVolume().getPath(); - destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid); final SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); newSnapshot.setPath(finalPath); @@ -708,9 +714,10 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) { } SR srcSr = null; VDI destVdi = null; - try { - SR primaryStorageSR; + SR primaryStorageSR = null; + + try { if (pool.isManaged()) { Map destDetails = cmd.getOptions2(); @@ -771,6 +778,7 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) { final VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(volumeUUID); newVol.setSize(vdir.virtualSize); + return new CopyCmdAnswer(newVol); } catch (final Types.XenAPIException e) { details += " due to " + e.toString(); @@ -782,6 +790,11 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) { if (srcSr != null) { hypervisorResource.removeSR(conn, srcSr); } + + if (pool.isManaged()) { + hypervisorResource.removeSR(conn, primaryStorageSR); + } + if (!result && destVdi != null) { try { destVdi.destroy(conn); diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 2caca72794f1..f5b67a78bacb 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -403,9 +403,10 @@ public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnecti SolidFireUtil.getIqnsFromHosts(hosts), new long[] { sfVolumeId }); } catch (Exception ex) { - String iqnInVagAlready = "Exceeded maximum number of Volume Access Groups per initiator"; + String iqnInVagAlready1 = "Exceeded maximum number of Volume Access Groups per initiator"; + String iqnInVagAlready2 = "Exceeded maximum number of VolumeAccessGroups per Initiator"; - if (!ex.getMessage().contains(iqnInVagAlready)) { + if (!ex.getMessage().contains(iqnInVagAlready1) && !ex.getMessage().contains(iqnInVagAlready2)) { throw new CloudRuntimeException(ex.getMessage()); } diff --git a/test/integration/plugins/solidfire/TestManagedSystemVMs.py b/test/integration/plugins/solidfire/TestManagedSystemVMs.py index a3343c745f14..2bfbe4aefb8b 100644 --- a/test/integration/plugins/solidfire/TestManagedSystemVMs.py +++ b/test/integration/plugins/solidfire/TestManagedSystemVMs.py @@ -488,7 +488,9 @@ def _verify_managed_system_vm_deleted(self, cs_root_volume_name): type="Routing" ) - sf_util.check_kvm_access_to_volume(sf_root_volume.iqn, list_hosts_response, self.testdata[TestData.kvm], self, False) + kvm_login = self.testdata[TestData.kvm] + + sf_util.check_kvm_access_to_volume(sf_root_volume.iqn, list_hosts_response, kvm_login[TestData.username], kvm_login[TestData.password], self, False) else: self.assertTrue(False, "Invalid hypervisor type") @@ -544,7 +546,9 @@ def _check_system_vms(self, system_vms, primary_storage_id): type="Routing" ) - sf_util.check_kvm_access_to_volume(sf_root_volume.iqn, list_hosts_response, self.testdata[TestData.kvm], self) + kvm_login = self.testdata[TestData.kvm] + + sf_util.check_kvm_access_to_volume(sf_root_volume.iqn, list_hosts_response, kvm_login[TestData.username], kvm_login[TestData.password], self) else: self.assertTrue(False, "Invalid hypervisor type") diff --git a/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py b/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py index adbb44be9507..d563e5eb2736 100644 --- a/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py +++ b/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py @@ -39,7 +39,7 @@ # Prerequisites: # Only one zone # Only one pod -# Two clusters +# Two clusters (have system VMs (including the VR) running on local or NFS storage) class TestData(): diff --git a/test/integration/plugins/solidfire/TestVMSnapshots.py b/test/integration/plugins/solidfire/TestVMSnapshots.py index db2539025dd8..880e6fd8e493 100644 --- a/test/integration/plugins/solidfire/TestVMSnapshots.py +++ b/test/integration/plugins/solidfire/TestVMSnapshots.py @@ -139,77 +139,9 @@ def __init__(self): TestData.tags: TestData.storageTag, "storagetype": "shared" }, - "testdiskofferings": { - "customiopsdo": { - "name": "SF_Custom_IOPS_DO", - "displaytext": "Customized IOPS DO (Size = 128 GB; Min IOPS = 500; Max IOPS = 1000)", - "disksize": 128, - "customizediops": True, - "miniops": 500, - "maxiops": 1000, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "customsizedo": { - "name": "SF_Custom_Size_DO", - "displaytext": "Customized IOPS DO (Min IOPS = 500; Max IOPS = 1000)", - "disksize": 175, - "customizediops": False, - "miniops": 500, - "maxiops": 1000, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "customsizeandiopsdo": { - "name": "SF_Custom_Size_IOPS_DO", - "displaytext": "Customized Size and IOPS DO", - "disksize": 200, - "customizediops": True, - "miniops": 400, - "maxiops": 800, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "newiopsdo": { - "name": "SF_New_IOPS_DO", - "displaytext": "New IOPS (Size = 128 GB; Min IOPS = 350, Max IOPS = 700)", - "disksize": 128, - "miniops": 350, - "maxiops": 700, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "newsizedo": { - "name": "SF_New_Size_DO", - "displaytext": "New Size: 175", - "disksize": 175, - "miniops": 400, - "maxiops": 800, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "newsizeandiopsdo": { - "name": "SF_New_Size_IOPS_DO", - "displaytext": "New Size and IOPS", - "disksize": 200, - "miniops": 200, - "maxiops": 400, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - } - }, TestData.volume_1: { "diskname": "testvolume", }, - "volume2": { - "diskname": "testvolume2", - }, TestData.zoneId: 1, TestData.clusterId: 1, TestData.domainId: 1, diff --git a/test/integration/plugins/solidfire/util/sf_util.py b/test/integration/plugins/solidfire/util/sf_util.py index f35839f241ea..de848d953c95 100644 --- a/test/integration/plugins/solidfire/util/sf_util.py +++ b/test/integration/plugins/solidfire/util/sf_util.py @@ -155,11 +155,11 @@ def check_xen_sr(xen_sr_name, xen_session, obj_assert, should_exist=True): else: check_list(xen_sr, 0, obj_assert, "SR " + xen_sr_name + " exists, but shouldn't.") -def check_kvm_access_to_volume(iscsi_name, kvm_hosts, kvm_login, obj_assert, should_exist=True): +def check_kvm_access_to_volume(iscsi_name, kvm_hosts, username, password, obj_assert, should_exist=True): count = 0 for kvm_host in kvm_hosts: - ssh_connection = sf_util.get_ssh_connection(kvm_host.ipaddress, kvm_login[TestData.username], kvm_login[TestData.password]) + ssh_connection = get_ssh_connection(kvm_host.ipaddress, username, password) stdin, stdout, stderr = ssh_connection.exec_command("ls /dev/disk/by-path | grep " + iscsi_name)