Skip to content

Commit b29391c

Browse files
committed
Merge LTS branch '4.19' into main
2 parents 0c61531 + c779b1c commit b29391c

70 files changed

Lines changed: 416 additions & 9128 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616
// under the License.
1717
package com.cloud.kubernetes.cluster;
1818

19-
import com.cloud.utils.component.Adapter;
2019
import org.apache.cloudstack.acl.ControlledEntity;
2120

21+
import com.cloud.uservm.UserVm;
22+
import com.cloud.utils.component.Adapter;
23+
2224
public interface KubernetesClusterHelper extends Adapter {
2325

2426
ControlledEntity findByUuid(String uuid);
2527
ControlledEntity findByVmId(long vmId);
28+
void checkVmCanBeDestroyed(UserVm userVm);
2629
}

api/src/main/java/com/cloud/uservm/UserVm.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,6 @@ public interface UserVm extends VirtualMachine, ControlledEntity {
4848
void setAccountId(long accountId);
4949

5050
public boolean isDisplayVm();
51+
52+
String getUserVmType();
5153
}

api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
// under the License.
1717
package org.apache.cloudstack.api.command.user.vm;
1818

19-
import java.util.ArrayList;
2019
import java.util.EnumSet;
20+
import java.util.HashSet;
2121
import java.util.List;
22+
import java.util.Set;
2223

2324
import org.apache.cloudstack.acl.RoleType;
2425
import org.apache.cloudstack.affinity.AffinityGroupResponse;
@@ -45,6 +46,7 @@
4546
import org.apache.cloudstack.api.response.VpcResponse;
4647
import org.apache.cloudstack.api.response.ZoneResponse;
4748
import org.apache.commons.lang3.BooleanUtils;
49+
import org.apache.commons.collections.CollectionUtils;
4850

4951
import com.cloud.exception.InvalidParameterValueException;
5052
import com.cloud.server.ResourceIcon;
@@ -56,7 +58,6 @@
5658
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
5759
public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd {
5860

59-
private static final String s_name = "listvirtualmachinesresponse";
6061

6162
/////////////////////////////////////////////////////
6263
//////////////// API parameters /////////////////////
@@ -96,7 +97,8 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements
9697
collectionType = CommandType.STRING,
9798
description = "comma separated list of vm details requested, "
9899
+ "value can be a list of [all, group, nics, stats, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp]."
99-
+ " If no parameter is passed in, the details will be defaulted to all")
100+
+ " If no parameter is passed in, the details will be defaulted to all. When return.vm.stats.on.vm.list is true, the default" +
101+
"details change to [group, nics, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp], thus the stats will not be returned. ")
100102
private List<String> viewDetails;
101103

102104
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "list vms by template")
@@ -237,22 +239,32 @@ public Long getAutoScaleVmGroupId() {
237239
return autoScaleVmGroupId;
238240
}
239241

242+
protected boolean isViewDetailsEmpty() {
243+
return CollectionUtils.isEmpty(viewDetails);
244+
}
245+
240246
public EnumSet<VMDetails> getDetails() throws InvalidParameterValueException {
241-
EnumSet<VMDetails> dv;
242-
if (viewDetails == null || viewDetails.size() <= 0) {
243-
dv = EnumSet.of(VMDetails.all);
244-
} else {
245-
try {
246-
ArrayList<VMDetails> dc = new ArrayList<VMDetails>();
247-
for (String detail : viewDetails) {
248-
dc.add(VMDetails.valueOf(detail));
249-
}
250-
dv = EnumSet.copyOf(dc);
251-
} catch (IllegalArgumentException e) {
252-
throw new InvalidParameterValueException("The details parameter contains a non permitted value. The allowed values are " + EnumSet.allOf(VMDetails.class));
247+
if (isViewDetailsEmpty()) {
248+
if (_queryService.ReturnVmStatsOnVmList.value()) {
249+
return EnumSet.of(VMDetails.all);
250+
}
251+
252+
Set<VMDetails> allDetails = new HashSet<>(Set.of(VMDetails.values()));
253+
allDetails.remove(VMDetails.stats);
254+
allDetails.remove(VMDetails.all);
255+
return EnumSet.copyOf(allDetails);
256+
}
257+
258+
try {
259+
Set<VMDetails> dc = new HashSet<>();
260+
for (String detail : viewDetails) {
261+
dc.add(VMDetails.valueOf(detail));
253262
}
263+
264+
return EnumSet.copyOf(dc);
265+
} catch (IllegalArgumentException e) {
266+
throw new InvalidParameterValueException("The details parameter contains a non permitted value. The allowed values are " + EnumSet.allOf(VMDetails.class));
254267
}
255-
return dv;
256268
}
257269

258270
@Override
@@ -275,10 +287,6 @@ public Boolean getVnf() {
275287
/////////////////////////////////////////////////////
276288
/////////////// API Implementation///////////////////
277289
/////////////////////////////////////////////////////
278-
@Override
279-
public String getCommandName() {
280-
return s_name;
281-
}
282290

283291
@Override
284292
public ApiCommandResourceType getApiResourceType() {

api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.cloud.uservm.UserVm;
3838
import com.cloud.vm.VirtualMachine;
3939
import com.google.gson.annotations.SerializedName;
40+
import org.apache.commons.collections.CollectionUtils;
4041

4142
@SuppressWarnings("unused")
4243
@EntityReference(value = {VirtualMachine.class, UserVm.class, VirtualRouter.class})
@@ -273,6 +274,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
273274
@Param(description = "the hypervisor on which the template runs")
274275
private String hypervisor;
275276

277+
@SerializedName(ApiConstants.IP_ADDRESS)
278+
@Param(description = "the VM's primary IP address")
279+
private String ipAddress;
280+
276281
@SerializedName(ApiConstants.PUBLIC_IP_ID)
277282
@Param(description = "public IP address id associated with vm via Static nat rule")
278283
private String publicIpId;
@@ -627,6 +632,10 @@ public String getHypervisor() {
627632
return hypervisor;
628633
}
629634

635+
public String getIpAddress() {
636+
return ipAddress;
637+
}
638+
630639
public String getPublicIpId() {
631640
return publicIpId;
632641
}
@@ -863,6 +872,13 @@ public void setForVirtualNetwork(Boolean forVirtualNetwork) {
863872

864873
public void setNics(Set<NicResponse> nics) {
865874
this.nics = nics;
875+
setIpAddress(nics);
876+
}
877+
878+
public void setIpAddress(final Set<NicResponse> nics) {
879+
if (CollectionUtils.isNotEmpty(nics)) {
880+
this.ipAddress = nics.iterator().next().getIpaddress();
881+
}
866882
}
867883

868884
public void addNic(NicResponse nic) {

api/src/main/java/org/apache/cloudstack/query/QueryService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ public interface QueryService {
125125
static final ConfigKey<Boolean> SharePublicTemplatesWithOtherDomains = new ConfigKey<>("Advanced", Boolean.class, "share.public.templates.with.other.domains", "true",
126126
"If false, templates of this domain will not show up in the list templates of other domains.", true, ConfigKey.Scope.Domain);
127127

128+
ConfigKey<Boolean> ReturnVmStatsOnVmList = new ConfigKey<>("Advanced", Boolean.class, "return.vm.stats.on.vm.list", "true",
129+
"If false, changes the listVirtualMachines default details to [group, nics, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp], so that the VMs' stats" +
130+
" are not returned by default when listing VMs; only when the 'stats' or 'all' detail is informed.", true, ConfigKey.Scope.Global);
131+
128132
ListResponse<UserResponse> searchForUsers(ListUsersCmd cmd) throws PermissionDeniedException;
129133

130134
ListResponse<UserResponse> searchForUsers(Long domainId, boolean recursive) throws PermissionDeniedException;

engine/schema/src/main/java/com/cloud/vm/UserVmVO.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ public boolean isUpdateParameters() {
148148
return updateParameters;
149149
}
150150

151+
@Override
151152
public String getUserVmType() {
152153
return userVmType;
153154
}

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterHelperImpl.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,24 @@
1818

1919
import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
2020
import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
21+
import com.cloud.uservm.UserVm;
2122
import com.cloud.utils.component.AdapterBase;
23+
import com.cloud.utils.exception.CloudRuntimeException;
24+
import com.cloud.vm.UserVmManager;
25+
26+
import javax.inject.Inject;
27+
2228
import org.apache.cloudstack.acl.ControlledEntity;
2329
import org.apache.cloudstack.framework.config.ConfigKey;
2430
import org.apache.cloudstack.framework.config.Configurable;
31+
import org.apache.log4j.Logger;
2532
import org.springframework.stereotype.Component;
2633

27-
import javax.inject.Inject;
2834
import java.util.Objects;
2935

3036
@Component
3137
public class KubernetesClusterHelperImpl extends AdapterBase implements KubernetesClusterHelper, Configurable {
38+
private static final Logger logger = Logger.getLogger(KubernetesClusterHelperImpl.class);
3239

3340
@Inject
3441
private KubernetesClusterDao kubernetesClusterDao;
@@ -49,6 +56,26 @@ public ControlledEntity findByVmId(long vmId) {
4956
return kubernetesClusterDao.findById(clusterVmMapVO.getClusterId());
5057
}
5158

59+
@Override
60+
public void checkVmCanBeDestroyed(UserVm userVm) {
61+
if (!UserVmManager.CKS_NODE.equals(userVm.getUserVmType())) {
62+
return;
63+
}
64+
KubernetesClusterVmMapVO vmMapVO = kubernetesClusterVmMapDao.findByVmId(userVm.getId());
65+
if (vmMapVO == null) {
66+
return;
67+
}
68+
logger.error(String.format("VM ID: %s is a part of Kubernetes cluster ID: %d", userVm.getId(), vmMapVO.getClusterId()));
69+
KubernetesCluster kubernetesCluster = kubernetesClusterDao.findById(vmMapVO.getClusterId());
70+
String msg = "Instance is a part of a Kubernetes cluster";
71+
if (kubernetesCluster != null) {
72+
msg += String.format(": %s", kubernetesCluster.getName());
73+
}
74+
msg += ". Use Instance delete option from Kubernetes cluster details or scale API for " +
75+
"Kubernetes clusters with 'nodeids' to destroy the instance.";
76+
throw new CloudRuntimeException(msg);
77+
}
78+
5279
@Override
5380
public String getConfigComponentName() {
5481
return KubernetesClusterHelper.class.getSimpleName();

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ public interface KubernetesClusterVmMapDao extends GenericDao<KubernetesClusterV
3030
int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
3131

3232
public int removeByClusterId(long clusterId);
33+
34+
KubernetesClusterVmMapVO findByVmId(long vmId);
3335
}

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,14 @@ public int removeByClusterId(long clusterId) {
8181
sc.setParameters("clusterId", clusterId);
8282
return remove(sc);
8383
}
84+
85+
@Override
86+
public KubernetesClusterVmMapVO findByVmId(long vmId) {
87+
SearchBuilder<KubernetesClusterVmMapVO> sb = createSearchBuilder();
88+
sb.and("vmId", sb.entity().getVmId(), SearchCriteria.Op.EQ);
89+
sb.done();
90+
SearchCriteria<KubernetesClusterVmMapVO> sc = sb.create();
91+
sc.setParameters("vmId", vmId);
92+
return findOneBy(sc);
93+
}
8494
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.kubernetes.cluster;
18+
19+
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
import org.mockito.InjectMocks;
23+
import org.mockito.Mock;
24+
import org.mockito.Mockito;
25+
import org.mockito.junit.MockitoJUnitRunner;
26+
27+
import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
28+
import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
29+
import com.cloud.uservm.UserVm;
30+
import com.cloud.utils.exception.CloudRuntimeException;
31+
import com.cloud.vm.UserVmManager;
32+
33+
@RunWith(MockitoJUnitRunner.class)
34+
public class KubernetesClusterHelperImplTest {
35+
@Mock
36+
KubernetesClusterVmMapDao kubernetesClusterVmMapDao;
37+
@Mock
38+
KubernetesClusterDao kubernetesClusterDao;
39+
40+
@InjectMocks
41+
KubernetesClusterHelperImpl kubernetesClusterHelper = new KubernetesClusterHelperImpl();
42+
43+
@Test
44+
public void testCheckVmCanBeDestroyedNotCKSNode() {
45+
UserVm vm = Mockito.mock(UserVm.class);
46+
Mockito.when(vm.getUserVmType()).thenReturn("");
47+
kubernetesClusterHelper.checkVmCanBeDestroyed(vm);
48+
Mockito.verify(kubernetesClusterVmMapDao, Mockito.never()).findByVmId(Mockito.anyLong());
49+
}
50+
51+
@Test
52+
public void testCheckVmCanBeDestroyedNotInCluster() {
53+
UserVm vm = Mockito.mock(UserVm.class);
54+
Mockito.when(vm.getId()).thenReturn(1L);
55+
Mockito.when(vm.getUserVmType()).thenReturn(UserVmManager.CKS_NODE);
56+
Mockito.when(kubernetesClusterVmMapDao.findByVmId(1L)).thenReturn(null);
57+
kubernetesClusterHelper.checkVmCanBeDestroyed(vm);
58+
}
59+
60+
@Test(expected = CloudRuntimeException.class)
61+
public void testCheckVmCanBeDestroyedInCluster() {
62+
UserVm vm = Mockito.mock(UserVm.class);
63+
Mockito.when(vm.getId()).thenReturn(1L);
64+
Mockito.when(vm.getUserVmType()).thenReturn(UserVmManager.CKS_NODE);
65+
KubernetesClusterVmMapVO map = Mockito.mock(KubernetesClusterVmMapVO.class);
66+
Mockito.when(map.getClusterId()).thenReturn(1L);
67+
Mockito.when(kubernetesClusterVmMapDao.findByVmId(1L)).thenReturn(map);
68+
Mockito.when(kubernetesClusterDao.findById(1L)).thenReturn(Mockito.mock(KubernetesClusterVO.class));
69+
kubernetesClusterHelper.checkVmCanBeDestroyed(vm);
70+
}
71+
}

0 commit comments

Comments
 (0)