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);