Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ static Boolean getFullCloneConfiguration(Long storeId) {

boolean canHostAccessStoragePool(Host host, StoragePool pool);

boolean canHostAccessOrPrepareStoragePool(Host host, StoragePool pool);

boolean canHostPrepareStoragePoolAccess(Host host, StoragePool pool);

boolean canDisconnectHostFromStoragePool(Host host, StoragePool pool);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao;
Expand Down Expand Up @@ -372,8 +371,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Inject
private NetworkDao _networkDao;
@Inject
private StoragePoolHostDao _poolHostDao;
@Inject
private VMSnapshotDao _vmSnapshotDao;
@Inject
private AffinityGroupVMMapDao _affinityGroupVMMapDao;
Expand Down Expand Up @@ -3422,7 +3419,7 @@ protected Map<Volume, StoragePool> buildMapUsingUserInformation(VirtualMachinePr
StoragePoolVO currentPool = _storagePoolDao.findById(volume.getPoolId());

executeManagedStorageChecksWhenTargetStoragePoolProvided(currentPool, volume, targetPool);
if (targetHost != null && _poolHostDao.findByPoolHost(targetPool.getId(), targetHost.getId()) == null) {
if (targetHost != null && !storageMgr.canHostAccessOrPrepareStoragePool(targetHost, targetPool)) {
throw new CloudRuntimeException(
String.format("Cannot migrate the volume [%s] to the storage pool [%s] while migrating VM [%s] to target host [%s]. The host does not have access to the storage pool entered.",
volume.getUuid(), targetPool.getUuid(), profile.getUuid(), targetHost.getUuid()));
Expand Down Expand Up @@ -3503,7 +3500,7 @@ protected void executeManagedStorageChecksWhenTargetStoragePoolNotProvided(Host
if (!currentPool.isManaged()) {
return;
}
if (targetHost != null && _poolHostDao.findByPoolHost(currentPool.getId(), targetHost.getId()) == null) {
if (targetHost != null && !storageMgr.canHostAccessOrPrepareStoragePool(targetHost, currentPool)) {
throw new CloudRuntimeException(String.format("The target host does not have access to the volume's managed storage pool. [volumeId=%s, storageId=%s, targetHostId=%s].", volume.getUuid(),
currentPool.getUuid(), targetHost.getUuid()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,11 @@
import com.cloud.storage.Storage;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.VMTemplateZoneVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao;
Expand Down Expand Up @@ -226,8 +224,6 @@ public class VirtualMachineManagerImplTest {
private VolumeVO volumeVoMock;
private long volumeMockId = 1111L;

@Mock
private StoragePoolHostDao storagePoolHostDaoMock;

@Mock
private StoragePoolAllocator storagePoolAllocatorMock;
Expand Down Expand Up @@ -587,7 +583,7 @@ public void buildMapUsingUserInformationTestTargetHostDoesNotHaveAccessToPool()
userDefinedVolumeToStoragePoolMap.put(volumeMockId, storagePoolVoMockId);

Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolProvided(any(StoragePoolVO.class), any(VolumeVO.class), any(StoragePoolVO.class));
Mockito.doReturn(null).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
Mockito.doReturn(false).when(storageManager).canHostAccessOrPrepareStoragePool(hostMock, storagePoolVoMock);

virtualMachineManagerImpl.buildMapUsingUserInformation(virtualMachineProfileMock, hostMock, userDefinedVolumeToStoragePoolMap);

Expand All @@ -600,7 +596,7 @@ public void buildMapUsingUserInformationTestTargetHostHasAccessToPool() {

Mockito.doNothing().when(virtualMachineManagerImpl).executeManagedStorageChecksWhenTargetStoragePoolProvided(any(StoragePoolVO.class), any(VolumeVO.class),
any(StoragePoolVO.class));
Mockito.doReturn(Mockito.mock(StoragePoolHostVO.class)).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
Mockito.doReturn(true).when(storageManager).canHostAccessOrPrepareStoragePool(hostMock, storagePoolVoMock);

Map<Volume, StoragePool> volumeToPoolObjectMap = virtualMachineManagerImpl.buildMapUsingUserInformation(virtualMachineProfileMock, hostMock, userDefinedVolumeToStoragePoolMap);

Expand Down Expand Up @@ -635,24 +631,24 @@ public void executeManagedStorageChecksWhenTargetStoragePoolNotProvidedTestCurre
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);

verify(storagePoolVoMock).isManaged();
verify(storagePoolHostDaoMock, Mockito.times(0)).findByPoolHost(anyLong(), anyLong());
Mockito.verify(storageManager, Mockito.times(0)).canHostAccessOrPrepareStoragePool(any(Host.class), any(StoragePool.class));
}

@Test
public void executeManagedStorageChecksWhenTargetStoragePoolNotProvidedTestCurrentStoragePoolManagedIsConnectedToHost() {
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
Mockito.doReturn(Mockito.mock(StoragePoolHostVO.class)).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
Mockito.doReturn(true).when(storageManager).canHostAccessOrPrepareStoragePool(hostMock, storagePoolVoMock);

virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);

verify(storagePoolVoMock).isManaged();
verify(storagePoolHostDaoMock, Mockito.times(1)).findByPoolHost(storagePoolVoMockId, hostMockId);
Mockito.verify(storageManager, Mockito.times(1)).canHostAccessOrPrepareStoragePool(hostMock, storagePoolVoMock);
}

@Test(expected = CloudRuntimeException.class)
public void executeManagedStorageChecksWhenTargetStoragePoolNotProvidedTestCurrentStoragePoolManagedIsNotConnectedToHost() {
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
Mockito.doReturn(null).when(storagePoolHostDaoMock).findByPoolHost(storagePoolVoMockId, hostMockId);
Mockito.doReturn(false).when(storageManager).canHostAccessOrPrepareStoragePool(hostMock, storagePoolVoMock);

virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolNotProvided(hostMock, storagePoolVoMock, volumeVoMock);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2565,8 +2565,9 @@ protected void verifyLiveMigrationForKVM(Map<VolumeInfo, DataStore> volumeDataSt
throw new CloudRuntimeException("Destination storage pool with ID " + dataStore.getId() + " was not located.");
}

if (srcStoragePoolVO.isManaged() && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
throw new CloudRuntimeException("Migrating a volume online with KVM from managed storage is not currently supported.");
boolean isSrcAndDestPoolPowerFlexStorage = srcStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex) && destStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex);
if (srcStoragePoolVO.isManaged() && !isSrcAndDestPoolPowerFlexStorage && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
throw new CloudRuntimeException("Migrating a volume online with KVM from managed storage (other than PowerFlex) is not currently supported.");
}

if (storageTypeConsistency == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2060,6 +2060,10 @@ public CopyManagedVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFu
private AsyncCallFuture<VolumeApiResult> copyManagedVolume(VolumeInfo srcVolume, DataStore destStore) {
AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<>();
VolumeApiResult res = new VolumeApiResult(srcVolume);
Host hostWithPoolsAccess = null;
VolumeInfo destVolume = null;
boolean srcVolumeAccessGranted = false;
boolean destVolumeAccessGranted = false;
try {
if (!snapshotMgr.canOperateOnVolume(srcVolume)) {
logger.debug("There are snapshots creating for this volume, can not move this volume");
Expand All @@ -2079,7 +2083,7 @@ private AsyncCallFuture<VolumeApiResult> copyManagedVolume(VolumeInfo srcVolume,
poolIds.add(srcVolume.getPoolId());
poolIds.add(destStore.getId());

Host hostWithPoolsAccess = _storageMgr.findUpAndEnabledHostWithAccessToStoragePools(poolIds);
hostWithPoolsAccess = _storageMgr.findUpAndEnabledHostWithAccessToStoragePools(poolIds);
if (hostWithPoolsAccess == null) {
logger.debug("No host(s) available with pool access, can not move this volume");
res.setResult("No host(s) available with pool access, can not move this volume");
Expand All @@ -2088,7 +2092,7 @@ private AsyncCallFuture<VolumeApiResult> copyManagedVolume(VolumeInfo srcVolume,
}

VolumeVO destVol = duplicateVolumeOnAnotherStorage(srcVolume, (StoragePool)destStore);
VolumeInfo destVolume = volFactory.getVolume(destVol.getId(), destStore);
destVolume = volFactory.getVolume(destVol.getId(), destStore);

// Create a volume on managed storage.
AsyncCallFuture<VolumeApiResult> createVolumeFuture = createVolumeAsync(destVolume, destStore);
Expand Down Expand Up @@ -2117,6 +2121,7 @@ private AsyncCallFuture<VolumeApiResult> copyManagedVolume(VolumeInfo srcVolume,
srcPrimaryDataStoreDetails.put(StorageManager.STORAGE_POOL_DISK_WAIT.toString(), String.valueOf(StorageManager.STORAGE_POOL_DISK_WAIT.valueIn(srcPrimaryDataStore.getId())));
srcPrimaryDataStore.setDetails(srcPrimaryDataStoreDetails);
grantAccess(srcVolume, hostWithPoolsAccess, srcVolume.getDataStore());
srcVolumeAccessGranted = true;
}

PrimaryDataStore destPrimaryDataStore = (PrimaryDataStore) destStore;
Expand All @@ -2131,6 +2136,7 @@ private AsyncCallFuture<VolumeApiResult> copyManagedVolume(VolumeInfo srcVolume,
destPrimaryDataStore.setDetails(destPrimaryDataStoreDetails);

grantAccess(destVolume, hostWithPoolsAccess, destStore);
destVolumeAccessGranted = true;

destVolume.processEvent(Event.CreateRequested);
srcVolume.processEvent(Event.MigrationRequested);
Expand All @@ -2141,17 +2147,40 @@ private AsyncCallFuture<VolumeApiResult> copyManagedVolume(VolumeInfo srcVolume,

motionSrv.copyAsync(srcVolume, destVolume, hostWithPoolsAccess, caller);
} catch (Exception e) {
logger.error("Copy to managed volume failed due to: " + e);
if(logger.isDebugEnabled()) {
logger.error("Copy to managed volume failed due to: {}", String.valueOf(e));
if (logger.isDebugEnabled()) {
logger.debug("Copy to managed volume failed.", e);
}
revokeAccessOnFailedManagedVolumeCopy(srcVolume, destVolume, hostWithPoolsAccess, srcVolumeAccessGranted, destVolumeAccessGranted);
res.setResult(e.toString());
future.complete(res);
}

return future;
}

private void revokeAccessOnFailedManagedVolumeCopy(VolumeInfo srcVolume, VolumeInfo destVolume, Host host, boolean srcVolumeAccessGranted, boolean destVolumeAccessGranted) {
if (host == null) {
return;
}

if (srcVolumeAccessGranted) {
try {
revokeAccess(srcVolume, host, srcVolume.getDataStore());
} catch (Exception e) {
logger.warn("Failed to revoke access to volume {} on host {} after a failed managed volume copy", srcVolume, host, e);
}
}

if (destVolumeAccessGranted) {
try {
revokeAccess(destVolume, host, destVolume.getDataStore());
} catch (Exception e) {
logger.warn("Failed to revoke access to volume {} on host {} after a failed managed volume copy", destVolume, host, e);
}
}
}

protected Void copyManagedVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback, CopyManagedVolumeContext<VolumeApiResult> context) {
VolumeInfo srcVolume = context.srcVolume;
VolumeInfo destVolume = context.destVolume;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import javax.inject.Inject;

import com.cloud.hypervisor.Hypervisor;
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
Expand Down Expand Up @@ -147,6 +148,8 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver {
private VolumeService volumeService;
@Inject
private VolumeOrchestrationService volumeMgr;
@Inject
private StorageManager storageMgr;
private ScaleIOSDCManager sdcManager;

public ScaleIOPrimaryDataStoreDriver() {
Expand Down Expand Up @@ -200,6 +203,7 @@ private boolean setVolumeLimitsFromDetails(VolumeVO volume, Host host, DataStore
public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) {
try {
sdcManager = ComponentContext.inject(sdcManager);
boolean hostConnectedToPool = storagePoolHostDao.findByPoolHost(dataStore.getId(), host.getId()) != null;
final String sdcId = sdcManager.prepareSDC(host, dataStore);
if (StringUtils.isBlank(sdcId)) {
alertHostSdcDisconnection(host);
Expand All @@ -209,6 +213,10 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
dataObject.getUuid(), host.getPrivateIpAddress()));
}

if (!hostConnectedToPool) {
connectHostToStoragePool(host, dataStore);
}

if (DataObjectType.VOLUME.equals(dataObject.getType())) {
final VolumeVO volume = volumeDao.findById(dataObject.getId());
logger.debug("Granting access for PowerFlex volume: {} at path {}", volume, volume.getPath());
Expand All @@ -231,6 +239,15 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore
}
}

private void connectHostToStoragePool(Host host, DataStore dataStore) {
try {
logger.debug("Connecting host {} to PowerFlex storage pool {}", host, dataStore);
storageMgr.connectHostToSharedPool(host, dataStore.getId());
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Failed to connect host %s to PowerFlex storage pool %s due to %s", host, dataStore, e.getMessage()), e);
}
}

private boolean grantAccess(DataObject dataObject, EndPoint ep, DataStore dataStore) {
Host host = hostDao.findById(ep.getId());
return grantAccess(dataObject, host, dataStore);
Expand Down Expand Up @@ -1522,6 +1539,11 @@ public boolean canHostPrepareStoragePoolAccess(Host host, StoragePool pool) {
return false;
}

if (!Hypervisor.HypervisorType.KVM.equals(host.getHypervisorType())) {
logger.debug("Host {} cannot prepare access to PowerFlex storage pool {}, unsupported hypervisor type: {}", host, pool, host.getHypervisorType());
return false;
}

sdcManager = ComponentContext.inject(sdcManager);
return sdcManager.areSDCConnectionsWithinLimit(pool.getId());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.Storage;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VolumeDao;
Expand Down Expand Up @@ -597,4 +599,18 @@ public void testGetVolumeSizeRequiredOnPool() {
16L * (1024 * 1024 * 1024),
true));
}

@Test
public void testCanHostPrepareStoragePoolAccessWithNullArguments() {
Assert.assertFalse(scaleIOPrimaryDataStoreDriver.canHostPrepareStoragePoolAccess(null, Mockito.mock(StoragePool.class)));
Assert.assertFalse(scaleIOPrimaryDataStoreDriver.canHostPrepareStoragePoolAccess(Mockito.mock(Host.class), null));
}

@Test
public void testCanHostPrepareStoragePoolAccessWithUnsupportedHypervisorType() {
Host host = Mockito.mock(Host.class);
when(host.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.VMware);

Assert.assertFalse(scaleIOPrimaryDataStoreDriver.canHostPrepareStoragePoolAccess(host, Mockito.mock(StoragePool.class)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,12 @@
import com.cloud.storage.ScopeType;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.template.VirtualMachineTemplate;
Expand Down Expand Up @@ -227,8 +225,6 @@ public void setHostAllocators(List<HostAllocator> hostAllocators) {
protected GuestOSCategoryDao _guestOSCategoryDao = null;
@Inject
protected DiskOfferingDao _diskOfferingDao;
@Inject
protected StoragePoolHostDao _poolHostDao;

@Inject
protected VolumeDao _volsDao;
Expand Down Expand Up @@ -1667,31 +1663,7 @@ public boolean checkAffinity(Host potentialHost, List<Long> preferredHosts) {
}

protected boolean hostCanAccessSPool(Host host, StoragePool pool) {
if (!_storageMgr.checkIfHostAndStoragePoolHasCommonStorageAccessGroups(host, pool)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("StoragePool %s and host %s does not have matching storage access groups", pool, host));
}
return false;
}

boolean hostCanAccessSPool = false;

StoragePoolHostVO hostPoolLinkage = _poolHostDao.findByPoolHost(pool.getId(), host.getId());
if (hostPoolLinkage != null && _storageMgr.canHostAccessStoragePool(host, pool)) {
hostCanAccessSPool = true;
}

logger.debug("Host: {}{} access pool: {}", host, hostCanAccessSPool ? " can" : " cannot", pool);
if (!hostCanAccessSPool) {
if (_storageMgr.canHostPrepareStoragePoolAccess(host, pool)) {
logger.debug("Host: {} can prepare access to pool: {}", host, pool);
hostCanAccessSPool = true;
} else {
logger.debug("Host: {} cannot prepare access to pool: {}", host, pool);
}
}

return hostCanAccessSPool;
return _storageMgr.canHostAccessOrPrepareStoragePool(host, pool);
}

protected List<Host> findSuitableHosts(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) {
Expand Down
Loading
Loading