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

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


The following commit(s) were added to refs/heads/4.19 by this push:
     new 91c7bc722f2 server,cks: check if vm is cks node during vm destroy 
(#9057)
91c7bc722f2 is described below

commit 91c7bc722f21625a4879aea1dffcd293712cbbad
Author: Abhishek Kumar <abhishek.mr...@gmail.com>
AuthorDate: Thu Jun 6 14:24:02 2024 +0530

    server,cks: check if vm is cks node during vm destroy (#9057)
    
    Signed-off-by: Abhishek Kumar <abhishek.mr...@gmail.com>
---
 .../cluster/KubernetesClusterHelper.java           |  5 +-
 api/src/main/java/com/cloud/uservm/UserVm.java     |  2 +
 .../src/main/java/com/cloud/vm/UserVmVO.java       |  1 +
 .../cluster/KubernetesClusterHelperImpl.java       | 35 ++++++++++-
 .../cluster/dao/KubernetesClusterVmMapDao.java     |  2 +
 .../cluster/dao/KubernetesClusterVmMapDaoImpl.java | 10 +++
 .../cluster/KubernetesClusterHelperImplTest.java   | 71 ++++++++++++++++++++++
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  | 19 +++++-
 utils/pom.xml                                      |  4 ++
 .../cloud/utils/component/ComponentContext.java    | 19 ++++++
 10 files changed, 163 insertions(+), 5 deletions(-)

diff --git 
a/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java 
b/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java
index e445e50f82c..e67e5277cee 100644
--- 
a/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java
+++ 
b/api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java
@@ -16,10 +16,13 @@
 // under the License.
 package com.cloud.kubernetes.cluster;
 
-import com.cloud.utils.component.Adapter;
 import org.apache.cloudstack.acl.ControlledEntity;
 
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.component.Adapter;
+
 public interface KubernetesClusterHelper extends Adapter {
 
     ControlledEntity findByUuid(String uuid);
+    void checkVmCanBeDestroyed(UserVm userVm);
 }
diff --git a/api/src/main/java/com/cloud/uservm/UserVm.java 
b/api/src/main/java/com/cloud/uservm/UserVm.java
index e30f5e03054..9035d2903c9 100644
--- a/api/src/main/java/com/cloud/uservm/UserVm.java
+++ b/api/src/main/java/com/cloud/uservm/UserVm.java
@@ -48,4 +48,6 @@ public interface UserVm extends VirtualMachine, 
ControlledEntity {
     void setAccountId(long accountId);
 
     public boolean isDisplayVm();
+
+    String getUserVmType();
 }
diff --git a/engine/schema/src/main/java/com/cloud/vm/UserVmVO.java 
b/engine/schema/src/main/java/com/cloud/vm/UserVmVO.java
index ce0bd2d5717..ce3a9a84a34 100644
--- a/engine/schema/src/main/java/com/cloud/vm/UserVmVO.java
+++ b/engine/schema/src/main/java/com/cloud/vm/UserVmVO.java
@@ -148,6 +148,7 @@ public class UserVmVO extends VMInstanceVO implements 
UserVm {
         return updateParameters;
     }
 
+    @Override
     public String getUserVmType() {
         return userVmType;
     }
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java
index 0ef916ab959..74f97426d85 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java
@@ -16,26 +16,55 @@
 // under the License.
 package com.cloud.kubernetes.cluster;
 
-import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
-import com.cloud.utils.component.AdapterBase;
+import javax.inject.Inject;
+
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
-import javax.inject.Inject;
+import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
+import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.UserVmManager;
 
 @Component
 public class KubernetesClusterHelperImpl extends AdapterBase implements 
KubernetesClusterHelper, Configurable {
+    private static final Logger logger = 
Logger.getLogger(KubernetesClusterHelperImpl.class);
 
     @Inject
     private KubernetesClusterDao kubernetesClusterDao;
+    @Inject
+    private KubernetesClusterVmMapDao kubernetesClusterVmMapDao;
 
     @Override
     public ControlledEntity findByUuid(String uuid) {
         return kubernetesClusterDao.findByUuid(uuid);
     }
 
+    @Override
+    public void checkVmCanBeDestroyed(UserVm userVm) {
+        if (!UserVmManager.CKS_NODE.equals(userVm.getUserVmType())) {
+            return;
+        }
+        KubernetesClusterVmMapVO vmMapVO = 
kubernetesClusterVmMapDao.findByVmId(userVm.getId());
+        if (vmMapVO == null) {
+            return;
+        }
+        logger.error(String.format("VM ID: %s is a part of Kubernetes cluster 
ID: %d", userVm.getId(), vmMapVO.getClusterId()));
+        KubernetesCluster kubernetesCluster = 
kubernetesClusterDao.findById(vmMapVO.getClusterId());
+        String msg = "Instance is a part of a Kubernetes cluster";
+        if (kubernetesCluster != null) {
+            msg += String.format(": %s", kubernetesCluster.getName());
+        }
+        msg += ". Use Instance delete option from Kubernetes cluster details 
or scale API for " +
+                "Kubernetes clusters with 'nodeids' to destroy the instance.";
+        throw new CloudRuntimeException(msg);
+    }
+
     @Override
     public String getConfigComponentName() {
         return KubernetesClusterHelper.class.getSimpleName();
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java
index 688a611ac99..abb7c3b5d01 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java
@@ -28,4 +28,6 @@ public interface KubernetesClusterVmMapDao extends 
GenericDao<KubernetesClusterV
     int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
 
     public int removeByClusterId(long clusterId);
+
+    KubernetesClusterVmMapVO findByVmId(long vmId);
 }
diff --git 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java
 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java
index b9f2ec917b2..3625873d029 100644
--- 
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java
+++ 
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java
@@ -69,4 +69,14 @@ public class KubernetesClusterVmMapDaoImpl extends 
GenericDaoBase<KubernetesClus
         sc.setParameters("clusterId", clusterId);
         return remove(sc);
     }
+
+    @Override
+    public KubernetesClusterVmMapVO findByVmId(long vmId) {
+        SearchBuilder<KubernetesClusterVmMapVO> sb = createSearchBuilder();
+        sb.and("vmId", sb.entity().getVmId(), SearchCriteria.Op.EQ);
+        sb.done();
+        SearchCriteria<KubernetesClusterVmMapVO> sc = sb.create();
+        sc.setParameters("vmId", vmId);
+        return findOneBy(sc);
+    }
 }
diff --git 
a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImplTest.java
 
b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImplTest.java
new file mode 100644
index 00000000000..167ade67cfb
--- /dev/null
+++ 
b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImplTest.java
@@ -0,0 +1,71 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.kubernetes.cluster;
+
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
+import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.UserVmManager;
+
+@RunWith(MockitoJUnitRunner.class)
+public class KubernetesClusterHelperImplTest {
+    @Mock
+    KubernetesClusterVmMapDao kubernetesClusterVmMapDao;
+    @Mock
+    KubernetesClusterDao kubernetesClusterDao;
+
+    @InjectMocks
+    KubernetesClusterHelperImpl kubernetesClusterHelper = new 
KubernetesClusterHelperImpl();
+
+    @Test
+    public void testCheckVmCanBeDestroyedNotCKSNode() {
+        UserVm vm = Mockito.mock(UserVm.class);
+        Mockito.when(vm.getUserVmType()).thenReturn("");
+        kubernetesClusterHelper.checkVmCanBeDestroyed(vm);
+        Mockito.verify(kubernetesClusterVmMapDao, 
Mockito.never()).findByVmId(Mockito.anyLong());
+    }
+
+    @Test
+    public void testCheckVmCanBeDestroyedNotInCluster() {
+        UserVm vm = Mockito.mock(UserVm.class);
+        Mockito.when(vm.getId()).thenReturn(1L);
+        Mockito.when(vm.getUserVmType()).thenReturn(UserVmManager.CKS_NODE);
+        
Mockito.when(kubernetesClusterVmMapDao.findByVmId(1L)).thenReturn(null);
+        kubernetesClusterHelper.checkVmCanBeDestroyed(vm);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testCheckVmCanBeDestroyedInCluster() {
+        UserVm vm = Mockito.mock(UserVm.class);
+        Mockito.when(vm.getId()).thenReturn(1L);
+        Mockito.when(vm.getUserVmType()).thenReturn(UserVmManager.CKS_NODE);
+        KubernetesClusterVmMapVO map = 
Mockito.mock(KubernetesClusterVmMapVO.class);
+        Mockito.when(map.getClusterId()).thenReturn(1L);
+        Mockito.when(kubernetesClusterVmMapDao.findByVmId(1L)).thenReturn(map);
+        
Mockito.when(kubernetesClusterDao.findById(1L)).thenReturn(Mockito.mock(KubernetesClusterVO.class));
+        kubernetesClusterHelper.checkVmCanBeDestroyed(vm);
+    }
+}
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java 
b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 3c172051463..d9484761998 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -130,8 +130,8 @@ import 
org.apache.cloudstack.storage.template.VnfTemplateManager;
 import org.apache.cloudstack.userdata.UserDataManager;
 import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
 import org.apache.cloudstack.utils.security.ParserUtils;
-import org.apache.cloudstack.vm.schedule.VMScheduleManager;
 import org.apache.cloudstack.vm.UnmanagedVMsManager;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
@@ -141,6 +141,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.log4j.Logger;
 import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.w3c.dom.Document;
@@ -241,6 +242,7 @@ import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
 import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
+import com.cloud.kubernetes.cluster.KubernetesClusterHelper;
 import com.cloud.network.IpAddressManager;
 import com.cloud.network.Network;
 import com.cloud.network.Network.GuestType;
@@ -346,6 +348,7 @@ import com.cloud.utils.DateUtil;
 import com.cloud.utils.Journal;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
+import com.cloud.utils.component.ComponentContext;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.concurrency.NamedThreadFactory;
 import com.cloud.utils.crypt.DBEncryptionUtil;
@@ -595,6 +598,7 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
     @Inject
     VMScheduleManager vmScheduleManager;
 
+
     private ScheduledExecutorService _executor = null;
     private ScheduledExecutorService _vmIpFetchExecutor = null;
     private int _expungeInterval;
@@ -3280,6 +3284,16 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         return  null;
     }
 
+    protected void checkPluginsIfVmCanBeDestroyed(UserVm vm) {
+        try {
+            KubernetesClusterHelper kubernetesClusterHelper =
+                    
ComponentContext.getDelegateComponentOfType(KubernetesClusterHelper.class);
+            kubernetesClusterHelper.checkVmCanBeDestroyed(vm);
+        } catch (NoSuchBeanDefinitionException ignored) {
+            s_logger.debug("No KubernetesClusterHelper bean found");
+        }
+    }
+
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VM_DESTROY, eventDescription = 
"destroying Vm", async = true)
     public UserVm destroyVm(DestroyVMCmd cmd) throws 
ResourceUnavailableException, ConcurrentOperationException {
@@ -3306,6 +3320,9 @@ public class UserVmManagerImpl extends ManagerBase 
implements UserVmManager, Vir
         // check if vm belongs to AutoScale vm group in Disabled state
         autoScaleManager.checkIfVmActionAllowed(vmId);
 
+        // check if vm belongs to any plugin resources
+        checkPluginsIfVmCanBeDestroyed(vm);
+
         // check if there are active volume snapshots tasks
         s_logger.debug("Checking if there are any ongoing snapshots on the 
ROOT volumes associated with VM with ID " + vmId);
         if (checkStatusOfVolumeSnapshots(vmId, Volume.Type.ROOT)) {
diff --git a/utils/pom.xml b/utils/pom.xml
index d52903a1df9..bf0d2bc346b 100755
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -226,6 +226,10 @@
             <artifactId>tink</artifactId>
             <version>${cs.tink.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git 
a/utils/src/main/java/com/cloud/utils/component/ComponentContext.java 
b/utils/src/main/java/com/cloud/utils/component/ComponentContext.java
index 8486dbf4bd4..0a086809a9d 100644
--- a/utils/src/main/java/com/cloud/utils/component/ComponentContext.java
+++ b/utils/src/main/java/com/cloud/utils/component/ComponentContext.java
@@ -29,6 +29,7 @@ import javax.management.MalformedObjectNameException;
 import javax.management.NotCompliantMBeanException;
 import javax.naming.ConfigurationException;
 
+import org.apache.commons.collections4.MapUtils;
 import org.apache.log4j.Logger;
 import org.springframework.aop.framework.Advised;
 import org.springframework.beans.BeansException;
@@ -286,4 +287,22 @@ public class ComponentContext implements 
ApplicationContextAware {
     private static synchronized void initInitializeBeans(boolean 
initializeBeans) {
         s_initializeBeans = initializeBeans;
     }
+
+    public static <T> T getDelegateComponentOfType(Class<T> beanType) {
+        if (s_appContextDelegates == null) {
+            throw new NoSuchBeanDefinitionException(beanType.getName());
+        }
+        T bean = null;
+        for (ApplicationContext context : s_appContextDelegates.values()) {
+            Map<String, T> map = context.getBeansOfType(beanType);
+            if (MapUtils.isNotEmpty(map)) {
+                bean = (T)map.values().toArray()[0];
+                break;
+            }
+        }
+        if (bean == null) {
+            throw new NoSuchBeanDefinitionException(beanType.getName());
+        }
+        return bean;
+    }
 }

Reply via email to