diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java index 13fa2608016c..ecd8683f83d5 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -71,6 +71,7 @@ import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.HypervisorGuru; import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.kubernetes.cluster.KubernetesServiceHelper; import com.cloud.network.Network; import com.cloud.network.NetworkModel; import com.cloud.network.Networks; @@ -314,6 +315,12 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { @Inject private ImportVmTasksManager importVmTasksManager; + private List kubernetesServiceHelpers; + + public void setKubernetesServiceHelpers(final List kubernetesServiceHelpers) { + this.kubernetesServiceHelpers = kubernetesServiceHelpers; + } + protected Gson gson; public UnmanagedVMsManagerImpl() { @@ -2365,6 +2372,8 @@ public List> getCommands() { * Perform validations before attempting to unmanage a VM from CloudStack: * - VM must not have any associated volume snapshot * - VM must not have an attached ISO + * - VM must not belong to any CKS cluster + * @throws UnsupportedServiceException in case any of the validations above fail */ void performUnmanageVMInstancePrechecks(VMInstanceVO vmVO) { if (hasVolumeSnapshotsPriorToUnmanageVM(vmVO)) { @@ -2376,6 +2385,15 @@ void performUnmanageVMInstancePrechecks(VMInstanceVO vmVO) { throw new UnsupportedServiceException("Cannot unmanage VM with id = " + vmVO.getUuid() + " as there is an ISO attached. Please detach ISO before unmanaging."); } + + if (isVmPartOfCKSCluster(vmVO)) { + throw new UnsupportedServiceException("Cannot unmanage VM with id = " + vmVO.getUuid() + + " as it belongs to a CKS cluster. Please remove the VM from the CKS cluster before unmanaging."); + } + } + + private boolean isVmPartOfCKSCluster(VMInstanceVO vmVO) { + return kubernetesServiceHelpers.get(0).findByVmId(vmVO.getId()) != null; } private boolean hasVolumeSnapshotsPriorToUnmanageVM(VMInstanceVO vmVO) { diff --git a/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml b/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml index 3afae7676b7b..0aa1bb5fdf8d 100644 --- a/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml +++ b/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml @@ -35,7 +35,9 @@ - + + + diff --git a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java index a24ba7f068b2..13aa7d4852c6 100644 --- a/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImplTest.java @@ -31,6 +31,7 @@ import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; @@ -38,8 +39,13 @@ import java.util.Map; import java.util.UUID; +import com.cloud.kubernetes.cluster.KubernetesServiceHelper; import com.cloud.offering.DiskOffering; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.dao.SnapshotDao; import com.cloud.vm.ImportVMTaskVO; +import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ResponseGenerator; import org.apache.cloudstack.api.ResponseObject; @@ -241,6 +247,10 @@ public class UnmanagedVMsManagerImplTest { private StoragePoolHostDao storagePoolHostDao; @Mock private ImportVmTasksManager importVmTasksManager; + @Mock + private KubernetesServiceHelper kubernetesServiceHelper; + @Mock + private SnapshotDao snapshotDao; @Mock private VMInstanceVO virtualMachine; @@ -279,6 +289,8 @@ public void setUp() throws Exception { UserVO user = new UserVO(1, "adminuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); CallContext.register(user, account); + unmanagedVMsManager.setKubernetesServiceHelpers(List.of(kubernetesServiceHelper)); + instance = new UnmanagedInstanceTO(); instance.setName("TestInstance"); instance.setCpuCores(2); @@ -568,6 +580,53 @@ public void unmanageVMInstanceStoppedInstanceTest() { unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false); } + @Test(expected = UnsupportedServiceException.class) + public void testUnmanageVMInstanceWithVolumeSnapshotsFail() { + when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User); + when(virtualMachine.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped); + when(virtualMachine.getId()).thenReturn(virtualMachineId); + UserVmVO userVmVO = mock(UserVmVO.class); + when(userVmDao.findById(anyLong())).thenReturn(userVmVO); + when(vmDao.findById(virtualMachineId)).thenReturn(virtualMachine); + VolumeVO volumeVO = mock(VolumeVO.class); + long volumeId = 20L; + when(volumeVO.getId()).thenReturn(volumeId); + SnapshotVO snapshotVO = mock(SnapshotVO.class); + when(snapshotVO.getState()).thenReturn(Snapshot.State.BackedUp); + when(snapshotDao.listByVolumeId(volumeId)).thenReturn(Collections.singletonList(snapshotVO)); + when(volumeDao.findByInstance(virtualMachineId)).thenReturn(Collections.singletonList(volumeVO)); + unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false); + } + + @Test(expected = UnsupportedServiceException.class) + public void testUnmanageVMInstanceWithAssociatedIsoFail() { + when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User); + when(virtualMachine.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped); + when(virtualMachine.getId()).thenReturn(virtualMachineId); + UserVmVO userVmVO = mock(UserVmVO.class); + when(userVmVO.getIsoId()).thenReturn(null); + when(userVmDao.findById(anyLong())).thenReturn(userVmVO); + when(vmDao.findById(virtualMachineId)).thenReturn(virtualMachine); + when(userVmVO.getIsoId()).thenReturn(1L); + unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false); + } + + @Test(expected = UnsupportedServiceException.class) + public void testUnmanageVMInstanceBelongingToCksClusterFail() { + when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User); + when(virtualMachine.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM); + when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped); + when(virtualMachine.getId()).thenReturn(virtualMachineId); + UserVmVO userVmVO = mock(UserVmVO.class); + when(userVmVO.getIsoId()).thenReturn(null); + when(userVmDao.findById(anyLong())).thenReturn(userVmVO); + when(vmDao.findById(virtualMachineId)).thenReturn(virtualMachine); + when(kubernetesServiceHelper.findByVmId(virtualMachineId)).thenReturn(mock(ControlledEntity.class)); + unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false); + } + @Test public void testListRemoteInstancesTest() { ListVmsForImportCmd cmd = Mockito.mock(ListVmsForImportCmd.class);