Skip to content

Commit 8849e0f

Browse files
authored
server: fix volume detach operation when no vm host (#7526)
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
1 parent 2b3e2e4 commit 8849e0f

File tree

2 files changed

+72
-50
lines changed

2 files changed

+72
-50
lines changed

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,10 @@
3434

3535
import javax.inject.Inject;
3636

37-
import com.cloud.projects.Project;
38-
import com.cloud.projects.ProjectManager;
39-
import org.apache.cloudstack.api.command.user.volume.AssignVolumeCmd;
37+
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
4038
import org.apache.cloudstack.api.ApiErrorCode;
4139
import org.apache.cloudstack.api.ServerApiException;
42-
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
40+
import org.apache.cloudstack.api.command.user.volume.AssignVolumeCmd;
4341
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
4442
import org.apache.cloudstack.api.command.user.volume.ChangeOfferingForVolumeCmd;
4543
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
@@ -104,8 +102,8 @@
104102
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
105103
import org.apache.commons.collections.CollectionUtils;
106104
import org.apache.commons.collections.MapUtils;
107-
import org.apache.commons.lang3.ObjectUtils;
108105
import org.apache.commons.lang3.BooleanUtils;
106+
import org.apache.commons.lang3.ObjectUtils;
109107
import org.apache.commons.lang3.StringUtils;
110108
import org.apache.log4j.Logger;
111109
import org.jetbrains.annotations.NotNull;
@@ -148,6 +146,8 @@
148146
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
149147
import com.cloud.offering.DiskOffering;
150148
import com.cloud.org.Grouping;
149+
import com.cloud.projects.Project;
150+
import com.cloud.projects.ProjectManager;
151151
import com.cloud.resource.ResourceState;
152152
import com.cloud.serializer.GsonHelper;
153153
import com.cloud.server.ManagementService;
@@ -2778,31 +2778,10 @@ private Volume orchestrateDetachVolumeFromVM(long vmId, long volumeId) {
27782778
String errorMsg = "Failed to detach volume " + volume.getName() + " from VM " + vm.getHostName();
27792779
boolean sendCommand = vm.getState() == State.Running;
27802780

2781-
Long hostId = vm.getHostId();
2782-
2783-
if (hostId == null) {
2784-
hostId = vm.getLastHostId();
2785-
HostVO host = _hostDao.findById(hostId);
2786-
2787-
if (host != null && host.getHypervisorType() == HypervisorType.VMware) {
2788-
sendCommand = true;
2789-
}
2790-
}
2791-
2792-
HostVO host = null;
27932781
StoragePoolVO volumePool = _storagePoolDao.findByIdIncludingRemoved(volume.getPoolId());
2794-
2795-
if (hostId != null) {
2796-
host = _hostDao.findById(hostId);
2797-
2798-
if (host != null && host.getHypervisorType() == HypervisorType.XenServer && volumePool != null && volumePool.isManaged()) {
2799-
sendCommand = true;
2800-
}
2801-
}
2802-
2803-
if (volumePool == null) {
2804-
sendCommand = false;
2805-
}
2782+
HostVO host = getHostForVmVolumeAttachDetach(vm, volumePool);
2783+
Long hostId = host != null ? host.getId() : null;
2784+
sendCommand = sendCommand || isSendCommandForVmVolumeAttachDetach(host, volumePool);
28062785

28072786
Answer answer = null;
28082787

@@ -4080,15 +4059,15 @@ private String getNameOfClusteredFileSystem(HostVO hostVO) {
40804059
return "clustered file systems";
40814060
}
40824061

4083-
private HostVO getHostForVmVolumeAttach(UserVmVO vm, StoragePoolVO volumeToAttachStoragePool) {
4062+
private HostVO getHostForVmVolumeAttachDetach(VirtualMachine vm, StoragePoolVO volumeStoragePool) {
40844063
HostVO host = null;
40854064
Pair<Long, Long> clusterAndHostId = virtualMachineManager.findClusterAndHostIdForVm(vm.getId());
40864065
Long hostId = clusterAndHostId.second();
40874066
Long clusterId = clusterAndHostId.first();
40884067
if (hostId == null && clusterId != null &&
40894068
State.Stopped.equals(vm.getState()) &&
4090-
volumeToAttachStoragePool != null &&
4091-
!ScopeType.HOST.equals(volumeToAttachStoragePool.getScope())) {
4069+
volumeStoragePool != null &&
4070+
!ScopeType.HOST.equals(volumeStoragePool.getScope())) {
40924071
List<HostVO> hosts = _hostDao.findHypervisorHostInCluster(clusterId);
40934072
if (!hosts.isEmpty()) {
40944073
host = hosts.get(0);
@@ -4100,6 +4079,18 @@ private HostVO getHostForVmVolumeAttach(UserVmVO vm, StoragePoolVO volumeToAttac
41004079
return host;
41014080
}
41024081

4082+
protected boolean isSendCommandForVmVolumeAttachDetach(HostVO host, StoragePoolVO volumeStoragePool) {
4083+
if (host == null || volumeStoragePool == null) {
4084+
return false;
4085+
}
4086+
boolean sendCommand = HypervisorType.VMware.equals(host.getHypervisorType());
4087+
if (HypervisorType.XenServer.equals(host.getHypervisorType()) &&
4088+
volumeStoragePool.isManaged()) {
4089+
sendCommand = true;
4090+
}
4091+
return sendCommand;
4092+
}
4093+
41034094
private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, Long deviceId) {
41044095
String errorMsg = "Failed to attach volume " + volumeToAttach.getName() + " to VM " + vm.getHostName();
41054096
boolean sendCommand = vm.getState() == State.Running;
@@ -4108,16 +4099,9 @@ private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volumeToAttach, L
41084099
if (s_logger.isTraceEnabled() && volumeToAttachStoragePool != null) {
41094100
s_logger.trace(String.format("storage is gotten from volume to attach: %s/%s",volumeToAttachStoragePool.getName(),volumeToAttachStoragePool.getUuid()));
41104101
}
4111-
HostVO host = getHostForVmVolumeAttach(vm, volumeToAttachStoragePool);
4112-
Long hostId = host == null ? null : host.getId();
4113-
if (host != null && host.getHypervisorType() == HypervisorType.VMware) {
4114-
sendCommand = true;
4115-
}
4116-
4117-
if (host != null && host.getHypervisorType() == HypervisorType.XenServer &&
4118-
volumeToAttachStoragePool != null && volumeToAttachStoragePool.isManaged()) {
4119-
sendCommand = true;
4120-
}
4102+
HostVO host = getHostForVmVolumeAttachDetach(vm, volumeToAttachStoragePool);
4103+
Long hostId = host != null ? host.getId() : null;
4104+
sendCommand = sendCommand || isSendCommandForVmVolumeAttachDetach(host, volumeToAttachStoragePool);
41214105

41224106
if (host != null) {
41234107
_hostDao.loadDetails(host);

server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@
1717
package com.cloud.storage;
1818

1919
import static org.junit.Assert.assertEquals;
20-
import com.cloud.exception.PermissionDeniedException;
21-
import com.cloud.projects.Project;
22-
import com.cloud.projects.ProjectManager;
23-
import com.cloud.storage.dao.SnapshotDao;
2420
import static org.mockito.Matchers.any;
2521
import static org.mockito.Matchers.anyLong;
2622
import static org.mockito.Matchers.anyObject;
@@ -40,10 +36,6 @@
4036
import java.util.UUID;
4137
import java.util.concurrent.ExecutionException;
4238

43-
import com.cloud.event.EventTypes;
44-
import com.cloud.event.UsageEventUtils;
45-
import com.cloud.service.ServiceOfferingVO;
46-
import com.cloud.service.dao.ServiceOfferingDao;
4739
import org.apache.cloudstack.acl.ControlledEntity;
4840
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
4941
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
@@ -90,16 +82,25 @@
9082
import com.cloud.configuration.Resource.ResourceType;
9183
import com.cloud.dc.DataCenterVO;
9284
import com.cloud.dc.dao.DataCenterDao;
85+
import com.cloud.event.EventTypes;
86+
import com.cloud.event.UsageEventUtils;
9387
import com.cloud.exception.InvalidParameterValueException;
88+
import com.cloud.exception.PermissionDeniedException;
9489
import com.cloud.exception.ResourceAllocationException;
90+
import com.cloud.host.HostVO;
9591
import com.cloud.host.dao.HostDao;
9692
import com.cloud.hypervisor.Hypervisor.HypervisorType;
9793
import com.cloud.org.Grouping;
94+
import com.cloud.projects.Project;
95+
import com.cloud.projects.ProjectManager;
9896
import com.cloud.serializer.GsonHelper;
9997
import com.cloud.server.TaggedResourceService;
98+
import com.cloud.service.ServiceOfferingVO;
99+
import com.cloud.service.dao.ServiceOfferingDao;
100100
import com.cloud.storage.Storage.ProvisioningType;
101101
import com.cloud.storage.Volume.Type;
102102
import com.cloud.storage.dao.DiskOfferingDao;
103+
import com.cloud.storage.dao.SnapshotDao;
103104
import com.cloud.storage.dao.StoragePoolTagsDao;
104105
import com.cloud.storage.dao.VMTemplateDao;
105106
import com.cloud.storage.dao.VolumeDao;
@@ -1525,4 +1526,41 @@ public void testGetMinimumHypervisorVersionInDatacenterVersions() {
15251526
String expected = "6.7";
15261527
testBaseListOrderedHostsHypervisorVersionInDc(hwVersions, hypervisorType, expected);
15271528
}
1529+
1530+
@Test
1531+
public void testIsSendCommandForVmVolumeAttachDetachNullValues() {
1532+
Assert.assertFalse(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(null, null));
1533+
Assert.assertFalse(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(null, Mockito.mock(StoragePoolVO.class)));
1534+
Assert.assertFalse(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(Mockito.mock(HostVO.class), null));
1535+
}
1536+
1537+
@Test
1538+
public void testIsSendCommandForVmVolumeAttachDetachVMwareHost() {
1539+
HostVO host = Mockito.mock(HostVO.class);
1540+
Mockito.when(host.getHypervisorType()).thenReturn(HypervisorType.VMware);
1541+
Assert.assertTrue(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(host, Mockito.mock(StoragePoolVO.class)));
1542+
}
1543+
1544+
@Test
1545+
public void testIsSendCommandForVmVolumeAttachDetachXenserverHostNonMananged() {
1546+
HostVO host = Mockito.mock(HostVO.class);
1547+
Mockito.when(host.getHypervisorType()).thenReturn(HypervisorType.XenServer);
1548+
Assert.assertFalse(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(host, Mockito.mock(StoragePoolVO.class)));
1549+
}
1550+
1551+
@Test
1552+
public void testIsSendCommandForVmVolumeAttachDetachXenserverHostMananged() {
1553+
HostVO host = Mockito.mock(HostVO.class);
1554+
Mockito.when(host.getHypervisorType()).thenReturn(HypervisorType.XenServer);
1555+
StoragePoolVO pool = Mockito.mock(StoragePoolVO.class);
1556+
Mockito.when(pool.isManaged()).thenReturn(true);
1557+
Assert.assertTrue(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(host, pool));
1558+
}
1559+
1560+
@Test
1561+
public void testIsSendCommandForVmVolumeAttachDetachKVMHost() {
1562+
HostVO host = Mockito.mock(HostVO.class);
1563+
Mockito.when(host.getHypervisorType()).thenReturn(HypervisorType.KVM);
1564+
Assert.assertFalse(volumeApiServiceImpl.isSendCommandForVmVolumeAttachDetach(host, Mockito.mock(StoragePoolVO.class)));
1565+
}
15281566
}

0 commit comments

Comments
 (0)