mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +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.
|
// under the License.
|
||||||
package com.cloud.kubernetes.cluster;
|
package com.cloud.kubernetes.cluster;
|
||||||
|
|
||||||
import com.cloud.utils.component.Adapter;
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
|
|
||||||
|
import com.cloud.uservm.UserVm;
|
||||||
|
import com.cloud.utils.component.Adapter;
|
||||||
|
|
||||||
public interface KubernetesClusterHelper extends Adapter {
|
public interface KubernetesClusterHelper extends Adapter {
|
||||||
|
|
||||||
ControlledEntity findByUuid(String uuid);
|
ControlledEntity findByUuid(String uuid);
|
||||||
|
void checkVmCanBeDestroyed(UserVm userVm);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,4 +48,6 @@ public interface UserVm extends VirtualMachine, ControlledEntity {
|
|||||||
void setAccountId(long accountId);
|
void setAccountId(long accountId);
|
||||||
|
|
||||||
public boolean isDisplayVm();
|
public boolean isDisplayVm();
|
||||||
|
|
||||||
|
String getUserVmType();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,6 +148,7 @@ public class UserVmVO extends VMInstanceVO implements UserVm {
|
|||||||
return updateParameters;
|
return updateParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getUserVmType() {
|
public String getUserVmType() {
|
||||||
return userVmType;
|
return userVmType;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,26 +16,55 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.kubernetes.cluster;
|
package com.cloud.kubernetes.cluster;
|
||||||
|
|
||||||
import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
|
import javax.inject.Inject;
|
||||||
import com.cloud.utils.component.AdapterBase;
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.stereotype.Component;
|
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
|
@Component
|
||||||
public class KubernetesClusterHelperImpl extends AdapterBase implements KubernetesClusterHelper, Configurable {
|
public class KubernetesClusterHelperImpl extends AdapterBase implements KubernetesClusterHelper, Configurable {
|
||||||
|
private static final Logger logger = Logger.getLogger(KubernetesClusterHelperImpl.class);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private KubernetesClusterDao kubernetesClusterDao;
|
private KubernetesClusterDao kubernetesClusterDao;
|
||||||
|
@Inject
|
||||||
|
private KubernetesClusterVmMapDao kubernetesClusterVmMapDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ControlledEntity findByUuid(String uuid) {
|
public ControlledEntity findByUuid(String uuid) {
|
||||||
return kubernetesClusterDao.findByUuid(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
|
@Override
|
||||||
public String getConfigComponentName() {
|
public String getConfigComponentName() {
|
||||||
return KubernetesClusterHelper.class.getSimpleName();
|
return KubernetesClusterHelper.class.getSimpleName();
|
||||||
|
|||||||
@ -28,4 +28,6 @@ public interface KubernetesClusterVmMapDao extends GenericDao<KubernetesClusterV
|
|||||||
int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
|
int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
|
||||||
|
|
||||||
public int removeByClusterId(long clusterId);
|
public int removeByClusterId(long clusterId);
|
||||||
|
|
||||||
|
KubernetesClusterVmMapVO findByVmId(long vmId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,4 +69,14 @@ public class KubernetesClusterVmMapDaoImpl extends GenericDaoBase<KubernetesClus
|
|||||||
sc.setParameters("clusterId", clusterId);
|
sc.setParameters("clusterId", clusterId);
|
||||||
return remove(sc);
|
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.userdata.UserDataManager;
|
||||||
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
||||||
import org.apache.cloudstack.utils.security.ParserUtils;
|
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.UnmanagedVMsManager;
|
||||||
|
import org.apache.cloudstack.vm.schedule.VMScheduleManager;
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
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.commons.lang3.builder.ToStringStyle;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.w3c.dom.Document;
|
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.Hypervisor.HypervisorType;
|
||||||
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
|
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
|
||||||
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
|
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
|
||||||
|
import com.cloud.kubernetes.cluster.KubernetesClusterHelper;
|
||||||
import com.cloud.network.IpAddressManager;
|
import com.cloud.network.IpAddressManager;
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
import com.cloud.network.Network.GuestType;
|
import com.cloud.network.Network.GuestType;
|
||||||
@ -346,6 +348,7 @@ import com.cloud.utils.DateUtil;
|
|||||||
import com.cloud.utils.Journal;
|
import com.cloud.utils.Journal;
|
||||||
import com.cloud.utils.NumbersUtil;
|
import com.cloud.utils.NumbersUtil;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.component.ComponentContext;
|
||||||
import com.cloud.utils.component.ManagerBase;
|
import com.cloud.utils.component.ManagerBase;
|
||||||
import com.cloud.utils.concurrency.NamedThreadFactory;
|
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||||
import com.cloud.utils.crypt.DBEncryptionUtil;
|
import com.cloud.utils.crypt.DBEncryptionUtil;
|
||||||
@ -595,6 +598,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
@Inject
|
@Inject
|
||||||
VMScheduleManager vmScheduleManager;
|
VMScheduleManager vmScheduleManager;
|
||||||
|
|
||||||
|
|
||||||
private ScheduledExecutorService _executor = null;
|
private ScheduledExecutorService _executor = null;
|
||||||
private ScheduledExecutorService _vmIpFetchExecutor = null;
|
private ScheduledExecutorService _vmIpFetchExecutor = null;
|
||||||
private int _expungeInterval;
|
private int _expungeInterval;
|
||||||
@ -3280,6 +3284,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
return null;
|
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
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_VM_DESTROY, eventDescription = "destroying Vm", async = true)
|
@ActionEvent(eventType = EventTypes.EVENT_VM_DESTROY, eventDescription = "destroying Vm", async = true)
|
||||||
public UserVm destroyVm(DestroyVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException {
|
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
|
// check if vm belongs to AutoScale vm group in Disabled state
|
||||||
autoScaleManager.checkIfVmActionAllowed(vmId);
|
autoScaleManager.checkIfVmActionAllowed(vmId);
|
||||||
|
|
||||||
|
// check if vm belongs to any plugin resources
|
||||||
|
checkPluginsIfVmCanBeDestroyed(vm);
|
||||||
|
|
||||||
// check if there are active volume snapshots tasks
|
// 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);
|
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)) {
|
if (checkStatusOfVolumeSnapshots(vmId, Volume.Type.ROOT)) {
|
||||||
|
|||||||
@ -226,6 +226,10 @@
|
|||||||
<artifactId>tink</artifactId>
|
<artifactId>tink</artifactId>
|
||||||
<version>${cs.tink.version}</version>
|
<version>${cs.tink.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import javax.management.MalformedObjectNameException;
|
|||||||
import javax.management.NotCompliantMBeanException;
|
import javax.management.NotCompliantMBeanException;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.MapUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.springframework.aop.framework.Advised;
|
import org.springframework.aop.framework.Advised;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
@ -286,4 +287,22 @@ public class ComponentContext implements ApplicationContextAware {
|
|||||||
private static synchronized void initInitializeBeans(boolean initializeBeans) {
|
private static synchronized void initInitializeBeans(boolean initializeBeans) {
|
||||||
s_initializeBeans = 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