This is an automated email from the ASF dual-hosted git repository.

sureshanaparti pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.22 by this push:
     new c1af36f8fc9 [4.22] Prevent unmanaging or reinstalling a VM if it is 
part of a CKS cluster (#12800)
c1af36f8fc9 is described below

commit c1af36f8fc9bcba6480f7f0daf2542c991f75e18
Author: Nicolas Vazquez <[email protected]>
AuthorDate: Thu Mar 26 09:47:49 2026 -0300

    [4.22] Prevent unmanaging or reinstalling a VM if it is part of a CKS 
cluster (#12800)
---
 .../src/main/java/com/cloud/vm/UserVmManager.java  |  5 ++
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  |  9 ++++
 .../cloudstack/vm/UnmanagedVMsManagerImpl.java     |  7 +++
 .../java/com/cloud/vm/UserVmManagerImplTest.java   |  4 ++
 .../cloudstack/vm/UnmanagedVMsManagerImplTest.java | 53 ++++++++++++++++++++++
 5 files changed, 78 insertions(+)

diff --git a/server/src/main/java/com/cloud/vm/UserVmManager.java 
b/server/src/main/java/com/cloud/vm/UserVmManager.java
index c035165a3fa..0a744709644 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManager.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManager.java
@@ -199,4 +199,9 @@ public interface UserVmManager extends UserVmService {
 
     Boolean getDestroyRootVolumeOnVmDestruction(Long domainId);
 
+    /**
+     * @return true if the VM is part of a CKS cluster, false otherwise.
+     */
+    boolean isVMPartOfAnyCKSCluster(VMInstanceVO vm);
+
 }
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java 
b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 1404ab206fb..4cb721666bd 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -8785,6 +8785,10 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
             throw new InvalidParameterValueException(String.format("Operation 
not supported for instance: %s",
                     vm.getName()));
         }
+        if (isVMPartOfAnyCKSCluster(vm)) {
+            throw new UnsupportedServiceException("Cannot restore VM with id = 
" + vm.getUuid() +
+                    " as it belongs to a CKS cluster. Please remove the VM 
from the CKS cluster before restoring.");
+        }
         _accountMgr.checkAccess(caller, null, true, vm);
 
         VMTemplateVO template;
@@ -9986,6 +9990,11 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         return DestroyRootVolumeOnVmDestruction.valueIn(domainId);
     }
 
+    @Override
+    public boolean isVMPartOfAnyCKSCluster(VMInstanceVO vm) {
+        return kubernetesServiceHelpers.get(0).findByVmId(vm.getId()) != null;
+    }
+
     private void setVncPasswordForKvmIfAvailable(Map<String, String> 
customParameters, UserVmVO vm) {
         if (customParameters.containsKey(VmDetailConstants.KVM_VNC_PASSWORD)
                 && 
StringUtils.isNotEmpty(customParameters.get(VmDetailConstants.KVM_VNC_PASSWORD)))
 {
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 fa97236aca4..e043791c6bf 100644
--- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java
@@ -2304,6 +2304,8 @@ public class UnmanagedVMsManagerImpl implements 
UnmanagedVMsManager {
      * 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)) {
@@ -2315,6 +2317,11 @@ public class UnmanagedVMsManagerImpl implements 
UnmanagedVMsManager {
             throw new UnsupportedServiceException("Cannot unmanage VM with id 
= " + vmVO.getUuid() +
                     " as there is an ISO attached. Please detach ISO before 
unmanaging.");
         }
+
+        if (userVmManager.isVMPartOfAnyCKSCluster(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 hasVolumeSnapshotsPriorToUnmanageVM(VMInstanceVO vmVO) {
diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java 
b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
index 21bcec59a5d..783be00c449 100644
--- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
+++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
@@ -59,6 +59,7 @@ import java.util.Map;
 import java.util.TimeZone;
 import java.util.UUID;
 
+import com.cloud.kubernetes.cluster.KubernetesServiceHelper;
 import com.cloud.storage.dao.SnapshotPolicyDao;
 import com.cloud.utils.fsm.NoTransitionException;
 import org.apache.cloudstack.acl.ControlledEntity;
@@ -1476,6 +1477,9 @@ public class UserVmManagerImplTest {
         when(cmd.getVmId()).thenReturn(vmId);
         when(cmd.getTemplateId()).thenReturn(2L);
         when(userVmDao.findById(vmId)).thenReturn(userVmVoMock);
+        KubernetesServiceHelper helper = mock(KubernetesServiceHelper.class);
+        when(helper.findByVmId(anyLong())).thenReturn(null);
+        
userVmManagerImpl.setKubernetesServiceHelpers(Collections.singletonList(helper));
 
         userVmManagerImpl.restoreVM(cmd);
     }
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 541148b5ddf..98e6388f3d6 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 static org.mockito.Mockito.when;
 
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -39,6 +40,9 @@ import java.util.Map;
 import java.util.UUID;
 
 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.api.ApiConstants;
 import org.apache.cloudstack.api.ResponseGenerator;
@@ -241,6 +245,8 @@ public class UnmanagedVMsManagerImplTest {
     private StoragePoolHostDao storagePoolHostDao;
     @Mock
     private ImportVmTasksManager importVmTasksManager;
+    @Mock
+    private SnapshotDao snapshotDao;
 
     @Mock
     private VMInstanceVO virtualMachine;
@@ -568,6 +574,53 @@ public class UnmanagedVMsManagerImplTest {
         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(userVmManager.isVMPartOfAnyCKSCluster(virtualMachine)).thenReturn(true);
+        unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false);
+    }
+
     @Test
     public void testListRemoteInstancesTest() {
         ListVmsForImportCmd cmd = Mockito.mock(ListVmsForImportCmd.class);

Reply via email to