|
58 | 58 | import org.apache.cloudstack.acl.SecurityChecker; |
59 | 59 | import org.apache.cloudstack.affinity.AffinityGroupVO; |
60 | 60 | import org.apache.cloudstack.affinity.dao.AffinityGroupDao; |
| 61 | +import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; |
61 | 62 | import org.apache.cloudstack.annotation.AnnotationService; |
62 | 63 | import org.apache.cloudstack.annotation.dao.AnnotationDao; |
63 | 64 | import org.apache.cloudstack.api.ApiCommandResourceType; |
|
86 | 87 | import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd; |
87 | 88 | import org.apache.cloudstack.api.command.user.kubernetes.cluster.StartKubernetesClusterCmd; |
88 | 89 | import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd; |
| 90 | +import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpdateKubernetesClusterAffinityGroupCmd; |
89 | 91 | import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpgradeKubernetesClusterCmd; |
90 | 92 | import org.apache.cloudstack.api.command.user.loadbalancer.AssignToLoadBalancerRuleCmd; |
91 | 93 | import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; |
@@ -332,6 +334,8 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne |
332 | 334 | @Inject |
333 | 335 | protected AffinityGroupDao affinityGroupDao; |
334 | 336 | @Inject |
| 337 | + protected AffinityGroupVMMapDao affinityGroupVMMapDao; |
| 338 | + @Inject |
335 | 339 | protected ServiceOfferingDao serviceOfferingDao; |
336 | 340 | @Inject |
337 | 341 | protected UserDataDao userDataDao; |
@@ -952,7 +956,7 @@ protected void setNodeTypeAffinityGroupResponse(KubernetesClusterResponse respon |
952 | 956 |
|
953 | 957 | protected void setAffinityGroupResponseForNodeType(KubernetesClusterResponse response, long clusterId, String nodeType) { |
954 | 958 | List<Long> affinityGroupIds = kubernetesClusterAffinityGroupMapDao.listAffinityGroupIdsByClusterIdAndNodeType(clusterId, nodeType); |
955 | | - if (affinityGroupIds == null || affinityGroupIds.isEmpty()) { |
| 959 | + if (CollectionUtils.isEmpty(affinityGroupIds)) { |
956 | 960 | return; |
957 | 961 | } |
958 | 962 | List<String> affinityGroupUuids = new ArrayList<>(); |
@@ -2313,6 +2317,94 @@ public boolean upgradeKubernetesCluster(UpgradeKubernetesClusterCmd cmd) throws |
2313 | 2317 | return upgradeWorker.upgradeCluster(); |
2314 | 2318 | } |
2315 | 2319 |
|
| 2320 | + @Override |
| 2321 | + @ActionEvent(eventType = KubernetesClusterEventTypes.EVENT_KUBERNETES_CLUSTER_AFFINITY_UPDATE, |
| 2322 | + eventDescription = "updating Kubernetes cluster affinity groups") |
| 2323 | + public boolean updateKubernetesClusterAffinityGroups(UpdateKubernetesClusterAffinityGroupCmd cmd) throws CloudRuntimeException { |
| 2324 | + if (!KubernetesServiceEnabled.value()) { |
| 2325 | + logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled"); |
| 2326 | + } |
| 2327 | + KubernetesClusterVO kubernetesCluster = validateClusterForAffinityGroupUpdate(cmd.getId()); |
| 2328 | + Map<String, List<Long>> affinityGroupNodeTypeMap = cmd.getAffinityGroupNodeTypeMap(); |
| 2329 | + validateNodeAffinityGroups(affinityGroupNodeTypeMap, kubernetesCluster.getAccountId()); |
| 2330 | + |
| 2331 | + final Long clusterId = kubernetesCluster.getId(); |
| 2332 | + Transaction.execute(new TransactionCallbackNoReturn() { |
| 2333 | + @Override |
| 2334 | + public void doInTransactionWithoutResult(TransactionStatus status) { |
| 2335 | + kubernetesClusterAffinityGroupMapDao.removeByClusterId(clusterId); |
| 2336 | + persistAffinityGroupMappings(clusterId, affinityGroupNodeTypeMap); |
| 2337 | + syncVmAffinityGroups(clusterId, affinityGroupNodeTypeMap); |
| 2338 | + } |
| 2339 | + }); |
| 2340 | + logger.info("Updated affinity groups for Kubernetes cluster {}", kubernetesCluster.getName()); |
| 2341 | + return true; |
| 2342 | + } |
| 2343 | + |
| 2344 | + private KubernetesClusterVO validateClusterForAffinityGroupUpdate(Long clusterId) { |
| 2345 | + KubernetesClusterVO kubernetesCluster = kubernetesClusterDao.findById(clusterId); |
| 2346 | + if (Objects.isNull(kubernetesCluster) || Objects.nonNull(kubernetesCluster.getRemoved())) { |
| 2347 | + throw new InvalidParameterValueException("Invalid Kubernetes cluster ID"); |
| 2348 | + } |
| 2349 | + if (!KubernetesCluster.ClusterType.CloudManaged.equals(kubernetesCluster.getClusterType())) { |
| 2350 | + throw new InvalidParameterValueException("Affinity groups can only be updated for CloudManaged Kubernetes clusters"); |
| 2351 | + } |
| 2352 | + if (!KubernetesCluster.State.Stopped.equals(kubernetesCluster.getState())) { |
| 2353 | + throw new InvalidParameterValueException(String.format( |
| 2354 | + "Kubernetes cluster %s must be stopped before updating affinity groups (current state: %s)", |
| 2355 | + kubernetesCluster.getName(), kubernetesCluster.getState())); |
| 2356 | + } |
| 2357 | + accountManager.checkAccess(CallContext.current().getCallingAccount(), |
| 2358 | + SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster); |
| 2359 | + return kubernetesCluster; |
| 2360 | + } |
| 2361 | + |
| 2362 | + private void validateNodeAffinityGroups(Map<String, List<Long>> affinityGroupNodeTypeMap, long ownerAccountId) { |
| 2363 | + if (MapUtils.isEmpty(affinityGroupNodeTypeMap)) { |
| 2364 | + return; |
| 2365 | + } |
| 2366 | + Account owner = accountDao.findById(ownerAccountId); |
| 2367 | + for (List<Long> affinityGroupIds : affinityGroupNodeTypeMap.values()) { |
| 2368 | + for (Long affinityGroupId : affinityGroupIds) { |
| 2369 | + AffinityGroupVO affinityGroup = affinityGroupDao.findById(affinityGroupId); |
| 2370 | + if (Objects.isNull(affinityGroup)) { |
| 2371 | + throw new InvalidParameterValueException("Unable to find affinity group with ID: " + affinityGroupId); |
| 2372 | + } |
| 2373 | + if (affinityGroup.getAccountId() != owner.getAccountId()) { |
| 2374 | + throw new InvalidParameterValueException(String.format( |
| 2375 | + "Affinity group %s does not belong to the cluster owner account %s", |
| 2376 | + affinityGroup.getName(), owner.getAccountName())); |
| 2377 | + } |
| 2378 | + } |
| 2379 | + } |
| 2380 | + } |
| 2381 | + |
| 2382 | + private void syncVmAffinityGroups(Long clusterId, Map<String, List<Long>> affinityGroupNodeTypeMap) { |
| 2383 | + List<KubernetesClusterVmMapVO> clusterVmMappings = kubernetesClusterVmMapDao.listByClusterId(clusterId); |
| 2384 | + if (CollectionUtils.isEmpty(clusterVmMappings)) { |
| 2385 | + return; |
| 2386 | + } |
| 2387 | + Map<String, List<Long>> nodeTypeAffinityMap = MapUtils.isEmpty(affinityGroupNodeTypeMap) |
| 2388 | + ? Collections.emptyMap() : affinityGroupNodeTypeMap; |
| 2389 | + for (KubernetesClusterVmMapVO clusterVmMapping : clusterVmMappings) { |
| 2390 | + if (clusterVmMapping.isExternalNode()) { |
| 2391 | + continue; |
| 2392 | + } |
| 2393 | + String nodeType = getNodeType(clusterVmMapping); |
| 2394 | + affinityGroupVMMapDao.updateMap(clusterVmMapping.getVmId(), |
| 2395 | + nodeTypeAffinityMap.getOrDefault(nodeType, Collections.emptyList())); |
| 2396 | + } |
| 2397 | + } |
| 2398 | + |
| 2399 | + private String getNodeType(KubernetesClusterVmMapVO clusterVmMapping) { |
| 2400 | + if (clusterVmMapping.isControlNode()) { |
| 2401 | + return CONTROL.name(); |
| 2402 | + } else if (clusterVmMapping.isEtcdNode()) { |
| 2403 | + return ETCD.name(); |
| 2404 | + } |
| 2405 | + return WORKER.name(); |
| 2406 | + } |
| 2407 | + |
2316 | 2408 | private void updateNodeCount(KubernetesClusterVO kubernetesCluster) { |
2317 | 2409 | List<KubernetesClusterVmMapVO> nodeList = kubernetesClusterVmMapDao.listByClusterId(kubernetesCluster.getId()); |
2318 | 2410 | kubernetesCluster.setControlNodeCount(nodeList.stream().filter(KubernetesClusterVmMapVO::isControlNode).count()); |
@@ -2664,6 +2756,7 @@ public List<Class<?>> getCommands() { |
2664 | 2756 | cmdList.add(RemoveVirtualMachinesFromKubernetesClusterCmd.class); |
2665 | 2757 | cmdList.add(AddNodesToKubernetesClusterCmd.class); |
2666 | 2758 | cmdList.add(RemoveNodesFromKubernetesClusterCmd.class); |
| 2759 | + cmdList.add(UpdateKubernetesClusterAffinityGroupCmd.class); |
2667 | 2760 | return cmdList; |
2668 | 2761 | } |
2669 | 2762 |
|
|
0 commit comments