CLOUDSTACK-4477: in order to select hypervisor host which can access storage pool, need to check storage_pool_host_ref
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d9016635 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d9016635 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d9016635 Branch: refs/heads/4.2 Commit: d901663578f81dbb4bcc0ea8eeba2597dacfdc24 Parents: f501c7b Author: Edison Su <[email protected]> Authored: Fri Aug 23 16:55:42 2013 -0700 Committer: Edison Su <[email protected]> Committed: Fri Aug 23 16:56:01 2013 -0700 ---------------------------------------------------------------------- .../test/DirectAgentManagerSimpleImpl.java | 15 +- .../storage/test/EndpointSelectorTest.java | 327 +++++++++++++++++++ .../test/FakeDriverTestConfiguration.java | 9 + .../endpoint/DefaultEndPointSelector.java | 19 +- 4 files changed, 364 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d9016635/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java ---------------------------------------------------------------------- diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java index ac50e9b..763a49e 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java @@ -26,6 +26,10 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.host.Host; +import com.cloud.host.Status; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -65,6 +69,9 @@ public class DirectAgentManagerSimpleImpl extends ManagerBase implements AgentMa ClusterDao clusterDao; @Inject ClusterDetailsDao clusterDetailsDao; + @Inject + HostDao _hostDao; + protected StateMachine2<Status, Event, Host> _statusStateMachine = Status.getStateMachine(); @Override public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { @@ -249,8 +256,12 @@ public class DirectAgentManagerSimpleImpl extends ManagerBase implements AgentMa @Override public boolean agentStatusTransitTo(HostVO host, Event e, long msId) { - // TODO Auto-generated method stub - return false; + try { + return _statusStateMachine.transitTo(host, e, host.getId(), _hostDao); + } catch (NoTransitionException e1) { + e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + return true; } @Override http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d9016635/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/EndpointSelectorTest.java ---------------------------------------------------------------------- diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/EndpointSelectorTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/EndpointSelectorTest.java new file mode 100644 index 0000000..15233bf --- /dev/null +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/EndpointSelectorTest.java @@ -0,0 +1,327 @@ +/* + * 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.test; + +import com.cloud.agent.AgentManager; +import com.cloud.cluster.LockMasterListener; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.org.Cluster; +import com.cloud.org.Managed; +import com.cloud.resource.ResourceState; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ScopeType; +import com.cloud.storage.Storage; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.User; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.db.Merovingian2; +import junit.framework.Assert; +import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; +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.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +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.PrimaryDataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.Scope; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.inject.Inject; +import java.net.URI; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:/fakeDriverTestContext.xml" }) +public class EndpointSelectorTest { + @Inject + SnapshotService snapshotService; + @Inject + SnapshotDao snapshotDao; + @Inject + SnapshotDataFactory snapshotDataFactory; + @Inject + PrimaryDataStoreProvider primaryDataStoreProvider; + @Inject + SnapshotDataStoreDao snapshotDataStoreDao; + @Inject + VolumeDao volumeDao; + @Inject + VolumeService volumeService; + @Inject + VolumeDataFactory volumeDataFactory; + @Inject + DataCenterDao dcDao; + Long dcId; + @Inject + HostPodDao podDao; + Long podId; + @Inject + ClusterDao clusterDao; + Long clusterId; + @Inject + ImageStoreDao imageStoreDao; + ImageStoreVO imageStore; + @Inject + AccountManager accountManager; + LockMasterListener lockMasterListener; + VolumeInfo vol = null; + FakePrimaryDataStoreDriver driver = new FakePrimaryDataStoreDriver(); + @Inject + MockStorageMotionStrategy mockStorageMotionStrategy; + Merovingian2 _lockMaster; + @Inject + DataStoreManager dataStoreManager; + @Inject + PrimaryDataStoreDao primaryDataStoreDao; + @Inject + SnapshotPolicyDao snapshotPolicyDao; + @Inject + HostDao hostDao; + @Inject + StoragePoolHostDao storagePoolHostDao; + @Inject + EndPointSelector endPointSelector; + @Inject + AgentManager agentMgr; + @Before + public void setUp() { + // create data center + + DataCenterVO dc = new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, + "10.0.0.1/24", null, null, DataCenter.NetworkType.Basic, null, null, true, true, null, null); + dc = dcDao.persist(dc); + dcId = dc.getId(); + // create pod + + HostPodVO pod = new HostPodVO(UUID.randomUUID().toString(), dc.getId(), "10.223.0.1", + "10.233.2.2/25", 8, "test"); + pod = podDao.persist(pod); + podId = pod.getId(); + // create xen cluster + ClusterVO cluster = new ClusterVO(dc.getId(), pod.getId(), "devcloud cluster"); + cluster.setHypervisorType(Hypervisor.HypervisorType.XenServer.toString()); + cluster.setClusterType(Cluster.ClusterType.CloudManaged); + cluster.setManagedState(Managed.ManagedState.Managed); + cluster = clusterDao.persist(cluster); + clusterId = cluster.getId(); + + imageStore = new ImageStoreVO(); + imageStore.setName(UUID.randomUUID().toString()); + imageStore.setDataCenterId(dcId); + imageStore.setProviderName(DataStoreProvider.NFS_IMAGE); + imageStore.setRole(DataStoreRole.Image); + imageStore.setUrl(UUID.randomUUID().toString()); + imageStore.setUuid(UUID.randomUUID().toString()); + imageStore.setProtocol("nfs"); + imageStore = imageStoreDao.persist(imageStore); + + when(primaryDataStoreProvider.configure(Mockito.anyMap())).thenReturn(true); + Set<DataStoreProvider.DataStoreProviderType> types = new HashSet<DataStoreProvider.DataStoreProviderType>(); + types.add(DataStoreProvider.DataStoreProviderType.PRIMARY); + + when(primaryDataStoreProvider.getTypes()).thenReturn(types); + when(primaryDataStoreProvider.getName()).thenReturn(DataStoreProvider.DEFAULT_PRIMARY); + when(primaryDataStoreProvider.getDataStoreDriver()).thenReturn(driver); + User user = mock(User.class); + when(user.getId()).thenReturn(1L); + Account account = mock(Account.class); + when(account.getId()).thenReturn(1L); + when(accountManager.getSystemAccount()).thenReturn(account); + when(accountManager.getSystemUser()).thenReturn(user); + + if(Merovingian2.getLockMaster() == null) { + _lockMaster = Merovingian2.createLockMaster(1234); + } else { + _lockMaster = Merovingian2.getLockMaster(); + } + _lockMaster.cleanupThisServer(); + ComponentContext.initComponentsLifeCycle(); + } + + public DataStore createPrimaryDataStore(ScopeType scope) { + String uuid = UUID.randomUUID().toString(); + List<StoragePoolVO> pools = primaryDataStoreDao.findPoolByName(uuid); + if (pools.size() > 0) { + return dataStoreManager.getPrimaryDataStore(pools.get(0).getId()); + } + + StoragePoolVO pool = new StoragePoolVO(); + if (scope != ScopeType.ZONE) { + pool.setClusterId(clusterId); + } + pool.setDataCenterId(dcId); + + pool.setHostAddress(uuid); + pool.setPath(uuid); + pool.setPort(0); + pool.setName(uuid); + pool.setUuid(uuid); + pool.setStatus(StoragePoolStatus.Up); + pool.setPoolType(Storage.StoragePoolType.NetworkFilesystem); + pool.setPodId(podId); + pool.setScope(scope); + pool.setStorageProviderName(DataStoreProvider.DEFAULT_PRIMARY); + pool = primaryDataStoreDao.persist(pool); + DataStore store = dataStoreManager.getPrimaryDataStore(pool.getId()); + return store; + } + + public HostVO createHost(Hypervisor.HypervisorType hypervisorType) { + String uuid = UUID.randomUUID().toString(); + HostVO host = new HostVO(uuid); + host.setName("devcloud xen host"); + host.setType(Host.Type.Routing); + host.setPrivateIpAddress(uuid); + host.setDataCenterId(dcId); + host.setVersion("6.0.1"); + host.setAvailable(true); + host.setSetup(true); + host.setPodId(podId); + host.setLastPinged(0); + host.setResourceState(ResourceState.Enabled); + host.setHypervisorType(hypervisorType); + host.setClusterId(clusterId); + + + host = hostDao.persist(host); + agentMgr.agentStatusTransitTo(host, Status.Event.AgentConnected, 1L); + host = hostDao.findById(host.getId()); + agentMgr.agentStatusTransitTo(host, Status.Event.Ready, 1L); + return hostDao.findById(host.getId()); + } + + public void addStorageToHost(DataStore store, HostVO host) { + StoragePoolHostVO storagePoolHostVO = new StoragePoolHostVO(store.getId(), host.getId(), UUID.randomUUID().toString()); + storagePoolHostDao.persist(storagePoolHostVO); + } + + @Test + public void testMixZonePrimaryStorages() { + Long srcStoreId = null; + Long destStoreId = imageStore.getId(); + DataStore store = createPrimaryDataStore(ScopeType.ZONE); + srcStoreId = store.getId(); + HostVO host = createHost(Hypervisor.HypervisorType.VMware); + addStorageToHost(store, host); + + store = createPrimaryDataStore(ScopeType.ZONE); + host = createHost(Hypervisor.HypervisorType.VMware); + addStorageToHost(store, host); + + Long xenStoreId = null; + store = createPrimaryDataStore(ScopeType.CLUSTER); + xenStoreId = store.getId(); + host = createHost(Hypervisor.HypervisorType.XenServer); + addStorageToHost(store, host); + + store = createPrimaryDataStore(ScopeType.CLUSTER); + host = createHost(Hypervisor.HypervisorType.XenServer); + addStorageToHost(store, host); + + ZoneScope srcScope = new ZoneScope(dcId); + + DataStore srcStore = mock(DataStore.class); + DataStore destStore = mock(DataStore.class); + + when(srcStore.getScope()).thenReturn(srcScope); + when(srcStore.getRole()).thenReturn(DataStoreRole.Primary); + when(srcStore.getId()).thenReturn(srcStoreId); + when(destStore.getScope()).thenReturn(srcScope); + when(destStore.getRole()).thenReturn(DataStoreRole.Image); + when(destStore.getId()).thenReturn(destStoreId); + + + + DataObject srcObj = mock(DataObject.class); + DataObject destObj = mock(DataObject.class); + when(srcObj.getDataStore()).thenReturn(srcStore); + when(destObj.getDataStore()).thenReturn(destStore); + EndPoint ep = endPointSelector.select(srcObj, destObj); + + Assert.assertTrue(ep != null); + Long hostId = ep.getId(); + HostVO newHost = hostDao.findById(hostId); + Assert.assertTrue(newHost.getHypervisorType() == Hypervisor.HypervisorType.VMware); + + when(srcStore.getRole()).thenReturn(DataStoreRole.Image); + when(srcStore.getId()).thenReturn(destStoreId); + when(destStore.getId()).thenReturn(srcStoreId); + when(destStore.getRole()).thenReturn(DataStoreRole.Primary); + ep = endPointSelector.select(srcObj, destObj); + + Assert.assertTrue(ep != null); + hostId = ep.getId(); + newHost = hostDao.findById(hostId); + Assert.assertTrue(newHost.getHypervisorType() == Hypervisor.HypervisorType.VMware); + + ClusterScope clusterScope = new ClusterScope(clusterId, podId, dcId); + when(srcStore.getRole()).thenReturn(DataStoreRole.Primary); + when(srcStore.getScope()).thenReturn(clusterScope); + when(srcStore.getId()).thenReturn(xenStoreId); + ep = endPointSelector.select(srcStore); + Assert.assertTrue(ep != null); + newHost = hostDao.findById(ep.getId()); + Assert.assertTrue(newHost.getHypervisorType() == Hypervisor.HypervisorType.XenServer); + + + + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d9016635/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakeDriverTestConfiguration.java ---------------------------------------------------------------------- diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakeDriverTestConfiguration.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakeDriverTestConfiguration.java index 3cf0cb6..75eda90 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakeDriverTestConfiguration.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakeDriverTestConfiguration.java @@ -21,10 +21,13 @@ package org.apache.cloudstack.storage.test; import com.cloud.storage.snapshot.SnapshotScheduler; import com.cloud.storage.snapshot.SnapshotSchedulerImpl; import com.cloud.user.DomainManager; +import com.cloud.utils.component.ComponentContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.storage.datastore.provider.CloudStackPrimaryDataStoreProviderImpl; import org.apache.cloudstack.storage.datastore.type.DataStoreType; +import org.apache.cloudstack.storage.endpoint.DefaultEndPointSelector; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; @@ -55,4 +58,10 @@ public class FakeDriverTestConfiguration extends ChildTestConfiguration{ return Mockito.mock(DomainManager.class); } + @Override + @Bean + public EndPointSelector selector() { + return ComponentContext.inject(DefaultEndPointSelector.class); + } + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d9016635/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java ---------------------------------------------------------------------- diff --git a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java index 0cd8ad3..a1d7315 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java +++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java @@ -55,7 +55,8 @@ public class DefaultEndPointSelector implements EndPointSelector { private static final Logger s_logger = Logger.getLogger(DefaultEndPointSelector.class); @Inject HostDao hostDao; - private String findOneHostOnPrimaryStorage = "select id from host where status = 'Up' and type = 'Routing' and resource_state = 'Enabled'"; + private String findOneHostOnPrimaryStorage = "select h.id from host h, storage_pool_host_ref s where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and" + + " h.id = s.host_id and s.pool_id = ? "; protected boolean moveBetweenPrimaryImage(DataStore srcStore, DataStore destStore) { DataStoreRole srcRole = srcStore.getRole(); @@ -90,7 +91,7 @@ public class DefaultEndPointSelector implements EndPointSelector { } @DB - protected EndPoint findEndPointInScope(Scope scope, String sqlBase) { + protected EndPoint findEndPointInScope(Scope scope, String sqlBase, Long poolId) { StringBuilder sbuilder = new StringBuilder(); sbuilder.append(sqlBase); @@ -114,6 +115,7 @@ public class DefaultEndPointSelector implements EndPointSelector { try { pstmt = txn.prepareStatement(sql); + pstmt.setLong(1, poolId); rs = pstmt.executeQuery(); while (rs.next()) { long id = rs.getLong(1); @@ -146,17 +148,26 @@ public class DefaultEndPointSelector implements EndPointSelector { Scope srcScope = srcStore.getScope(); Scope destScope = destStore.getScope(); Scope selectedScope = null; + Long poolId = null; + // assumption, at least one of scope should be zone, find the least // scope if (srcScope.getScopeType() != ScopeType.ZONE) { selectedScope = srcScope; + poolId = srcStore.getId(); } else if (destScope.getScopeType() != ScopeType.ZONE) { selectedScope = destScope; + poolId = destStore.getId(); } else { // if both are zone scope selectedScope = srcScope; + if (srcStore.getRole() == DataStoreRole.Primary) { + poolId = srcStore.getId(); + } else if (destStore.getRole() == DataStoreRole.Primary) { + poolId = destStore.getId(); + } } - return findEndPointInScope(selectedScope, findOneHostOnPrimaryStorage); + return findEndPointInScope(selectedScope, findOneHostOnPrimaryStorage, poolId); } @Override @@ -184,7 +195,7 @@ public class DefaultEndPointSelector implements EndPointSelector { } protected EndPoint findEndpointForPrimaryStorage(DataStore store) { - return findEndPointInScope(store.getScope(), findOneHostOnPrimaryStorage); + return findEndPointInScope(store.getScope(), findOneHostOnPrimaryStorage, store.getId()); } protected EndPoint findEndpointForImageStorage(DataStore store) {
