Repository: cloudstack Updated Branches: refs/heads/master ea2ee1521 -> 7629d6f12
CLOUDSTACK-6170 Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/7629d6f1 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/7629d6f1 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/7629d6f1 Branch: refs/heads/master Commit: 7629d6f1297d8a609368a378ad5c179e9606ee1d Parents: ea2ee15 Author: Mike Tutkowski <mike.tutkow...@solidfire.com> Authored: Thu Mar 20 12:15:27 2014 -0600 Committer: Mike Tutkowski <mike.tutkow...@solidfire.com> Committed: Thu Mar 20 23:54:53 2014 -0600 ---------------------------------------------------------------------- .../service/VolumeOrchestrationService.java | 3 + .../orchestration/VolumeOrchestrator.java | 11 ++++ server/src/com/cloud/vm/UserVmManagerImpl.java | 65 ++++++++++++++++++++ server/test/com/cloud/vm/UserVmManagerTest.java | 29 +++++++++ 4 files changed, 108 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7629d6f1/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java ---------------------------------------------------------------------- diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index 095d954..3b555e5 100644 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -21,6 +21,7 @@ package org.apache.cloudstack.engine.orchestration.service; import java.util.Map; import java.util.Set; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import com.cloud.agent.api.to.VirtualMachineTO; @@ -94,6 +95,8 @@ public interface VolumeOrchestrationService { void cleanupVolumes(long vmId) throws ConcurrentOperationException; + void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore); + void disconnectVolumesFromHost(long vmId, long hostId); void migrateVolumes(VirtualMachine vm, VirtualMachineTO vmTo, Host srcHost, Host destHost, Map<Volume, StoragePool> volumeToPool); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7629d6f1/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java ---------------------------------------------------------------------- diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index a74d79c..4ebde04 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -37,8 +37,10 @@ import org.apache.log4j.Logger; 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.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService; @@ -832,6 +834,15 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati } @Override + public void disconnectVolumeFromHost(VolumeInfo volumeInfo, Host host, DataStore dataStore) { + DataStoreDriver dataStoreDriver = dataStore != null ? dataStore.getDriver() : null; + + if (dataStoreDriver instanceof PrimaryDataStoreDriver) { + ((PrimaryDataStoreDriver)dataStoreDriver).disconnectVolumeFromHost(volumeInfo, host, dataStore); + } + } + + @Override public void disconnectVolumesFromHost(long vmId, long hostId) { HostVO host = _hostDao.findById(hostId); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7629d6f1/server/src/com/cloud/vm/UserVmManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index b4888a8..f92eaca 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -70,6 +70,8 @@ import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.service.api.OrchestrationService; +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.TemplateDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; @@ -81,11 +83,13 @@ import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; import com.cloud.agent.api.GetVmDiskStatsAnswer; import com.cloud.agent.api.GetVmDiskStatsCommand; import com.cloud.agent.api.GetVmStatsAnswer; @@ -94,6 +98,8 @@ import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.VmDiskStatsEntry; import com.cloud.agent.api.VmStatsEntry; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; @@ -199,6 +205,7 @@ import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.DataStoreRole; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; @@ -448,6 +455,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir DeploymentPlanningManager _planningMgr; @Inject VolumeApiService _volumeService; + @Inject + DataStoreManager _dataStoreMgr; protected ScheduledExecutorService _executor = null; protected int _expungeInterval; @@ -4651,6 +4660,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir /* Detach and destory the old root volume */ _volsDao.detachVolume(root.getId()); + + handleManagedStorage(vm, root); + volumeMgr.destroyVolume(root); // For VMware hypervisor since the old root volume is replaced by the new root volume, force expunge old root volume if it has been created in storage @@ -4698,6 +4710,59 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } + private void handleManagedStorage(UserVmVO vm, VolumeVO root) { + StoragePoolVO storagePool = _storagePoolDao.findById(root.getPoolId()); + + if (storagePool.isManaged()) { + Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId(); + + if (hostId != null) { + DataTO volTO = volFactory.getVolume(root.getId()).getTO(); + DiskTO disk = new DiskTO(volTO, root.getDeviceId(), root.getPath(), root.getVolumeType()); + + // it's OK in this case to send a detach command to the host for a root volume as this + // will simply lead to the SR that supports the root volume being removed + DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName()); + + cmd.setManaged(true); + + cmd.setStorageHost(storagePool.getHostAddress()); + cmd.setStoragePort(storagePool.getPort()); + + cmd.set_iScsiName(root.get_iScsiName()); + + Commands cmds = new Commands(Command.OnError.Stop); + + cmds.addCommand(cmd); + + try { + _agentMgr.send(hostId, cmds); + } + catch (Exception ex) { + throw new CloudRuntimeException(ex.getMessage()); + } + + if (!cmds.isSuccessful()) { + for (Answer answer : cmds.getAnswers()) { + if (!answer.getResult()) { + s_logger.warn("Failed to reset vm due to: " + answer.getDetails()); + + throw new CloudRuntimeException("Unable to reset " + vm + " due to " + answer.getDetails()); + } + } + } + + if (hostId != null) { + // root.getPoolId() should be null if the VM we are attaching the disk to has never been started before + DataStore dataStore = root.getPoolId() != null ? _dataStoreMgr.getDataStore(root.getPoolId(), DataStoreRole.Primary) : null; + Host host = this._hostDao.findById(hostId); + + volumeMgr.disconnectVolumeFromHost(volFactory.getVolume(root.getId()), host, dataStore); + } + } + } + } + @Override public void prepareStop(VirtualMachineProfile profile) { UserVmVO vm = _vmDao.findById(profile.getId()); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7629d6f1/server/test/com/cloud/vm/UserVmManagerTest.java ---------------------------------------------------------------------- diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index 43010a3..b67c164 100755 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -50,6 +50,8 @@ import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import com.cloud.capacity.CapacityManager; import com.cloud.configuration.ConfigurationManager; @@ -141,6 +143,8 @@ public class UserVmManagerTest { EntityManager _entityMgr; @Mock ResourceLimitService _resourceLimitMgr; + @Mock + PrimaryDataStoreDao _storagePoolDao; @Before public void setup() { @@ -162,6 +166,7 @@ public class UserVmManagerTest { _userVmMgr._resourceLimitMgr = _resourceLimitMgr; _userVmMgr._scaleRetry = 2; _userVmMgr._entityMgr = _entityMgr; + _userVmMgr._storagePoolDao = _storagePoolDao; doReturn(3L).when(_account).getId(); doReturn(8L).when(_vmMock).getAccountId(); @@ -214,6 +219,12 @@ public class UserVmManagerTest { Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid"); UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString()); + StoragePoolVO storagePool = new StoragePoolVO(); + + storagePool.setManaged(false); + + when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool); + CallContext.register(user, account); try { _userVmMgr.restoreVMInternal(_account, _vmMock, null); @@ -245,6 +256,12 @@ public class UserVmManagerTest { Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid"); UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString()); + StoragePoolVO storagePool = new StoragePoolVO(); + + storagePool.setManaged(false); + + when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool); + CallContext.register(user, account); try { _userVmMgr.restoreVMInternal(_account, _vmMock, null); @@ -282,6 +299,12 @@ public class UserVmManagerTest { Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid"); UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString()); + StoragePoolVO storagePool = new StoragePoolVO(); + + storagePool.setManaged(false); + + when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool); + CallContext.register(user, account); try { _userVmMgr.restoreVMInternal(_account, _vmMock, 14L); @@ -321,6 +344,12 @@ public class UserVmManagerTest { Account account = new AccountVO("testaccount", 1L, "networkdomain", (short)0, "uuid"); UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString()); + StoragePoolVO storagePool = new StoragePoolVO(); + + storagePool.setManaged(false); + + when(_storagePoolDao.findById(anyLong())).thenReturn(storagePool); + CallContext.register(user, account); try { _userVmMgr.restoreVMInternal(_account, _vmMock, 14L);