mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 11:52:28 +01:00
server,cks: check if vm is cks node during vm destroy (#9057)
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
631d6ad09b
commit
91c7bc722f
@ -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);
|
||||
}
|
||||
|
||||
@ -48,4 +48,6 @@ public interface UserVm extends VirtualMachine, ControlledEntity {
|
||||
void setAccountId(long accountId);
|
||||
|
||||
public boolean isDisplayVm();
|
||||
|
||||
String getUserVmType();
|
||||
}
|
||||
|
||||
@ -148,6 +148,7 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
||||
return updateParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserVmType() {
|
||||
return userVmType;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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)) {
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user