mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
cks: Add unmanaged kubernetes cluster (#7515)
There are tools like cluster-api which create and manage kubernetes cluster on CloudStack. This PR adds the option to add unmanaged kubernetes cluster which are not managed by CKS plugin. This helps provide a consolidated view of unmanaged clusters on CloudStack. The changes done make sure that operations for managed clusters are not executed for unmanaged clusters. Two new APIs have also been added: 1. addVirtualMachinesToKubernetesCluster - to add VMs to unmanaged clusters. 2. removeVirtualMachinesFromKubernetesCluster - to remove VMs to unmanaged clusters. Two APIs have been updated: 1. createKubernetesCluster - made KUBERNETES_VERSION_ID, SERVICE_OFFERING_ID, SIZE as not required for unmanaged clusters. Add an additional parameter, managed, which is true by default. 2. listKubernetesClusters - Add a parameter managed to filter on managed field. Co-authored-by: Pearl Dsilva <pearl1594@gmail.com> Co-authored-by: dahn <daan.hoogland@gmail.com>
This commit is contained in:
parent
c6237c48ac
commit
2fcbe6241f
@ -248,6 +248,7 @@ public class ApiConstants {
|
|||||||
public static final String IP_AVAILABLE = "ipavailable";
|
public static final String IP_AVAILABLE = "ipavailable";
|
||||||
public static final String IP_LIMIT = "iplimit";
|
public static final String IP_LIMIT = "iplimit";
|
||||||
public static final String IP_TOTAL = "iptotal";
|
public static final String IP_TOTAL = "iptotal";
|
||||||
|
public static final String IS_CONTROL_NODE = "iscontrolnode";
|
||||||
public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired";
|
public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired";
|
||||||
public static final String IS_DYNAMIC = "isdynamic";
|
public static final String IS_DYNAMIC = "isdynamic";
|
||||||
public static final String IS_EDGE = "isedge";
|
public static final String IS_EDGE = "isedge";
|
||||||
|
|||||||
@ -176,3 +176,7 @@ CREATE TABLE `cloud`.`vm_scheduled_job` (
|
|||||||
CONSTRAINT `fk_vm_scheduled_job__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE,
|
CONSTRAINT `fk_vm_scheduled_job__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE,
|
||||||
CONSTRAINT `fk_vm_scheduled_job__vm_schedule_id` FOREIGN KEY (`vm_schedule_id`) REFERENCES `vm_schedule`(`id`) ON DELETE CASCADE
|
CONSTRAINT `fk_vm_scheduled_job__vm_schedule_id` FOREIGN KEY (`vm_schedule_id`) REFERENCES `vm_schedule`(`id`) ON DELETE CASCADE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
-- Add support for different cluster types for kubernetes
|
||||||
|
ALTER TABLE `cloud`.`kubernetes_cluster` ADD COLUMN `cluster_type` varchar(64) DEFAULT 'CloudManaged' COMMENT 'type of cluster';
|
||||||
|
ALTER TABLE `cloud`.`kubernetes_cluster` MODIFY COLUMN `kubernetes_version_id` bigint unsigned NULL COMMENT 'the ID of the Kubernetes version of this Kubernetes cluster';
|
||||||
|
|||||||
@ -32,6 +32,10 @@ import com.cloud.utils.fsm.StateMachine2;
|
|||||||
*/
|
*/
|
||||||
public interface KubernetesCluster extends ControlledEntity, com.cloud.utils.fsm.StateObject<KubernetesCluster.State>, Identity, InternalIdentity, Displayable {
|
public interface KubernetesCluster extends ControlledEntity, com.cloud.utils.fsm.StateObject<KubernetesCluster.State>, Identity, InternalIdentity, Displayable {
|
||||||
|
|
||||||
|
enum ClusterType {
|
||||||
|
CloudManaged, ExternalManaged;
|
||||||
|
};
|
||||||
|
|
||||||
enum Event {
|
enum Event {
|
||||||
StartRequested,
|
StartRequested,
|
||||||
StopRequested,
|
StopRequested,
|
||||||
@ -115,10 +119,10 @@ public interface KubernetesCluster extends ControlledEntity, com.cloud.utils.fsm
|
|||||||
String getName();
|
String getName();
|
||||||
String getDescription();
|
String getDescription();
|
||||||
long getZoneId();
|
long getZoneId();
|
||||||
long getKubernetesVersionId();
|
Long getKubernetesVersionId();
|
||||||
long getServiceOfferingId();
|
Long getServiceOfferingId();
|
||||||
long getTemplateId();
|
Long getTemplateId();
|
||||||
long getNetworkId();
|
Long getNetworkId();
|
||||||
long getDomainId();
|
long getDomainId();
|
||||||
long getAccountId();
|
long getAccountId();
|
||||||
long getControlNodeCount();
|
long getControlNodeCount();
|
||||||
@ -137,4 +141,5 @@ public interface KubernetesCluster extends ControlledEntity, com.cloud.utils.fsm
|
|||||||
Long getMinSize();
|
Long getMinSize();
|
||||||
Long getMaxSize();
|
Long getMaxSize();
|
||||||
Long getSecurityGroupId();
|
Long getSecurityGroupId();
|
||||||
|
ClusterType getClusterType();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package com.cloud.kubernetes.cluster;
|
package com.cloud.kubernetes.cluster;
|
||||||
|
|
||||||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||||
|
import static com.cloud.vm.UserVmManager.AllowUserExpungeRecoverVm;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@ -25,8 +26,11 @@ import java.util.Arrays;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -36,17 +40,22 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.uservm.UserVm;
|
||||||
|
import com.cloud.vm.UserVmService;
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
import org.apache.cloudstack.acl.SecurityChecker;
|
import org.apache.cloudstack.acl.SecurityChecker;
|
||||||
import org.apache.cloudstack.annotation.AnnotationService;
|
import org.apache.cloudstack.annotation.AnnotationService;
|
||||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.api.ApiConstants.VMDetails;
|
import org.apache.cloudstack.api.ApiConstants.VMDetails;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.AddVirtualMachinesToKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.DeleteKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.DeleteKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.RemoveVirtualMachinesFromKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.StartKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.StartKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd;
|
||||||
@ -54,6 +63,7 @@ import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpgradeKubernet
|
|||||||
import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
|
import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
|
||||||
import org.apache.cloudstack.api.response.KubernetesClusterResponse;
|
import org.apache.cloudstack.api.response.KubernetesClusterResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
import org.apache.cloudstack.api.response.RemoveVirtualMachinesFromKubernetesClusterResponse;
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
import org.apache.cloudstack.config.ApiServiceConfiguration;
|
import org.apache.cloudstack.config.ApiServiceConfiguration;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
@ -244,6 +254,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
@Inject
|
@Inject
|
||||||
public SecurityGroupService securityGroupService;
|
public SecurityGroupService securityGroupService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private UserVmService userVmService;
|
||||||
|
|
||||||
private void logMessage(final Level logLevel, final String message, final Exception e) {
|
private void logMessage(final Level logLevel, final String message, final Exception e) {
|
||||||
if (logLevel == Level.WARN) {
|
if (logLevel == Level.WARN) {
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
@ -535,10 +548,14 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
response.setControlNodes(kubernetesCluster.getControlNodeCount());
|
response.setControlNodes(kubernetesCluster.getControlNodeCount());
|
||||||
response.setClusterSize(kubernetesCluster.getNodeCount());
|
response.setClusterSize(kubernetesCluster.getNodeCount());
|
||||||
VMTemplateVO template = ApiDBUtils.findTemplateById(kubernetesCluster.getTemplateId());
|
VMTemplateVO template = ApiDBUtils.findTemplateById(kubernetesCluster.getTemplateId());
|
||||||
response.setTemplateId(template.getUuid());
|
if (template != null) {
|
||||||
|
response.setTemplateId(template.getUuid());
|
||||||
|
}
|
||||||
ServiceOfferingVO offering = serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
|
ServiceOfferingVO offering = serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
|
||||||
response.setServiceOfferingId(offering.getUuid());
|
if (offering != null) {
|
||||||
response.setServiceOfferingName(offering.getName());
|
response.setServiceOfferingId(offering.getUuid());
|
||||||
|
response.setServiceOfferingName(offering.getName());
|
||||||
|
}
|
||||||
KubernetesSupportedVersionVO version = kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
|
KubernetesSupportedVersionVO version = kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
response.setKubernetesVersionId(version.getUuid());
|
response.setKubernetesVersionId(version.getUuid());
|
||||||
@ -561,13 +578,15 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
response.setMemory(String.valueOf(kubernetesCluster.getMemory()));
|
response.setMemory(String.valueOf(kubernetesCluster.getMemory()));
|
||||||
NetworkVO ntwk = networkDao.findByIdIncludingRemoved(kubernetesCluster.getNetworkId());
|
NetworkVO ntwk = networkDao.findByIdIncludingRemoved(kubernetesCluster.getNetworkId());
|
||||||
response.setEndpoint(kubernetesCluster.getEndpoint());
|
response.setEndpoint(kubernetesCluster.getEndpoint());
|
||||||
response.setNetworkId(ntwk.getUuid());
|
if (ntwk != null) {
|
||||||
response.setAssociatedNetworkName(ntwk.getName());
|
response.setNetworkId(ntwk.getUuid());
|
||||||
if (ntwk.getGuestType() == Network.GuestType.Isolated) {
|
response.setAssociatedNetworkName(ntwk.getName());
|
||||||
List<IPAddressVO> ipAddresses = ipAddressDao.listByAssociatedNetwork(ntwk.getId(), true);
|
if (ntwk.getGuestType() == Network.GuestType.Isolated) {
|
||||||
if (ipAddresses != null && ipAddresses.size() == 1) {
|
List<IPAddressVO> ipAddresses = ipAddressDao.listByAssociatedNetwork(ntwk.getId(), true);
|
||||||
response.setIpAddress(ipAddresses.get(0).getAddress().addr());
|
if (ipAddresses != null && ipAddresses.size() == 1) {
|
||||||
response.setIpAddressId(ipAddresses.get(0).getUuid());
|
response.setIpAddress(ipAddresses.get(0).getAddress().addr());
|
||||||
|
response.setIpAddressId(ipAddresses.get(0).getUuid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,6 +614,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
response.setAutoscalingEnabled(kubernetesCluster.getAutoscalingEnabled());
|
response.setAutoscalingEnabled(kubernetesCluster.getAutoscalingEnabled());
|
||||||
response.setMinSize(kubernetesCluster.getMinSize());
|
response.setMinSize(kubernetesCluster.getMinSize());
|
||||||
response.setMaxSize(kubernetesCluster.getMaxSize());
|
response.setMaxSize(kubernetesCluster.getMaxSize());
|
||||||
|
response.setClusterType(kubernetesCluster.getClusterType());
|
||||||
response.setCreated(kubernetesCluster.getCreated());
|
response.setCreated(kubernetesCluster.getCreated());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -608,7 +628,95 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateKubernetesClusterCreateParameters(final CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
private DataCenter validateAndGetZoneForKubernetesCreateParameters(Long zoneId) {
|
||||||
|
DataCenter zone = dataCenterDao.findById(zoneId);
|
||||||
|
if (zone == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find zone by ID: " + zoneId);
|
||||||
|
}
|
||||||
|
if (zone.getAllocationState() == Grouping.AllocationState.Disabled) {
|
||||||
|
throw new PermissionDeniedException(String.format("Cannot perform this operation, zone ID: %s is currently disabled", zone.getUuid()));
|
||||||
|
}
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSshKeyPairForKubernetesCreateParameters(String sshKeyPair, Account owner) {
|
||||||
|
if (!StringUtils.isBlank(sshKeyPair)) {
|
||||||
|
SSHKeyPairVO sshKeyPairVO = sshKeyPairDao.findByName(owner.getAccountId(), owner.getDomainId(), sshKeyPair);
|
||||||
|
if (sshKeyPairVO == null) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Given SSH key pair with name: %s was not found for the account %s", sshKeyPair, owner.getAccountName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Network validateAndGetNetworkForKubernetesCreateParameters(Long networkId) {
|
||||||
|
Network network = null;
|
||||||
|
if (networkId != null) {
|
||||||
|
network = networkService.getNetwork(networkId);
|
||||||
|
if (network == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find network with given ID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateUnmanagedKubernetesClusterCreateParameters(final CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
||||||
|
final String name = cmd.getName();
|
||||||
|
final Long zoneId = cmd.getZoneId();
|
||||||
|
final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
||||||
|
final Long networkId = cmd.getNetworkId();
|
||||||
|
final String sshKeyPair = cmd.getSSHKeyPairName();
|
||||||
|
final String dockerRegistryUserName = cmd.getDockerRegistryUserName();
|
||||||
|
final String dockerRegistryPassword = cmd.getDockerRegistryPassword();
|
||||||
|
final String dockerRegistryUrl = cmd.getDockerRegistryUrl();
|
||||||
|
final Long nodeRootDiskSize = cmd.getNodeRootDiskSize();
|
||||||
|
final String externalLoadBalancerIpAddress = cmd.getExternalLoadBalancerIpAddress();
|
||||||
|
|
||||||
|
if (name == null || name.isEmpty()) {
|
||||||
|
throw new InvalidParameterValueException("Invalid name for the Kubernetes cluster name: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAndGetZoneForKubernetesCreateParameters(zoneId);
|
||||||
|
validateSshKeyPairForKubernetesCreateParameters(sshKeyPair, owner);
|
||||||
|
|
||||||
|
if (nodeRootDiskSize != null && nodeRootDiskSize <= 0) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Invalid value for %s", ApiConstants.NODE_ROOT_DISK_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
validateDockerRegistryParams(dockerRegistryUserName, dockerRegistryPassword, dockerRegistryUrl);
|
||||||
|
|
||||||
|
validateAndGetNetworkForKubernetesCreateParameters(networkId);
|
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(externalLoadBalancerIpAddress) && (!NetUtils.isValidIp4(externalLoadBalancerIpAddress) && !NetUtils.isValidIp6(externalLoadBalancerIpAddress))) {
|
||||||
|
throw new InvalidParameterValueException("Invalid external load balancer IP address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCommandSupported(KubernetesCluster cluster, String cmdName) {
|
||||||
|
switch (cluster.getClusterType()) {
|
||||||
|
case CloudManaged:
|
||||||
|
return Arrays.asList(
|
||||||
|
BaseCmd.getCommandNameByClass(CreateKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(ListKubernetesClustersCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(DeleteKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(ScaleKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(StartKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(StopKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(UpgradeKubernetesClusterCmd.class)
|
||||||
|
).contains(cmdName);
|
||||||
|
case ExternalManaged:
|
||||||
|
return Arrays.asList(
|
||||||
|
BaseCmd.getCommandNameByClass(CreateKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(ListKubernetesClustersCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(DeleteKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(AddVirtualMachinesToKubernetesClusterCmd.class),
|
||||||
|
BaseCmd.getCommandNameByClass(RemoveVirtualMachinesFromKubernetesClusterCmd.class)
|
||||||
|
).contains(cmdName);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateManagedKubernetesClusterCreateParameters(final CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
||||||
validateEndpointUrl();
|
validateEndpointUrl();
|
||||||
final String name = cmd.getName();
|
final String name = cmd.getName();
|
||||||
final Long zoneId = cmd.getZoneId();
|
final Long zoneId = cmd.getZoneId();
|
||||||
@ -619,7 +727,6 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
final String sshKeyPair = cmd.getSSHKeyPairName();
|
final String sshKeyPair = cmd.getSSHKeyPairName();
|
||||||
final Long controlNodeCount = cmd.getControlNodes();
|
final Long controlNodeCount = cmd.getControlNodes();
|
||||||
final Long clusterSize = cmd.getClusterSize();
|
final Long clusterSize = cmd.getClusterSize();
|
||||||
final long totalNodeCount = controlNodeCount + clusterSize;
|
|
||||||
final String dockerRegistryUserName = cmd.getDockerRegistryUserName();
|
final String dockerRegistryUserName = cmd.getDockerRegistryUserName();
|
||||||
final String dockerRegistryPassword = cmd.getDockerRegistryPassword();
|
final String dockerRegistryPassword = cmd.getDockerRegistryPassword();
|
||||||
final String dockerRegistryUrl = cmd.getDockerRegistryUrl();
|
final String dockerRegistryUrl = cmd.getDockerRegistryUrl();
|
||||||
@ -627,31 +734,24 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
final String externalLoadBalancerIpAddress = cmd.getExternalLoadBalancerIpAddress();
|
final String externalLoadBalancerIpAddress = cmd.getExternalLoadBalancerIpAddress();
|
||||||
|
|
||||||
if (name == null || name.isEmpty()) {
|
if (name == null || name.isEmpty()) {
|
||||||
throw new InvalidParameterValueException("Invalid name for the Kubernetes cluster name:" + name);
|
throw new InvalidParameterValueException("Invalid name for the Kubernetes cluster name: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controlNodeCount < 1) {
|
if (controlNodeCount < 1) {
|
||||||
throw new InvalidParameterValueException("Invalid cluster control nodes count: " + controlNodeCount);
|
throw new InvalidParameterValueException("Invalid cluster control nodes count: " + controlNodeCount);
|
||||||
}
|
}
|
||||||
|
if (clusterSize == null || clusterSize < 1) {
|
||||||
if (clusterSize < 1) {
|
|
||||||
throw new InvalidParameterValueException("Invalid cluster size: " + clusterSize);
|
throw new InvalidParameterValueException("Invalid cluster size: " + clusterSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxClusterSize = KubernetesMaxClusterSize.valueIn(owner.getId());
|
int maxClusterSize = KubernetesMaxClusterSize.valueIn(owner.getId());
|
||||||
|
final long totalNodeCount = controlNodeCount + clusterSize;
|
||||||
if (totalNodeCount > maxClusterSize) {
|
if (totalNodeCount > maxClusterSize) {
|
||||||
throw new InvalidParameterValueException(
|
throw new InvalidParameterValueException(
|
||||||
String.format("Maximum cluster size can not exceed %d. Please contact your administrator", maxClusterSize));
|
String.format("Maximum cluster size can not exceed %d. Please contact your administrator", maxClusterSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
DataCenter zone = dataCenterDao.findById(zoneId);
|
DataCenter zone = validateAndGetZoneForKubernetesCreateParameters(zoneId);
|
||||||
if (zone == null) {
|
|
||||||
throw new InvalidParameterValueException("Unable to find zone by ID: " + zoneId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Grouping.AllocationState.Disabled == zone.getAllocationState()) {
|
|
||||||
throw new PermissionDeniedException(String.format("Cannot perform this operation, zone ID: %s is currently disabled", zone.getUuid()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isKubernetesServiceConfigured(zone)) {
|
if (!isKubernetesServiceConfigured(zone)) {
|
||||||
throw new CloudRuntimeException("Kubernetes service has not been configured properly to provision Kubernetes clusters");
|
throw new CloudRuntimeException("Kubernetes service has not been configured properly to provision Kubernetes clusters");
|
||||||
@ -694,12 +794,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
throw new InvalidParameterValueException("No service offering with ID: " + serviceOfferingId);
|
throw new InvalidParameterValueException("No service offering with ID: " + serviceOfferingId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sshKeyPair != null && !sshKeyPair.isEmpty()) {
|
validateSshKeyPairForKubernetesCreateParameters(sshKeyPair, owner);
|
||||||
SSHKeyPairVO sshKeyPairVO = sshKeyPairDao.findByName(owner.getAccountId(), owner.getDomainId(), sshKeyPair);
|
|
||||||
if (sshKeyPairVO == null) {
|
|
||||||
throw new InvalidParameterValueException(String.format("Given SSH key pair with name: %s was not found for the account %s", sshKeyPair, owner.getAccountName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodeRootDiskSize != null && nodeRootDiskSize <= 0) {
|
if (nodeRootDiskSize != null && nodeRootDiskSize <= 0) {
|
||||||
throw new InvalidParameterValueException(String.format("Invalid value for %s", ApiConstants.NODE_ROOT_DISK_SIZE));
|
throw new InvalidParameterValueException(String.format("Invalid value for %s", ApiConstants.NODE_ROOT_DISK_SIZE));
|
||||||
@ -711,13 +806,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
|
|
||||||
validateDockerRegistryParams(dockerRegistryUserName, dockerRegistryPassword, dockerRegistryUrl);
|
validateDockerRegistryParams(dockerRegistryUserName, dockerRegistryPassword, dockerRegistryUrl);
|
||||||
|
|
||||||
Network network = null;
|
Network network = validateAndGetNetworkForKubernetesCreateParameters(networkId);
|
||||||
if (networkId != null) {
|
|
||||||
network = networkService.getNetwork(networkId);
|
|
||||||
if (network == null) {
|
|
||||||
throw new InvalidParameterValueException("Unable to find network with given ID");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(externalLoadBalancerIpAddress)) {
|
if (StringUtils.isNotEmpty(externalLoadBalancerIpAddress)) {
|
||||||
if (!NetUtils.isValidIp4(externalLoadBalancerIpAddress) && !NetUtils.isValidIp6(externalLoadBalancerIpAddress)) {
|
if (!NetUtils.isValidIp4(externalLoadBalancerIpAddress) && !NetUtils.isValidIp6(externalLoadBalancerIpAddress)) {
|
||||||
@ -788,15 +877,16 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
List<KubernetesClusterDetailsVO> details = new ArrayList<>();
|
List<KubernetesClusterDetailsVO> details = new ArrayList<>();
|
||||||
long kubernetesClusterId = kubernetesCluster.getId();
|
long kubernetesClusterId = kubernetesCluster.getId();
|
||||||
|
|
||||||
if (Network.GuestType.Shared.equals(network.getGuestType())) {
|
if ((network != null && Network.GuestType.Shared.equals(network.getGuestType())) || kubernetesCluster.getClusterType() == KubernetesCluster.ClusterType.ExternalManaged) {
|
||||||
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.EXTERNAL_LOAD_BALANCER_IP_ADDRESS, externalLoadBalancerIpAddress, true);
|
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.EXTERNAL_LOAD_BALANCER_IP_ADDRESS, externalLoadBalancerIpAddress, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_USER_NAME, dockerRegistryUserName, true);
|
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_USER_NAME, dockerRegistryUserName, true);
|
||||||
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_PASSWORD, dockerRegistryPassword, false);
|
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_PASSWORD, dockerRegistryPassword, false);
|
||||||
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_URL, dockerRegistryUrl, true);
|
addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_URL, dockerRegistryUrl, true);
|
||||||
|
if (kubernetesCluster.getClusterType() == KubernetesCluster.ClusterType.CloudManaged) {
|
||||||
details.add(new KubernetesClusterDetailsVO(kubernetesClusterId, "networkCleanup", String.valueOf(networkCleanup), true));
|
details.add(new KubernetesClusterDetailsVO(kubernetesClusterId, "networkCleanup", String.valueOf(networkCleanup), true));
|
||||||
|
}
|
||||||
kubernetesClusterDetailsDao.saveDetails(details);
|
kubernetesClusterDetailsDao.saveDetails(details);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -865,6 +955,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
|
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
|
accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
|
||||||
|
if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Scale kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
final KubernetesSupportedVersion clusterVersion = kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
|
final KubernetesSupportedVersion clusterVersion = kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
|
||||||
if (clusterVersion == null) {
|
if (clusterVersion == null) {
|
||||||
@ -973,6 +1066,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
if (kubernetesCluster == null || kubernetesCluster.getRemoved() != null) {
|
if (kubernetesCluster == null || kubernetesCluster.getRemoved() != null) {
|
||||||
throw new InvalidParameterValueException("Invalid Kubernetes cluster ID");
|
throw new InvalidParameterValueException("Invalid Kubernetes cluster ID");
|
||||||
}
|
}
|
||||||
|
if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Upgrade kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
|
||||||
|
}
|
||||||
accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
|
accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
|
||||||
if (!KubernetesCluster.State.Running.equals(kubernetesCluster.getState())) {
|
if (!KubernetesCluster.State.Running.equals(kubernetesCluster.getState())) {
|
||||||
throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s is not in running state", kubernetesCluster.getName()));
|
throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s is not in running state", kubernetesCluster.getName()));
|
||||||
@ -1032,12 +1128,62 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KubernetesCluster createKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
public KubernetesCluster createUnmanagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
||||||
if (!KubernetesServiceEnabled.value()) {
|
if (!KubernetesServiceEnabled.value()) {
|
||||||
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
validateKubernetesClusterCreateParameters(cmd);
|
validateUnmanagedKubernetesClusterCreateParameters(cmd);
|
||||||
|
|
||||||
|
final DataCenter zone = dataCenterDao.findById(cmd.getZoneId());
|
||||||
|
final long controlNodeCount = cmd.getControlNodes();
|
||||||
|
final long clusterSize = Objects.requireNonNullElse(cmd.getClusterSize(), 0L);
|
||||||
|
final ServiceOffering serviceOffering = serviceOfferingDao.findById(cmd.getServiceOfferingId());
|
||||||
|
final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
||||||
|
final KubernetesSupportedVersion clusterKubernetesVersion = kubernetesSupportedVersionDao.findById(cmd.getKubernetesVersionId());
|
||||||
|
|
||||||
|
final Network network = networkDao.findById(cmd.getNetworkId());
|
||||||
|
long cores = 0;
|
||||||
|
long memory = 0;
|
||||||
|
Long serviceOfferingId = null;
|
||||||
|
if (serviceOffering != null) {
|
||||||
|
serviceOfferingId = serviceOffering.getId();
|
||||||
|
cores = serviceOffering.getCpu() * (controlNodeCount + clusterSize);
|
||||||
|
memory = serviceOffering.getRamSize() * (controlNodeCount + clusterSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Long finalServiceOfferingId = serviceOfferingId;
|
||||||
|
final Long defaultNetworkId = network == null ? null : network.getId();
|
||||||
|
final Long clusterKubernetesVersionId = clusterKubernetesVersion == null ? null : clusterKubernetesVersion.getId();
|
||||||
|
final long finalCores = cores;
|
||||||
|
final long finalMemory = memory;
|
||||||
|
final KubernetesClusterVO cluster = Transaction.execute(new TransactionCallback<KubernetesClusterVO>() {
|
||||||
|
@Override
|
||||||
|
public KubernetesClusterVO doInTransaction(TransactionStatus status) {
|
||||||
|
KubernetesClusterVO newCluster = new KubernetesClusterVO(cmd.getName(), cmd.getDisplayName(), zone.getId(), clusterKubernetesVersionId,
|
||||||
|
finalServiceOfferingId, null, defaultNetworkId, owner.getDomainId(),
|
||||||
|
owner.getAccountId(), controlNodeCount, clusterSize, KubernetesCluster.State.Running, cmd.getSSHKeyPairName(), finalCores, finalMemory,
|
||||||
|
cmd.getNodeRootDiskSize(), "", KubernetesCluster.ClusterType.ExternalManaged);
|
||||||
|
kubernetesClusterDao.persist(newCluster);
|
||||||
|
return newCluster;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addKubernetesClusterDetails(cluster, network, cmd);
|
||||||
|
|
||||||
|
if (LOGGER.isInfoEnabled()) {
|
||||||
|
LOGGER.info(String.format("Kubernetes cluster with name: %s and ID: %s has been created", cluster.getName(), cluster.getUuid()));
|
||||||
|
}
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KubernetesCluster createManagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
||||||
|
if (!KubernetesServiceEnabled.value()) {
|
||||||
|
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
validateManagedKubernetesClusterCreateParameters(cmd);
|
||||||
|
|
||||||
final DataCenter zone = dataCenterDao.findById(cmd.getZoneId());
|
final DataCenter zone = dataCenterDao.findById(cmd.getZoneId());
|
||||||
final long controlNodeCount = cmd.getControlNodes();
|
final long controlNodeCount = cmd.getControlNodes();
|
||||||
@ -1086,7 +1232,8 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
public KubernetesClusterVO doInTransaction(TransactionStatus status) {
|
public KubernetesClusterVO doInTransaction(TransactionStatus status) {
|
||||||
KubernetesClusterVO newCluster = new KubernetesClusterVO(cmd.getName(), cmd.getDisplayName(), zone.getId(), clusterKubernetesVersion.getId(),
|
KubernetesClusterVO newCluster = new KubernetesClusterVO(cmd.getName(), cmd.getDisplayName(), zone.getId(), clusterKubernetesVersion.getId(),
|
||||||
serviceOffering.getId(), finalTemplate.getId(), defaultNetwork.getId(), owner.getDomainId(),
|
serviceOffering.getId(), finalTemplate.getId(), defaultNetwork.getId(), owner.getDomainId(),
|
||||||
owner.getAccountId(), controlNodeCount, clusterSize, KubernetesCluster.State.Created, cmd.getSSHKeyPairName(), cores, memory, cmd.getNodeRootDiskSize(), "");
|
owner.getAccountId(), controlNodeCount, clusterSize, KubernetesCluster.State.Created, cmd.getSSHKeyPairName(), cores, memory,
|
||||||
|
cmd.getNodeRootDiskSize(), "", KubernetesCluster.ClusterType.CloudManaged);
|
||||||
if (zone.isSecurityGroupEnabled()) {
|
if (zone.isSecurityGroupEnabled()) {
|
||||||
newCluster.setSecurityGroupId(finalSecurityGroupVO.getId());
|
newCluster.setSecurityGroupId(finalSecurityGroupVO.getId());
|
||||||
}
|
}
|
||||||
@ -1183,7 +1330,8 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean stopKubernetesCluster(long kubernetesClusterId) throws CloudRuntimeException {
|
public boolean stopKubernetesCluster(StopKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
||||||
|
long kubernetesClusterId = cmd.getId();
|
||||||
if (!KubernetesServiceEnabled.value()) {
|
if (!KubernetesServiceEnabled.value()) {
|
||||||
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
||||||
}
|
}
|
||||||
@ -1191,6 +1339,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
if (kubernetesCluster == null) {
|
if (kubernetesCluster == null) {
|
||||||
throw new InvalidParameterValueException("Failed to find Kubernetes cluster with given ID");
|
throw new InvalidParameterValueException("Failed to find Kubernetes cluster with given ID");
|
||||||
}
|
}
|
||||||
|
if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Stop kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
|
||||||
|
}
|
||||||
if (kubernetesCluster.getRemoved() != null) {
|
if (kubernetesCluster.getRemoved() != null) {
|
||||||
throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s is already deleted", kubernetesCluster.getName()));
|
throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s is already deleted", kubernetesCluster.getName()));
|
||||||
}
|
}
|
||||||
@ -1213,18 +1364,51 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteKubernetesCluster(Long kubernetesClusterId) throws CloudRuntimeException {
|
public boolean deleteKubernetesCluster(DeleteKubernetesClusterCmd cmd) throws CloudRuntimeException {
|
||||||
if (!KubernetesServiceEnabled.value()) {
|
if (!KubernetesServiceEnabled.value()) {
|
||||||
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
||||||
}
|
}
|
||||||
|
Long kubernetesClusterId = cmd.getId();
|
||||||
KubernetesClusterVO cluster = kubernetesClusterDao.findById(kubernetesClusterId);
|
KubernetesClusterVO cluster = kubernetesClusterDao.findById(kubernetesClusterId);
|
||||||
if (cluster == null) {
|
if (cluster == null) {
|
||||||
throw new InvalidParameterValueException("Invalid cluster id specified");
|
throw new InvalidParameterValueException("Invalid cluster id specified");
|
||||||
}
|
}
|
||||||
accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, cluster);
|
accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, cluster);
|
||||||
KubernetesClusterDestroyWorker destroyWorker = new KubernetesClusterDestroyWorker(cluster, this);
|
if (cluster.getClusterType() == KubernetesCluster.ClusterType.CloudManaged) {
|
||||||
destroyWorker = ComponentContext.inject(destroyWorker);
|
KubernetesClusterDestroyWorker destroyWorker = new KubernetesClusterDestroyWorker(cluster, this);
|
||||||
return destroyWorker.destroy();
|
destroyWorker = ComponentContext.inject(destroyWorker);
|
||||||
|
return destroyWorker.destroy();
|
||||||
|
} else {
|
||||||
|
boolean cleanup = cmd.getCleanup();
|
||||||
|
boolean expunge = cmd.getExpunge();
|
||||||
|
if (cleanup || expunge) {
|
||||||
|
CallContext ctx = CallContext.current();
|
||||||
|
|
||||||
|
if (expunge && !accountManager.isAdmin(ctx.getCallingAccount().getId()) && !AllowUserExpungeRecoverVm.valueIn(cmd.getEntityOwnerId())) {
|
||||||
|
throw new PermissionDeniedException("Parameter " + ApiConstants.EXPUNGE + " can be passed by Admin only. Or when the allow.user.expunge.recover.vm key is set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<KubernetesClusterVmMapVO> vmMapList = kubernetesClusterVmMapDao.listByClusterId(kubernetesClusterId);
|
||||||
|
for (KubernetesClusterVmMapVO vmMap : vmMapList) {
|
||||||
|
try {
|
||||||
|
userVmService.destroyVm(vmMap.getVmId(), expunge);
|
||||||
|
if (expunge) {
|
||||||
|
userVmService.expungeVm(vmMap.getVmId());
|
||||||
|
}
|
||||||
|
} catch (Exception exception) {
|
||||||
|
logMessage(Level.WARN, String.format("Failed to destroy vm %d", vmMap.getVmId()), exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Transaction.execute(new TransactionCallback<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean doInTransaction(TransactionStatus status) {
|
||||||
|
kubernetesClusterDetailsDao.removeDetails(kubernetesClusterId);
|
||||||
|
kubernetesClusterVmMapDao.removeByClusterId(kubernetesClusterId);
|
||||||
|
return kubernetesClusterDao.remove(kubernetesClusterId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1238,6 +1422,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
final String state = cmd.getState();
|
final String state = cmd.getState();
|
||||||
final String name = cmd.getName();
|
final String name = cmd.getName();
|
||||||
final String keyword = cmd.getKeyword();
|
final String keyword = cmd.getKeyword();
|
||||||
|
final String cmdClusterType = cmd.getClusterType();
|
||||||
List<KubernetesClusterResponse> responsesList = new ArrayList<KubernetesClusterResponse>();
|
List<KubernetesClusterResponse> responsesList = new ArrayList<KubernetesClusterResponse>();
|
||||||
List<Long> permittedAccounts = new ArrayList<Long>();
|
List<Long> permittedAccounts = new ArrayList<Long>();
|
||||||
Ternary<Long, Boolean, Project.ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, Project.ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
|
Ternary<Long, Boolean, Project.ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, Project.ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
|
||||||
@ -1245,6 +1430,17 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
Long domainId = domainIdRecursiveListProject.first();
|
Long domainId = domainIdRecursiveListProject.first();
|
||||||
Boolean isRecursive = domainIdRecursiveListProject.second();
|
Boolean isRecursive = domainIdRecursiveListProject.second();
|
||||||
Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
||||||
|
|
||||||
|
KubernetesCluster.ClusterType clusterType = null;
|
||||||
|
|
||||||
|
if (cmdClusterType != null) {
|
||||||
|
try {
|
||||||
|
clusterType = KubernetesCluster.ClusterType.valueOf(cmdClusterType);
|
||||||
|
} catch (IllegalArgumentException exception) {
|
||||||
|
throw new InvalidParameterValueException("Unable to resolve cluster type " + cmdClusterType + " to a supported value (CloudManaged, ExternalManaged)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Filter searchFilter = new Filter(KubernetesClusterVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
|
Filter searchFilter = new Filter(KubernetesClusterVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||||
SearchBuilder<KubernetesClusterVO> sb = kubernetesClusterDao.createSearchBuilder();
|
SearchBuilder<KubernetesClusterVO> sb = kubernetesClusterDao.createSearchBuilder();
|
||||||
accountManager.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
accountManager.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||||
@ -1252,6 +1448,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
|
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
|
||||||
sb.and("keyword", sb.entity().getName(), SearchCriteria.Op.LIKE);
|
sb.and("keyword", sb.entity().getName(), SearchCriteria.Op.LIKE);
|
||||||
sb.and("state", sb.entity().getState(), SearchCriteria.Op.IN);
|
sb.and("state", sb.entity().getState(), SearchCriteria.Op.IN);
|
||||||
|
sb.and("cluster_type", sb.entity().getClusterType(), SearchCriteria.Op.EQ);
|
||||||
SearchCriteria<KubernetesClusterVO> sc = sb.create();
|
SearchCriteria<KubernetesClusterVO> sc = sb.create();
|
||||||
accountManager.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
accountManager.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
@ -1266,6 +1463,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
if (name != null) {
|
if (name != null) {
|
||||||
sc.setParameters("name", name);
|
sc.setParameters("name", name);
|
||||||
}
|
}
|
||||||
|
if (clusterType != null) {
|
||||||
|
sc.setParameters("cluster_type", clusterType);
|
||||||
|
}
|
||||||
List<KubernetesClusterVO> kubernetesClusters = kubernetesClusterDao.search(sc, searchFilter);
|
List<KubernetesClusterVO> kubernetesClusters = kubernetesClusterDao.search(sc, searchFilter);
|
||||||
for (KubernetesClusterVO cluster : kubernetesClusters) {
|
for (KubernetesClusterVO cluster : kubernetesClusters) {
|
||||||
KubernetesClusterResponse clusterResponse = createKubernetesClusterResponse(cluster.getId());
|
KubernetesClusterResponse clusterResponse = createKubernetesClusterResponse(cluster.getId());
|
||||||
@ -1342,6 +1542,114 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
return upgradeWorker.upgradeCluster();
|
return upgradeWorker.upgradeCluster();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateNodeCount(KubernetesClusterVO kubernetesCluster) {
|
||||||
|
List<KubernetesClusterVmMapVO> nodeList = kubernetesClusterVmMapDao.listByClusterId(kubernetesCluster.getId());
|
||||||
|
kubernetesCluster.setControlNodeCount(nodeList.stream().filter(KubernetesClusterVmMapVO::isControlNode).count());
|
||||||
|
kubernetesCluster.setNodeCount(nodeList.size());
|
||||||
|
kubernetesCluster.setNodeCount(nodeList.size());
|
||||||
|
kubernetesClusterDao.persist(kubernetesCluster);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addVmsToCluster(AddVirtualMachinesToKubernetesClusterCmd cmd) {
|
||||||
|
if (!KubernetesServiceEnabled.value()) {
|
||||||
|
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
||||||
|
}
|
||||||
|
List<Long> vmIds = cmd.getVmIds();
|
||||||
|
Long clusterId = cmd.getId();
|
||||||
|
|
||||||
|
KubernetesClusterVO kubernetesCluster = kubernetesClusterDao.findById(clusterId);
|
||||||
|
if (kubernetesCluster == null) {
|
||||||
|
throw new InvalidParameterValueException("Invalid Kubernetes cluster ID specified");
|
||||||
|
}
|
||||||
|
if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
|
||||||
|
throw new InvalidParameterValueException("VM cannot be added to a CloudStack managed Kubernetes cluster");
|
||||||
|
}
|
||||||
|
|
||||||
|
// User should have access to both VM and Kubernetes cluster
|
||||||
|
accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
|
||||||
|
|
||||||
|
for (Long vmId : vmIds) {
|
||||||
|
VMInstanceVO vmInstance = vmInstanceDao.findById(vmId);
|
||||||
|
if (vmInstance == null) {
|
||||||
|
throw new InvalidParameterValueException("Invalid VM ID specified");
|
||||||
|
}
|
||||||
|
accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, vmInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
KubernetesClusterVmMapVO clusterVmMap = null;
|
||||||
|
List<KubernetesClusterVmMapVO> clusterVmMapList = kubernetesClusterVmMapDao.listByClusterIdAndVmIdsIn(clusterId, vmIds);
|
||||||
|
ArrayList<Long> alreadyExistingVmIds = new ArrayList<>();
|
||||||
|
for (KubernetesClusterVmMapVO clusterVmMapVO : clusterVmMapList) {
|
||||||
|
alreadyExistingVmIds.add(clusterVmMapVO.getVmId());
|
||||||
|
}
|
||||||
|
vmIds.removeAll(alreadyExistingVmIds);
|
||||||
|
for (Long vmId : vmIds) {
|
||||||
|
clusterVmMap = new KubernetesClusterVmMapVO(clusterId, vmId, cmd.isControlNode());
|
||||||
|
kubernetesClusterVmMapDao.persist(clusterVmMap);
|
||||||
|
}
|
||||||
|
updateNodeCount(kubernetesCluster);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RemoveVirtualMachinesFromKubernetesClusterResponse> removeVmsFromCluster(RemoveVirtualMachinesFromKubernetesClusterCmd cmd) {
|
||||||
|
if (!KubernetesServiceEnabled.value()) {
|
||||||
|
logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
|
||||||
|
}
|
||||||
|
List<Long> vmIds = cmd.getVmIds();
|
||||||
|
Long clusterId = cmd.getId();
|
||||||
|
|
||||||
|
KubernetesClusterVO kubernetesCluster = kubernetesClusterDao.findById(clusterId);
|
||||||
|
if (kubernetesCluster == null) {
|
||||||
|
throw new InvalidParameterValueException("Invalid Kubernetes cluster ID specified");
|
||||||
|
}
|
||||||
|
if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
|
||||||
|
throw new InvalidParameterValueException("VM cannot be removed from a CloudStack Managed Kubernetes cluster");
|
||||||
|
}
|
||||||
|
accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
|
||||||
|
|
||||||
|
List<KubernetesClusterVmMapVO> kubernetesClusterVmMap = kubernetesClusterVmMapDao.listByClusterIdAndVmIdsIn(clusterId, vmIds);
|
||||||
|
List<RemoveVirtualMachinesFromKubernetesClusterResponse> responseList = new ArrayList<>();
|
||||||
|
|
||||||
|
Set<Long> vmIdsRemoved = new HashSet<>();
|
||||||
|
|
||||||
|
for (KubernetesClusterVmMapVO clusterVmMap : kubernetesClusterVmMap) {
|
||||||
|
RemoveVirtualMachinesFromKubernetesClusterResponse response = new RemoveVirtualMachinesFromKubernetesClusterResponse();
|
||||||
|
UserVm vm = userVmService.getUserVm(clusterVmMap.getVmId());
|
||||||
|
response.setVmId(vm.getUuid());
|
||||||
|
response.setSuccess(kubernetesClusterVmMapDao.remove(clusterVmMap.getId()));
|
||||||
|
response.setObjectName(cmd.getCommandName());
|
||||||
|
responseList.add(response);
|
||||||
|
vmIdsRemoved.add(clusterVmMap.getVmId());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Long vmId : vmIds) {
|
||||||
|
if (!vmIdsRemoved.contains(vmId)) {
|
||||||
|
RemoveVirtualMachinesFromKubernetesClusterResponse response = new RemoveVirtualMachinesFromKubernetesClusterResponse();
|
||||||
|
VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(vmId);
|
||||||
|
if (vm == null) {
|
||||||
|
response.setVmId(vmId.toString());
|
||||||
|
response.setDisplayText("Not a valid vm id");
|
||||||
|
vmIdsRemoved.add(vmId);
|
||||||
|
} else {
|
||||||
|
response.setVmId(vm.getUuid());
|
||||||
|
vmIdsRemoved.add(vmId);
|
||||||
|
if (vm.isRemoved()) {
|
||||||
|
response.setDisplayText("VM is already removed");
|
||||||
|
} else {
|
||||||
|
response.setDisplayText("VM is not part of the cluster");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.setObjectName(cmd.getCommandName());
|
||||||
|
response.setSuccess(false);
|
||||||
|
responseList.add(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateNodeCount(kubernetesCluster);
|
||||||
|
return responseList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Class<?>> getCommands() {
|
public List<Class<?>> getCommands() {
|
||||||
List<Class<?>> cmdList = new ArrayList<Class<?>>();
|
List<Class<?>> cmdList = new ArrayList<Class<?>>();
|
||||||
@ -1356,6 +1664,8 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
cmdList.add(GetKubernetesClusterConfigCmd.class);
|
cmdList.add(GetKubernetesClusterConfigCmd.class);
|
||||||
cmdList.add(ScaleKubernetesClusterCmd.class);
|
cmdList.add(ScaleKubernetesClusterCmd.class);
|
||||||
cmdList.add(UpgradeKubernetesClusterCmd.class);
|
cmdList.add(UpgradeKubernetesClusterCmd.class);
|
||||||
|
cmdList.add(AddVirtualMachinesToKubernetesClusterCmd.class);
|
||||||
|
cmdList.add(RemoveVirtualMachinesFromKubernetesClusterCmd.class);
|
||||||
return cmdList;
|
return cmdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1442,7 +1752,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
public void reallyRun() {
|
public void reallyRun() {
|
||||||
try {
|
try {
|
||||||
// run through Kubernetes clusters in 'Running' state and ensure all the VM's are Running in the cluster
|
// run through Kubernetes clusters in 'Running' state and ensure all the VM's are Running in the cluster
|
||||||
List<KubernetesClusterVO> runningKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Running);
|
List<KubernetesClusterVO> runningKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Running);
|
||||||
for (KubernetesCluster kubernetesCluster : runningKubernetesClusters) {
|
for (KubernetesCluster kubernetesCluster : runningKubernetesClusters) {
|
||||||
if (LOGGER.isInfoEnabled()) {
|
if (LOGGER.isInfoEnabled()) {
|
||||||
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s", kubernetesCluster.getName()));
|
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s", kubernetesCluster.getName()));
|
||||||
@ -1457,7 +1767,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run through Kubernetes clusters in 'Stopped' state and ensure all the VM's are Stopped in the cluster
|
// run through Kubernetes clusters in 'Stopped' state and ensure all the VM's are Stopped in the cluster
|
||||||
List<KubernetesClusterVO> stoppedKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Stopped);
|
List<KubernetesClusterVO> stoppedKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Stopped);
|
||||||
for (KubernetesCluster kubernetesCluster : stoppedKubernetesClusters) {
|
for (KubernetesCluster kubernetesCluster : stoppedKubernetesClusters) {
|
||||||
if (LOGGER.isInfoEnabled()) {
|
if (LOGGER.isInfoEnabled()) {
|
||||||
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Stopped.toString()));
|
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Stopped.toString()));
|
||||||
@ -1472,7 +1782,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run through Kubernetes clusters in 'Alert' state and reconcile state as 'Running' if the VM's are running or 'Stopped' if VM's are stopped
|
// run through Kubernetes clusters in 'Alert' state and reconcile state as 'Running' if the VM's are running or 'Stopped' if VM's are stopped
|
||||||
List<KubernetesClusterVO> alertKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Alert);
|
List<KubernetesClusterVO> alertKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Alert);
|
||||||
for (KubernetesClusterVO kubernetesCluster : alertKubernetesClusters) {
|
for (KubernetesClusterVO kubernetesCluster : alertKubernetesClusters) {
|
||||||
if (LOGGER.isInfoEnabled()) {
|
if (LOGGER.isInfoEnabled()) {
|
||||||
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Alert.toString()));
|
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Alert.toString()));
|
||||||
@ -1495,7 +1805,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
|
|
||||||
if (firstRun) {
|
if (firstRun) {
|
||||||
// run through Kubernetes clusters in 'Starting' state and reconcile state as 'Alert' or 'Error' if the VM's are running
|
// run through Kubernetes clusters in 'Starting' state and reconcile state as 'Alert' or 'Error' if the VM's are running
|
||||||
List<KubernetesClusterVO> startingKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Starting);
|
List<KubernetesClusterVO> startingKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Starting);
|
||||||
for (KubernetesCluster kubernetesCluster : startingKubernetesClusters) {
|
for (KubernetesCluster kubernetesCluster : startingKubernetesClusters) {
|
||||||
if ((new Date()).getTime() - kubernetesCluster.getCreated().getTime() < 10*60*1000) {
|
if ((new Date()).getTime() - kubernetesCluster.getCreated().getTime() < 10*60*1000) {
|
||||||
continue;
|
continue;
|
||||||
@ -1513,7 +1823,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||||||
LOGGER.warn(String.format("Failed to run Kubernetes cluster Starting state scanner on Kubernetes cluster : %s status scanner", kubernetesCluster.getName()), e);
|
LOGGER.warn(String.format("Failed to run Kubernetes cluster Starting state scanner on Kubernetes cluster : %s status scanner", kubernetesCluster.getName()), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<KubernetesClusterVO> destroyingKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Destroying);
|
List<KubernetesClusterVO> destroyingKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Destroying);
|
||||||
for (KubernetesCluster kubernetesCluster : destroyingKubernetesClusters) {
|
for (KubernetesCluster kubernetesCluster : destroyingKubernetesClusters) {
|
||||||
if (LOGGER.isInfoEnabled()) {
|
if (LOGGER.isInfoEnabled()) {
|
||||||
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Destroying.toString()));
|
LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Destroying.toString()));
|
||||||
|
|||||||
@ -16,20 +16,27 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.kubernetes.cluster;
|
package com.cloud.kubernetes.cluster;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.AddVirtualMachinesToKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.DeleteKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.RemoveVirtualMachinesFromKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpgradeKubernetesClusterCmd;
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpgradeKubernetesClusterCmd;
|
||||||
import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
|
import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
|
||||||
import org.apache.cloudstack.api.response.KubernetesClusterResponse;
|
import org.apache.cloudstack.api.response.KubernetesClusterResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
import org.apache.cloudstack.api.response.RemoveVirtualMachinesFromKubernetesClusterResponse;
|
||||||
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 com.cloud.utils.component.PluggableService;
|
import com.cloud.utils.component.PluggableService;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface KubernetesClusterService extends PluggableService, Configurable {
|
public interface KubernetesClusterService extends PluggableService, Configurable {
|
||||||
static final String MIN_KUBERNETES_VERSION_HA_SUPPORT = "1.16.0";
|
static final String MIN_KUBERNETES_VERSION_HA_SUPPORT = "1.16.0";
|
||||||
static final int MIN_KUBERNETES_CLUSTER_NODE_CPU = 2;
|
static final int MIN_KUBERNETES_CLUSTER_NODE_CPU = 2;
|
||||||
@ -81,13 +88,17 @@ public interface KubernetesClusterService extends PluggableService, Configurable
|
|||||||
|
|
||||||
KubernetesCluster findById(final Long id);
|
KubernetesCluster findById(final Long id);
|
||||||
|
|
||||||
KubernetesCluster createKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
KubernetesCluster createUnmanagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
||||||
|
|
||||||
|
KubernetesCluster createManagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
||||||
|
|
||||||
boolean startKubernetesCluster(long kubernetesClusterId, boolean onCreate) throws CloudRuntimeException;
|
boolean startKubernetesCluster(long kubernetesClusterId, boolean onCreate) throws CloudRuntimeException;
|
||||||
|
|
||||||
boolean stopKubernetesCluster(long kubernetesClusterId) throws CloudRuntimeException;
|
boolean stopKubernetesCluster(StopKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
||||||
|
|
||||||
boolean deleteKubernetesCluster(Long kubernetesClusterId) throws CloudRuntimeException;
|
boolean deleteKubernetesCluster(DeleteKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
||||||
|
|
||||||
|
boolean isCommandSupported(KubernetesCluster cluster, String cmdName);
|
||||||
|
|
||||||
ListResponse<KubernetesClusterResponse> listKubernetesClusters(ListKubernetesClustersCmd cmd);
|
ListResponse<KubernetesClusterResponse> listKubernetesClusters(ListKubernetesClustersCmd cmd);
|
||||||
|
|
||||||
@ -98,4 +109,8 @@ public interface KubernetesClusterService extends PluggableService, Configurable
|
|||||||
boolean scaleKubernetesCluster(ScaleKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
boolean scaleKubernetesCluster(ScaleKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
||||||
|
|
||||||
boolean upgradeKubernetesCluster(UpgradeKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
boolean upgradeKubernetesCluster(UpgradeKubernetesClusterCmd cmd) throws CloudRuntimeException;
|
||||||
|
|
||||||
|
boolean addVmsToCluster(AddVirtualMachinesToKubernetesClusterCmd cmd);
|
||||||
|
|
||||||
|
List<RemoveVirtualMachinesFromKubernetesClusterResponse> removeVmsFromCluster(RemoveVirtualMachinesFromKubernetesClusterCmd cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,16 +52,16 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
private long zoneId;
|
private long zoneId;
|
||||||
|
|
||||||
@Column(name = "kubernetes_version_id")
|
@Column(name = "kubernetes_version_id")
|
||||||
private long kubernetesVersionId;
|
private Long kubernetesVersionId;
|
||||||
|
|
||||||
@Column(name = "service_offering_id")
|
@Column(name = "service_offering_id")
|
||||||
private long serviceOfferingId;
|
private Long serviceOfferingId;
|
||||||
|
|
||||||
@Column(name = "template_id")
|
@Column(name = "template_id")
|
||||||
private long templateId;
|
private Long templateId;
|
||||||
|
|
||||||
@Column(name = "network_id")
|
@Column(name = "network_id")
|
||||||
private long networkId;
|
private Long networkId;
|
||||||
|
|
||||||
@Column(name = "domain_id")
|
@Column(name = "domain_id")
|
||||||
private long domainId;
|
private long domainId;
|
||||||
@ -114,6 +114,9 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
@Column(name = "security_group_id")
|
@Column(name = "security_group_id")
|
||||||
private Long securityGroupId;
|
private Long securityGroupId;
|
||||||
|
|
||||||
|
@Column(name = "cluster_type")
|
||||||
|
private ClusterType clusterType;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
@ -160,7 +163,7 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getKubernetesVersionId() {
|
public Long getKubernetesVersionId() {
|
||||||
return kubernetesVersionId;
|
return kubernetesVersionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +172,7 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getServiceOfferingId() {
|
public Long getServiceOfferingId() {
|
||||||
return serviceOfferingId;
|
return serviceOfferingId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +181,7 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getTemplateId() {
|
public Long getTemplateId() {
|
||||||
return templateId;
|
return templateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +190,7 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
return networkId;
|
return networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,13 +353,21 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
return securityGroupId;
|
return securityGroupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClusterType getClusterType() {
|
||||||
|
return clusterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClusterType(ClusterType clusterType) {
|
||||||
|
this.clusterType = clusterType;
|
||||||
|
}
|
||||||
|
|
||||||
public KubernetesClusterVO() {
|
public KubernetesClusterVO() {
|
||||||
this.uuid = UUID.randomUUID().toString();
|
this.uuid = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public KubernetesClusterVO(String name, String description, long zoneId, long kubernetesVersionId, long serviceOfferingId, long templateId,
|
public KubernetesClusterVO(String name, String description, long zoneId, Long kubernetesVersionId, Long serviceOfferingId, Long templateId,
|
||||||
long networkId, long domainId, long accountId, long controlNodeCount, long nodeCount, State state,
|
Long networkId, long domainId, long accountId, long controlNodeCount, long nodeCount, State state,
|
||||||
String keyPair, long cores, long memory, Long nodeRootDiskSize, String endpoint) {
|
String keyPair, long cores, long memory, Long nodeRootDiskSize, String endpoint, ClusterType clusterType) {
|
||||||
this.uuid = UUID.randomUUID().toString();
|
this.uuid = UUID.randomUUID().toString();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
@ -377,14 +388,15 @@ public class KubernetesClusterVO implements KubernetesCluster {
|
|||||||
this.nodeRootDiskSize = nodeRootDiskSize;
|
this.nodeRootDiskSize = nodeRootDiskSize;
|
||||||
}
|
}
|
||||||
this.endpoint = endpoint;
|
this.endpoint = endpoint;
|
||||||
|
this.clusterType = clusterType;
|
||||||
this.checkForGc = false;
|
this.checkForGc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KubernetesClusterVO(String name, String description, long zoneId, long kubernetesVersionId, long serviceOfferingId, long templateId,
|
public KubernetesClusterVO(String name, String description, long zoneId, long kubernetesVersionId, long serviceOfferingId, long templateId,
|
||||||
long networkId, long domainId, long accountId, long controlNodeCount, long nodeCount, State state, String keyPair, long cores,
|
long networkId, long domainId, long accountId, long controlNodeCount, long nodeCount, State state, String keyPair, long cores,
|
||||||
long memory, Long nodeRootDiskSize, String endpoint, boolean autoscalingEnabled, Long minSize, Long maxSize) {
|
long memory, Long nodeRootDiskSize, String endpoint, ClusterType clusterType, boolean autoscalingEnabled, Long minSize, Long maxSize) {
|
||||||
this(name, description, zoneId, kubernetesVersionId, serviceOfferingId, templateId, networkId, domainId, accountId, controlNodeCount,
|
this(name, description, zoneId, kubernetesVersionId, serviceOfferingId, templateId, networkId, domainId, accountId, controlNodeCount,
|
||||||
nodeCount, state, keyPair, cores, memory, nodeRootDiskSize, endpoint);
|
nodeCount, state, keyPair, cores, memory, nodeRootDiskSize, endpoint, clusterType);
|
||||||
this.autoscalingEnabled = autoscalingEnabled;
|
this.autoscalingEnabled = autoscalingEnabled;
|
||||||
this.minSize = minSize;
|
this.minSize = minSize;
|
||||||
this.maxSize = maxSize;
|
this.maxSize = maxSize;
|
||||||
|
|||||||
@ -28,7 +28,7 @@ public interface KubernetesClusterDao extends GenericDao<KubernetesClusterVO, Lo
|
|||||||
|
|
||||||
List<KubernetesClusterVO> listByAccount(long accountId);
|
List<KubernetesClusterVO> listByAccount(long accountId);
|
||||||
List<KubernetesClusterVO> findKubernetesClustersToGarbageCollect();
|
List<KubernetesClusterVO> findKubernetesClustersToGarbageCollect();
|
||||||
List<KubernetesClusterVO> findKubernetesClustersInState(KubernetesCluster.State state);
|
List<KubernetesClusterVO> findManagedKubernetesClustersInState(KubernetesCluster.State state);
|
||||||
List<KubernetesClusterVO> listByNetworkId(long networkId);
|
List<KubernetesClusterVO> listByNetworkId(long networkId);
|
||||||
List<KubernetesClusterVO> listAllByKubernetesVersion(long kubernetesVersionId);
|
List<KubernetesClusterVO> listAllByKubernetesVersion(long kubernetesVersionId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ public class KubernetesClusterDaoImpl extends GenericDaoBase<KubernetesClusterVO
|
|||||||
|
|
||||||
private final SearchBuilder<KubernetesClusterVO> AccountIdSearch;
|
private final SearchBuilder<KubernetesClusterVO> AccountIdSearch;
|
||||||
private final SearchBuilder<KubernetesClusterVO> GarbageCollectedSearch;
|
private final SearchBuilder<KubernetesClusterVO> GarbageCollectedSearch;
|
||||||
private final SearchBuilder<KubernetesClusterVO> StateSearch;
|
private final SearchBuilder<KubernetesClusterVO> ManagedStateSearch;
|
||||||
private final SearchBuilder<KubernetesClusterVO> SameNetworkSearch;
|
private final SearchBuilder<KubernetesClusterVO> SameNetworkSearch;
|
||||||
private final SearchBuilder<KubernetesClusterVO> KubernetesVersionSearch;
|
private final SearchBuilder<KubernetesClusterVO> KubernetesVersionSearch;
|
||||||
|
|
||||||
@ -44,11 +44,13 @@ public class KubernetesClusterDaoImpl extends GenericDaoBase<KubernetesClusterVO
|
|||||||
GarbageCollectedSearch = createSearchBuilder();
|
GarbageCollectedSearch = createSearchBuilder();
|
||||||
GarbageCollectedSearch.and("gc", GarbageCollectedSearch.entity().isCheckForGc(), SearchCriteria.Op.EQ);
|
GarbageCollectedSearch.and("gc", GarbageCollectedSearch.entity().isCheckForGc(), SearchCriteria.Op.EQ);
|
||||||
GarbageCollectedSearch.and("state", GarbageCollectedSearch.entity().getState(), SearchCriteria.Op.EQ);
|
GarbageCollectedSearch.and("state", GarbageCollectedSearch.entity().getState(), SearchCriteria.Op.EQ);
|
||||||
|
GarbageCollectedSearch.and("cluster_type", GarbageCollectedSearch.entity().getClusterType(), SearchCriteria.Op.EQ);
|
||||||
GarbageCollectedSearch.done();
|
GarbageCollectedSearch.done();
|
||||||
|
|
||||||
StateSearch = createSearchBuilder();
|
ManagedStateSearch = createSearchBuilder();
|
||||||
StateSearch.and("state", StateSearch.entity().getState(), SearchCriteria.Op.EQ);
|
ManagedStateSearch.and("state", ManagedStateSearch.entity().getState(), SearchCriteria.Op.EQ);
|
||||||
StateSearch.done();
|
ManagedStateSearch.and("cluster_type", ManagedStateSearch.entity().getClusterType(), SearchCriteria.Op.EQ);
|
||||||
|
ManagedStateSearch.done();
|
||||||
|
|
||||||
SameNetworkSearch = createSearchBuilder();
|
SameNetworkSearch = createSearchBuilder();
|
||||||
SameNetworkSearch.and("network_id", SameNetworkSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
|
SameNetworkSearch.and("network_id", SameNetworkSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
|
||||||
@ -71,13 +73,15 @@ public class KubernetesClusterDaoImpl extends GenericDaoBase<KubernetesClusterVO
|
|||||||
SearchCriteria<KubernetesClusterVO> sc = GarbageCollectedSearch.create();
|
SearchCriteria<KubernetesClusterVO> sc = GarbageCollectedSearch.create();
|
||||||
sc.setParameters("gc", true);
|
sc.setParameters("gc", true);
|
||||||
sc.setParameters("state", KubernetesCluster.State.Destroying);
|
sc.setParameters("state", KubernetesCluster.State.Destroying);
|
||||||
|
sc.setParameters("cluster_type", KubernetesCluster.ClusterType.CloudManaged);
|
||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<KubernetesClusterVO> findKubernetesClustersInState(KubernetesCluster.State state) {
|
public List<KubernetesClusterVO> findManagedKubernetesClustersInState(KubernetesCluster.State state) {
|
||||||
SearchCriteria<KubernetesClusterVO> sc = StateSearch.create();
|
SearchCriteria<KubernetesClusterVO> sc = ManagedStateSearch.create();
|
||||||
sc.setParameters("state", state);
|
sc.setParameters("state", state);
|
||||||
|
sc.setParameters("cluster_type", KubernetesCluster.ClusterType.CloudManaged);
|
||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,4 +24,8 @@ import java.util.List;
|
|||||||
public interface KubernetesClusterVmMapDao extends GenericDao<KubernetesClusterVmMapVO, Long> {
|
public interface KubernetesClusterVmMapDao extends GenericDao<KubernetesClusterVmMapVO, Long> {
|
||||||
public List<KubernetesClusterVmMapVO> listByClusterId(long clusterId);
|
public List<KubernetesClusterVmMapVO> listByClusterId(long clusterId);
|
||||||
public List<KubernetesClusterVmMapVO> listByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
|
public List<KubernetesClusterVmMapVO> listByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
|
||||||
|
|
||||||
|
int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
|
||||||
|
|
||||||
|
public int removeByClusterId(long clusterId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,4 +54,19 @@ public class KubernetesClusterVmMapDaoImpl extends GenericDaoBase<KubernetesClus
|
|||||||
sc.setParameters("vmIdsIN", vmIds.toArray());
|
sc.setParameters("vmIdsIN", vmIds.toArray());
|
||||||
return listBy(sc);
|
return listBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds) {
|
||||||
|
SearchCriteria<KubernetesClusterVmMapVO> sc = clusterIdSearch.create();
|
||||||
|
sc.setParameters("clusterId", clusterId);
|
||||||
|
sc.setParameters("vmIdsIN", vmIds.toArray());
|
||||||
|
return remove(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int removeByClusterId(long clusterId) {
|
||||||
|
SearchCriteria<KubernetesClusterVmMapVO> sc = clusterIdSearch.create();
|
||||||
|
sc.setParameters("clusterId", clusterId);
|
||||||
|
return remove(sc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,106 @@
|
|||||||
|
// 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 org.apache.cloudstack.api.command.user.kubernetes.cluster;
|
||||||
|
|
||||||
|
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.KubernetesClusterResponse;
|
||||||
|
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||||
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@APICommand(name = "addVirtualMachinesToKubernetesCluster",
|
||||||
|
description = "Add VMs to an ExternalManaged kubernetes cluster. Not applicable for CloudManaged kubernetes clusters.",
|
||||||
|
responseObject = SuccessResponse.class,
|
||||||
|
since = "4.19.0",
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||||
|
public class AddVirtualMachinesToKubernetesClusterCmd extends BaseCmd {
|
||||||
|
public static final Logger LOGGER = Logger.getLogger(AddVirtualMachinesToKubernetesClusterCmd.class.getName());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public KubernetesClusterService kubernetesClusterService;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ID, type = CommandType.UUID,
|
||||||
|
entityType = KubernetesClusterResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "the ID of the Kubernetes cluster")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_IDS, type = CommandType.LIST,
|
||||||
|
collectionType=CommandType.UUID,
|
||||||
|
entityType = UserVmResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "the IDs of the VMs to add to the cluster")
|
||||||
|
private List<Long> vmIds;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_CONTROL_NODE, type = CommandType.BOOLEAN,
|
||||||
|
description = "Is control node or not? Defaults to false.")
|
||||||
|
private Boolean isControlNode;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getVmIds() {
|
||||||
|
return vmIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isControlNode() {
|
||||||
|
return (isControlNode != null) && isControlNode;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
return CallContext.current().getCallingAccount().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws ServerApiException {
|
||||||
|
try {
|
||||||
|
if (!kubernetesClusterService.addVmsToCluster(this)) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add VMs to cluster");
|
||||||
|
}
|
||||||
|
final SuccessResponse response = new SuccessResponse();
|
||||||
|
response.setResponseName(getCommandName());
|
||||||
|
setResponseObject(response);
|
||||||
|
} catch (CloudRuntimeException e) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@ import java.security.InvalidParameterException;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||||
import org.apache.cloudstack.api.ACL;
|
import org.apache.cloudstack.api.ACL;
|
||||||
@ -77,13 +78,13 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||||||
description = "availability zone in which Kubernetes cluster to be launched")
|
description = "availability zone in which Kubernetes cluster to be launched")
|
||||||
private Long zoneId;
|
private Long zoneId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.KUBERNETES_VERSION_ID, type = CommandType.UUID, entityType = KubernetesSupportedVersionResponse.class, required = true,
|
@Parameter(name = ApiConstants.KUBERNETES_VERSION_ID, type = CommandType.UUID, entityType = KubernetesSupportedVersionResponse.class,
|
||||||
description = "Kubernetes version with which cluster to be launched")
|
description = "Kubernetes version with which cluster to be launched")
|
||||||
private Long kubernetesVersionId;
|
private Long kubernetesVersionId;
|
||||||
|
|
||||||
@ACL(accessType = AccessType.UseEntry)
|
@ACL(accessType = AccessType.UseEntry)
|
||||||
@Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class,
|
@Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class,
|
||||||
required = true, description = "the ID of the service offering for the virtual machines in the cluster.")
|
description = "the ID of the service offering for the virtual machines in the cluster.")
|
||||||
private Long serviceOfferingId;
|
private Long serviceOfferingId;
|
||||||
|
|
||||||
@ACL(accessType = AccessType.UseEntry)
|
@ACL(accessType = AccessType.UseEntry)
|
||||||
@ -125,7 +126,7 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||||||
private String externalLoadBalancerIpAddress;
|
private String externalLoadBalancerIpAddress;
|
||||||
|
|
||||||
@Parameter(name=ApiConstants.SIZE, type = CommandType.LONG,
|
@Parameter(name=ApiConstants.SIZE, type = CommandType.LONG,
|
||||||
required = true, description = "number of Kubernetes cluster worker nodes")
|
description = "number of Kubernetes cluster worker nodes")
|
||||||
private Long clusterSize;
|
private Long clusterSize;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DOCKER_REGISTRY_USER_NAME, type = CommandType.STRING,
|
@Parameter(name = ApiConstants.DOCKER_REGISTRY_USER_NAME, type = CommandType.STRING,
|
||||||
@ -144,6 +145,9 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||||||
description = "root disk size in GB for each node")
|
description = "root disk size in GB for each node")
|
||||||
private Long nodeRootDiskSize;
|
private Long nodeRootDiskSize;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CLUSTER_TYPE, type = CommandType.STRING, required = true, description = "type of the cluster: CloudManaged, ExternalManaged", since="4.19.0")
|
||||||
|
private String clusterType;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -233,6 +237,13 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getClusterType() {
|
||||||
|
if (clusterType == null) {
|
||||||
|
return KubernetesCluster.ClusterType.CloudManaged.toString();
|
||||||
|
}
|
||||||
|
return clusterType;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -279,7 +290,8 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
try {
|
try {
|
||||||
if (!kubernetesClusterService.startKubernetesCluster(getEntityId(), true)) {
|
if (KubernetesCluster.ClusterType.valueOf(getClusterType()) == KubernetesCluster.ClusterType.CloudManaged
|
||||||
|
&& !kubernetesClusterService.startKubernetesCluster(getEntityId(), true)) {
|
||||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to start Kubernetes cluster");
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to start Kubernetes cluster");
|
||||||
}
|
}
|
||||||
KubernetesClusterResponse response = kubernetesClusterService.createKubernetesClusterResponse(getEntityId());
|
KubernetesClusterResponse response = kubernetesClusterService.createKubernetesClusterResponse(getEntityId());
|
||||||
@ -292,8 +304,20 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create() throws CloudRuntimeException {
|
public void create() throws CloudRuntimeException {
|
||||||
|
KubernetesCluster cluster;
|
||||||
|
KubernetesCluster.ClusterType type;
|
||||||
try {
|
try {
|
||||||
KubernetesCluster cluster = kubernetesClusterService.createKubernetesCluster(this);
|
type = KubernetesCluster.ClusterType.valueOf(getClusterType());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new InvalidParameterValueException("Unable to resolve cluster type " + getClusterType() + " to a supported value (CloudManaged, ExternalManaged)");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (type == KubernetesCluster.ClusterType.CloudManaged) {
|
||||||
|
cluster = kubernetesClusterService.createManagedKubernetesCluster(this);
|
||||||
|
} else {
|
||||||
|
cluster = kubernetesClusterService.createUnmanagedKubernetesCluster(this);
|
||||||
|
}
|
||||||
if (cluster == null) {
|
if (cluster == null) {
|
||||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Kubernetes cluster");
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Kubernetes cluster");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,18 @@ public class DeleteKubernetesClusterCmd extends BaseAsyncCmd {
|
|||||||
description = "the ID of the Kubernetes cluster")
|
description = "the ID of the Kubernetes cluster")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CLEANUP,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
since = "4.19.0",
|
||||||
|
description = "Destroy attached instances of the ExternalManaged Cluster. Default: false")
|
||||||
|
private Boolean cleanup;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.EXPUNGE,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
since = "4.19.0",
|
||||||
|
description = "Expunge attached instances of the ExternalManaged Cluster. If true, value of cleanup is ignored. Default: false")
|
||||||
|
private Boolean expunge;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -66,6 +78,14 @@ public class DeleteKubernetesClusterCmd extends BaseAsyncCmd {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getCleanup() {
|
||||||
|
return cleanup != null && cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getExpunge() {
|
||||||
|
return expunge != null && expunge;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -73,7 +93,7 @@ public class DeleteKubernetesClusterCmd extends BaseAsyncCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() throws ServerApiException, ConcurrentOperationException {
|
public void execute() throws ServerApiException, ConcurrentOperationException {
|
||||||
try {
|
try {
|
||||||
if (!kubernetesClusterService.deleteKubernetesCluster(id)) {
|
if (!kubernetesClusterService.deleteKubernetesCluster(this)) {
|
||||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to delete Kubernetes cluster ID: %d", getId()));
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to delete Kubernetes cluster ID: %d", getId()));
|
||||||
}
|
}
|
||||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||||
|
|||||||
@ -61,6 +61,10 @@ public class ListKubernetesClustersCmd extends BaseListProjectAndAccountResource
|
|||||||
" (a substring match is made against the parameter value, data for all matching Kubernetes clusters will be returned)")
|
" (a substring match is made against the parameter value, data for all matching Kubernetes clusters will be returned)")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CLUSTER_TYPE, type = CommandType.STRING, since = "4.19.0",
|
||||||
|
description = "type of the cluster: CloudManaged, ExternalManaged")
|
||||||
|
private String clusterType;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -77,6 +81,10 @@ public class ListKubernetesClustersCmd extends BaseListProjectAndAccountResource
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getClusterType() {
|
||||||
|
return clusterType;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -0,0 +1,103 @@
|
|||||||
|
// 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 org.apache.cloudstack.api.command.user.kubernetes.cluster;
|
||||||
|
|
||||||
|
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.BaseListCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.KubernetesClusterResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
import org.apache.cloudstack.api.response.RemoveVirtualMachinesFromKubernetesClusterResponse;
|
||||||
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@APICommand(name = "removeVirtualMachinesFromKubernetesCluster",
|
||||||
|
description = "Remove VMs from an ExternalManaged kubernetes cluster. Not applicable for CloudManaged kubernetes clusters.",
|
||||||
|
responseObject = RemoveVirtualMachinesFromKubernetesClusterResponse.class,
|
||||||
|
since = "4.19.0",
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||||
|
public class RemoveVirtualMachinesFromKubernetesClusterCmd extends BaseListCmd {
|
||||||
|
public static final Logger LOGGER = Logger.getLogger(RemoveVirtualMachinesFromKubernetesClusterCmd.class.getName());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public KubernetesClusterService kubernetesClusterService;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID,
|
||||||
|
entityType = KubernetesClusterResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "the ID of the Kubernetes cluster")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_IDS, type = CommandType.LIST,
|
||||||
|
collectionType=CommandType.UUID,
|
||||||
|
entityType = UserVmResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "the IDs of the VMs to remove from the cluster")
|
||||||
|
private List<Long> vmIds;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getVmIds() {
|
||||||
|
return vmIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
return CallContext.current().getCallingAccount().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws ServerApiException {
|
||||||
|
try {
|
||||||
|
List<RemoveVirtualMachinesFromKubernetesClusterResponse> responseList = kubernetesClusterService.removeVmsFromCluster(this);
|
||||||
|
if (responseList.size() < 1) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Provided VMs are not part of the CKS cluster");
|
||||||
|
}
|
||||||
|
ListResponse<RemoveVirtualMachinesFromKubernetesClusterResponse> listResponse = new ListResponse<>();
|
||||||
|
listResponse.setResponseName(getCommandName());
|
||||||
|
listResponse.setResponses(responseList);
|
||||||
|
setResponseObject(listResponse);
|
||||||
|
} catch (CloudRuntimeException e) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -43,7 +43,7 @@ import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
|||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
@APICommand(name = "scaleKubernetesCluster",
|
@APICommand(name = "scaleKubernetesCluster",
|
||||||
description = "Scales a created, running or stopped Kubernetes cluster",
|
description = "Scales a created, running or stopped CloudManaged Kubernetes cluster",
|
||||||
responseObject = KubernetesClusterResponse.class,
|
responseObject = KubernetesClusterResponse.class,
|
||||||
responseView = ResponseObject.ResponseView.Restricted,
|
responseView = ResponseObject.ResponseView.Restricted,
|
||||||
entityType = {KubernetesCluster.class},
|
entityType = {KubernetesCluster.class},
|
||||||
|
|||||||
@ -36,7 +36,7 @@ import com.cloud.kubernetes.cluster.KubernetesClusterEventTypes;
|
|||||||
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
@APICommand(name = "startKubernetesCluster", description = "Starts a stopped Kubernetes cluster",
|
@APICommand(name = "startKubernetesCluster", description = "Starts a stopped CloudManaged Kubernetes cluster",
|
||||||
responseObject = KubernetesClusterResponse.class,
|
responseObject = KubernetesClusterResponse.class,
|
||||||
responseView = ResponseObject.ResponseView.Restricted,
|
responseView = ResponseObject.ResponseView.Restricted,
|
||||||
entityType = {KubernetesCluster.class},
|
entityType = {KubernetesCluster.class},
|
||||||
@ -99,6 +99,10 @@ public class StartKubernetesClusterCmd extends BaseAsyncCmd {
|
|||||||
if (kubernetesCluster == null) {
|
if (kubernetesCluster == null) {
|
||||||
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Given Kubernetes cluster was not found");
|
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Given Kubernetes cluster was not found");
|
||||||
}
|
}
|
||||||
|
if (!kubernetesClusterService.isCommandSupported(kubernetesCluster, getActualCommandName())) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
|
||||||
|
String.format("Start kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
|
||||||
|
}
|
||||||
return kubernetesCluster;
|
return kubernetesCluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import com.cloud.kubernetes.cluster.KubernetesClusterEventTypes;
|
|||||||
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
@APICommand(name = "stopKubernetesCluster", description = "Stops a running Kubernetes cluster",
|
@APICommand(name = "stopKubernetesCluster", description = "Stops a running CloudManaged Kubernetes cluster",
|
||||||
responseObject = SuccessResponse.class,
|
responseObject = SuccessResponse.class,
|
||||||
responseView = ResponseObject.ResponseView.Restricted,
|
responseView = ResponseObject.ResponseView.Restricted,
|
||||||
entityType = {KubernetesCluster.class},
|
entityType = {KubernetesCluster.class},
|
||||||
@ -95,7 +95,7 @@ public class StopKubernetesClusterCmd extends BaseAsyncCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() throws ServerApiException, ConcurrentOperationException {
|
public void execute() throws ServerApiException, ConcurrentOperationException {
|
||||||
try {
|
try {
|
||||||
if (!kubernetesClusterService.stopKubernetesCluster(getId())) {
|
if (!kubernetesClusterService.stopKubernetesCluster(this)) {
|
||||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to start Kubernetes cluster ID: %d", getId()));
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to start Kubernetes cluster ID: %d", getId()));
|
||||||
}
|
}
|
||||||
final SuccessResponse response = new SuccessResponse(getCommandName());
|
final SuccessResponse response = new SuccessResponse(getCommandName());
|
||||||
|
|||||||
@ -38,7 +38,7 @@ import com.cloud.kubernetes.cluster.KubernetesClusterEventTypes;
|
|||||||
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
import com.cloud.kubernetes.cluster.KubernetesClusterService;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
@APICommand(name = "upgradeKubernetesCluster", description = "Upgrades a running Kubernetes cluster",
|
@APICommand(name = "upgradeKubernetesCluster", description = "Upgrades a running CloudManaged Kubernetes cluster",
|
||||||
responseObject = KubernetesClusterResponse.class,
|
responseObject = KubernetesClusterResponse.class,
|
||||||
responseView = ResponseObject.ResponseView.Restricted,
|
responseView = ResponseObject.ResponseView.Restricted,
|
||||||
entityType = {KubernetesCluster.class},
|
entityType = {KubernetesCluster.class},
|
||||||
|
|||||||
@ -159,6 +159,10 @@ public class KubernetesClusterResponse extends BaseResponseWithAnnotations imple
|
|||||||
@Param(description = "Maximum size of the cluster")
|
@Param(description = "Maximum size of the cluster")
|
||||||
private Long maxSize;
|
private Long maxSize;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.CLUSTER_TYPE)
|
||||||
|
@Param(description = "the type of the cluster")
|
||||||
|
private KubernetesCluster.ClusterType clusterType;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.CREATED)
|
@SerializedName(ApiConstants.CREATED)
|
||||||
@Param(description = "the date when this Kubernetes cluster was created")
|
@Param(description = "the date when this Kubernetes cluster was created")
|
||||||
private Date created;
|
private Date created;
|
||||||
@ -386,4 +390,12 @@ public class KubernetesClusterResponse extends BaseResponseWithAnnotations imple
|
|||||||
public void setCreated(Date created) {
|
public void setCreated(Date created) {
|
||||||
this.created = created;
|
this.created = created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KubernetesCluster.ClusterType getClusterType() {
|
||||||
|
return clusterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClusterType(KubernetesCluster.ClusterType clusterType) {
|
||||||
|
this.clusterType = clusterType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
// 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 org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import com.cloud.serializer.Param;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
|
||||||
|
public class RemoveVirtualMachinesFromKubernetesClusterResponse extends SuccessResponse {
|
||||||
|
@SerializedName(ApiConstants.ID)
|
||||||
|
@Param(description = "the id of the Kubernetes cluster")
|
||||||
|
private String vmId;
|
||||||
|
|
||||||
|
public RemoveVirtualMachinesFromKubernetesClusterResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVmId(String vmId) {
|
||||||
|
this.vmId = vmId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +1,52 @@
|
|||||||
// Licensed to the Apache Software Foundation (ASF) under one
|
/*
|
||||||
// or more contributor license agreements. See the NOTICE file
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
// distributed with this work for additional information
|
* or more contributor license agreements. See the NOTICE file
|
||||||
// regarding copyright ownership. The ASF licenses this file
|
* distributed with this work for additional information
|
||||||
// to you under the Apache License, Version 2.0 (the
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
// "License"); you may not use this file except in compliance
|
* to you under the Apache License, Version 2.0 (the
|
||||||
// with the License. You may obtain a copy of the License at
|
* "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
|
*
|
||||||
//
|
* 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
|
* Unless required by applicable law or agreed to in writing,
|
||||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* software distributed under the License is distributed on an
|
||||||
// KIND, either express or implied. See the License for the
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
// specific language governing permissions and limitations
|
* KIND, either express or implied. See the License for the
|
||||||
// under the License.
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.cloud.kubernetes.cluster;
|
package com.cloud.kubernetes.cluster;
|
||||||
|
|
||||||
|
import com.cloud.api.query.dao.TemplateJoinDao;
|
||||||
import java.util.ArrayList;
|
import com.cloud.api.query.vo.TemplateJoinVO;
|
||||||
import java.util.List;
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.exception.PermissionDeniedException;
|
||||||
|
import com.cloud.kubernetes.cluster.actionworkers.KubernetesClusterActionWorker;
|
||||||
|
import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
|
||||||
|
import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.dao.FirewallRulesDao;
|
||||||
|
import com.cloud.network.rules.FirewallRule;
|
||||||
|
import com.cloud.network.rules.FirewallRuleVO;
|
||||||
|
import com.cloud.network.vpc.NetworkACL;
|
||||||
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.user.AccountManager;
|
||||||
|
import com.cloud.user.User;
|
||||||
|
import com.cloud.vm.VMInstanceVO;
|
||||||
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.AddVirtualMachinesToKubernetesClusterCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.kubernetes.cluster.RemoveVirtualMachinesFromKubernetesClusterCmd;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
@ -28,19 +55,11 @@ import org.mockito.Mockito;
|
|||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import com.cloud.api.query.dao.TemplateJoinDao;
|
import java.lang.reflect.Field;
|
||||||
import com.cloud.api.query.vo.TemplateJoinVO;
|
import java.util.ArrayList;
|
||||||
import com.cloud.dc.DataCenter;
|
import java.util.Arrays;
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import java.util.Collections;
|
||||||
import com.cloud.exception.PermissionDeniedException;
|
import java.util.List;
|
||||||
import com.cloud.kubernetes.cluster.actionworkers.KubernetesClusterActionWorker;
|
|
||||||
import com.cloud.network.Network;
|
|
||||||
import com.cloud.network.dao.FirewallRulesDao;
|
|
||||||
import com.cloud.network.rules.FirewallRule;
|
|
||||||
import com.cloud.network.rules.FirewallRuleVO;
|
|
||||||
import com.cloud.network.vpc.NetworkACL;
|
|
||||||
import com.cloud.storage.VMTemplateVO;
|
|
||||||
import com.cloud.storage.dao.VMTemplateDao;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class KubernetesClusterManagerImplTest {
|
public class KubernetesClusterManagerImplTest {
|
||||||
@ -54,6 +73,18 @@ public class KubernetesClusterManagerImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
TemplateJoinDao templateJoinDao;
|
TemplateJoinDao templateJoinDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
KubernetesClusterDao kubernetesClusterDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
KubernetesClusterVmMapDao kubernetesClusterVmMapDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VMInstanceDao vmInstanceDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AccountManager accountManager;
|
||||||
|
|
||||||
@Spy
|
@Spy
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
KubernetesClusterManagerImpl kubernetesClusterManager;
|
KubernetesClusterManagerImpl kubernetesClusterManager;
|
||||||
@ -171,7 +202,7 @@ public class KubernetesClusterManagerImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateKubernetesClusterScaleSizeDownsacaleNoError() {
|
public void testValidateKubernetesClusterScaleSizeDownscaleNoError() {
|
||||||
KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
|
KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
|
||||||
Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
|
Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
|
||||||
Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
|
Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
|
||||||
@ -209,5 +240,56 @@ public class KubernetesClusterManagerImplTest {
|
|||||||
Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(VMTemplateVO.class));
|
Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(VMTemplateVO.class));
|
||||||
Mockito.when(templateJoinDao.newTemplateView(Mockito.any(VMTemplateVO.class), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(List.of(Mockito.mock(TemplateJoinVO.class)));
|
Mockito.when(templateJoinDao.newTemplateView(Mockito.any(VMTemplateVO.class), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(List.of(Mockito.mock(TemplateJoinVO.class)));
|
||||||
kubernetesClusterManager.validateKubernetesClusterScaleSize(clusterVO, 4L, 10, Mockito.mock(DataCenter.class));
|
kubernetesClusterManager.validateKubernetesClusterScaleSize(clusterVO, 4L, 10, Mockito.mock(DataCenter.class));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class));
|
||||||
|
overrideDefaultConfigValue(KubernetesClusterService.KubernetesServiceEnabled, "_defaultValue", "true");
|
||||||
|
Mockito.doNothing().when(accountManager).checkAccess(
|
||||||
|
Mockito.any(Account.class), Mockito.any(), Mockito.anyBoolean(), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
CallContext.unregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void overrideDefaultConfigValue(final ConfigKey configKey, final String name, final Object o) throws IllegalAccessException, NoSuchFieldException {
|
||||||
|
Field f = ConfigKey.class.getDeclaredField(name);
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.set(configKey, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addVmsToCluster() {
|
||||||
|
KubernetesClusterVO cluster = Mockito.mock(KubernetesClusterVO.class);
|
||||||
|
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
|
||||||
|
AddVirtualMachinesToKubernetesClusterCmd cmd = Mockito.mock(AddVirtualMachinesToKubernetesClusterCmd.class);
|
||||||
|
List<Long> vmIds = Arrays.asList(1L, 2L, 3L);
|
||||||
|
|
||||||
|
Mockito.when(cmd.getId()).thenReturn(1L);
|
||||||
|
Mockito.when(cmd.getVmIds()).thenReturn(vmIds);
|
||||||
|
Mockito.when(cmd.getActualCommandName()).thenReturn(BaseCmd.getCommandNameByClass(RemoveVirtualMachinesFromKubernetesClusterCmd.class));
|
||||||
|
Mockito.when(cluster.getClusterType()).thenReturn(KubernetesCluster.ClusterType.ExternalManaged);
|
||||||
|
Mockito.when(vmInstanceDao.findById(Mockito.anyLong())).thenReturn(vm);
|
||||||
|
Mockito.when(kubernetesClusterDao.findById(Mockito.anyLong())).thenReturn(cluster);
|
||||||
|
Mockito.when(kubernetesClusterVmMapDao.listByClusterIdAndVmIdsIn(1L, vmIds)).thenReturn(Collections.emptyList());
|
||||||
|
Assert.assertTrue(kubernetesClusterManager.addVmsToCluster(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeVmsFromCluster() {
|
||||||
|
KubernetesClusterVO cluster = Mockito.mock(KubernetesClusterVO.class);
|
||||||
|
RemoveVirtualMachinesFromKubernetesClusterCmd cmd = Mockito.mock(RemoveVirtualMachinesFromKubernetesClusterCmd.class);
|
||||||
|
List<Long> vmIds = Arrays.asList(1L, 2L, 3L);
|
||||||
|
|
||||||
|
Mockito.when(cmd.getId()).thenReturn(1L);
|
||||||
|
Mockito.when(cmd.getVmIds()).thenReturn(vmIds);
|
||||||
|
Mockito.when(cmd.getActualCommandName()).thenReturn(BaseCmd.getCommandNameByClass(RemoveVirtualMachinesFromKubernetesClusterCmd.class));
|
||||||
|
Mockito.when(cluster.getClusterType()).thenReturn(KubernetesCluster.ClusterType.ExternalManaged);
|
||||||
|
Mockito.when(kubernetesClusterDao.findById(Mockito.anyLong())).thenReturn(cluster);
|
||||||
|
Assert.assertTrue(kubernetesClusterManager.removeVmsFromCluster(cmd).size() > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,9 @@ from marvin.cloudstackAPI import (listInfrastructure,
|
|||||||
scaleKubernetesCluster,
|
scaleKubernetesCluster,
|
||||||
getKubernetesClusterConfig,
|
getKubernetesClusterConfig,
|
||||||
destroyVirtualMachine,
|
destroyVirtualMachine,
|
||||||
deleteNetwork)
|
deleteNetwork,
|
||||||
|
addVirtualMachinesToKubernetesCluster,
|
||||||
|
removeVirtualMachinesFromKubernetesCluster)
|
||||||
from marvin.cloudstackException import CloudstackAPIException
|
from marvin.cloudstackException import CloudstackAPIException
|
||||||
from marvin.codes import PASS, FAILED
|
from marvin.codes import PASS, FAILED
|
||||||
from marvin.lib.base import (Template,
|
from marvin.lib.base import (Template,
|
||||||
@ -46,12 +48,14 @@ from marvin.lib.base import (Template,
|
|||||||
VpcOffering,
|
VpcOffering,
|
||||||
VPC,
|
VPC,
|
||||||
NetworkACLList,
|
NetworkACLList,
|
||||||
NetworkACL)
|
NetworkACL,
|
||||||
|
VirtualMachine)
|
||||||
from marvin.lib.utils import (cleanup_resources,
|
from marvin.lib.utils import (cleanup_resources,
|
||||||
validateList,
|
validateList,
|
||||||
random_gen)
|
random_gen)
|
||||||
from marvin.lib.common import (get_zone,
|
from marvin.lib.common import (get_zone,
|
||||||
get_domain)
|
get_domain,
|
||||||
|
get_template)
|
||||||
from marvin.sshClient import SshClient
|
from marvin.sshClient import SshClient
|
||||||
from nose.plugins.attrib import attr
|
from nose.plugins.attrib import attr
|
||||||
from marvin.lib.decoratorGenerators import skipTestIf
|
from marvin.lib.decoratorGenerators import skipTestIf
|
||||||
@ -86,6 +90,7 @@ class TestKubernetesCluster(cloudstackTestCase):
|
|||||||
cls._cleanup = []
|
cls._cleanup = []
|
||||||
cls.kubernetes_version_ids = []
|
cls.kubernetes_version_ids = []
|
||||||
cls.vpcAllowAllAclDetailsMap = {}
|
cls.vpcAllowAllAclDetailsMap = {}
|
||||||
|
cls.initial_configuration_cks_enabled = None
|
||||||
|
|
||||||
if cls.hypervisorNotSupported == False:
|
if cls.hypervisorNotSupported == False:
|
||||||
cls.endpoint_url = Configurations.list(cls.apiclient, name="endpoint.url")[0].value
|
cls.endpoint_url = Configurations.list(cls.apiclient, name="endpoint.url")[0].value
|
||||||
@ -610,7 +615,82 @@ class TestKubernetesCluster(cloudstackTestCase):
|
|||||||
k8s_cluster = None
|
k8s_cluster = None
|
||||||
return
|
return
|
||||||
|
|
||||||
def createKubernetesCluster(self, name, version_id, size=1, control_nodes=1):
|
@attr(tags=["advanced", "smoke"], required_hardware="false")
|
||||||
|
def test_11_test_unmanaged_cluster_lifecycle(self):
|
||||||
|
"""Test all operations on unmanaged Kubernetes cluster
|
||||||
|
|
||||||
|
# Validate the following:
|
||||||
|
# 1. createKubernetesCluster should return valid info for new cluster
|
||||||
|
# 2. The Cloud Database contains the valid information
|
||||||
|
# 3. stopKubernetesCluster doesn't work
|
||||||
|
# 4. startKubernetesCluster doesn't work
|
||||||
|
# 5. upgradeKubernetesCluster doesn't work
|
||||||
|
# 6. Adding & removing vm from cluster works
|
||||||
|
# 7. deleteKubernetesCluster should delete an existing HA Kubernetes cluster
|
||||||
|
"""
|
||||||
|
cluster = self.createKubernetesCluster("test-unmanaged-cluster", None,
|
||||||
|
cluster_type="ExternalManaged")
|
||||||
|
self.verifyKubernetesClusterState(cluster, 'Running')
|
||||||
|
self.debug("Stopping unmanaged Kubernetes cluster with ID: %s" % cluster.id)
|
||||||
|
try:
|
||||||
|
self.stopKubernetesCluster(cluster.id)
|
||||||
|
self.fail("Should not be able to stop unmanaged cluster")
|
||||||
|
except Exception as e:
|
||||||
|
self.debug("Expected exception: %s" % e)
|
||||||
|
|
||||||
|
self.debug("Starting unmanaged Kubernetes cluster with ID: %s" % cluster.id)
|
||||||
|
try:
|
||||||
|
self.startKubernetesCluster(cluster.id)
|
||||||
|
self.fail("Should not be able to start unmanaged cluster")
|
||||||
|
except Exception as e:
|
||||||
|
self.debug("Expected exception: %s" % e)
|
||||||
|
|
||||||
|
self.debug("Upgrading unmanaged Kubernetes cluster with ID: %s" % cluster.id)
|
||||||
|
try:
|
||||||
|
self.upgradeKubernetesCluster(cluster.id, self.kubernetes_version_1_24_0.id)
|
||||||
|
self.fail("Should not be able to upgrade unmanaged cluster")
|
||||||
|
except Exception as e:
|
||||||
|
self.debug("Expected exception: %s" % e)
|
||||||
|
|
||||||
|
template = get_template(self.apiclient,
|
||||||
|
self.zone.id,
|
||||||
|
self.services["ostype"])
|
||||||
|
|
||||||
|
self.services["virtual_machine"]["template"] = template.id
|
||||||
|
virtualMachine = VirtualMachine.create(self.apiclient, self.services["virtual_machine"], zoneid=self.zone.id,
|
||||||
|
accountid=self.account.name, domainid=self.account.domainid,
|
||||||
|
serviceofferingid=self.cks_service_offering.id)
|
||||||
|
self.debug("Adding VM %s to unmanaged Kubernetes cluster with ID: %s" % (virtualMachine.id, cluster.id))
|
||||||
|
self.addVirtualMachinesToKubernetesCluster(cluster.id, [virtualMachine.id])
|
||||||
|
cluster = self.listKubernetesCluster(cluster.id)
|
||||||
|
self.assertEqual(virtualMachine.id, cluster.virtualmachines[0].id, "VM should be part of the kubernetes cluster")
|
||||||
|
self.assertEqual(1, len(cluster.virtualmachines), "Only one VM should be part of the kubernetes cluster")
|
||||||
|
|
||||||
|
self.debug("Removing VM %s from unmanaged Kubernetes cluster with ID: %s" % (virtualMachine.id, cluster.id))
|
||||||
|
self.removeVirtualMachinesFromKubernetesCluster(cluster.id, [virtualMachine.id])
|
||||||
|
cluster = self.listKubernetesCluster(cluster.id)
|
||||||
|
self.assertEqual(0, len(cluster.virtualmachines), "No VM should be part of the kubernetes cluster")
|
||||||
|
|
||||||
|
self.debug("Deleting unmanaged Kubernetes cluster with ID: %s" % cluster.id)
|
||||||
|
self.deleteKubernetesClusterAndVerify(cluster.id)
|
||||||
|
return
|
||||||
|
|
||||||
|
def addVirtualMachinesToKubernetesCluster(self, cluster_id, vm_list):
|
||||||
|
cmd = addVirtualMachinesToKubernetesCluster.addVirtualMachinesToKubernetesClusterCmd()
|
||||||
|
cmd.id = cluster_id
|
||||||
|
cmd.virtualmachineids = vm_list
|
||||||
|
|
||||||
|
return self.apiclient.addVirtualMachinesToKubernetesCluster(cmd)
|
||||||
|
|
||||||
|
def removeVirtualMachinesFromKubernetesCluster(self, cluster_id, vm_list):
|
||||||
|
cmd = removeVirtualMachinesFromKubernetesCluster.removeVirtualMachinesFromKubernetesClusterCmd()
|
||||||
|
cmd.id = cluster_id
|
||||||
|
cmd.virtualmachineids = vm_list
|
||||||
|
|
||||||
|
return self.apiclient.removeVirtualMachinesFromKubernetesCluster(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def createKubernetesCluster(self, name, version_id, size=1, control_nodes=1, cluster_type='CloudManaged'):
|
||||||
createKubernetesClusterCmd = createKubernetesCluster.createKubernetesClusterCmd()
|
createKubernetesClusterCmd = createKubernetesCluster.createKubernetesClusterCmd()
|
||||||
createKubernetesClusterCmd.name = name
|
createKubernetesClusterCmd.name = name
|
||||||
createKubernetesClusterCmd.description = name + "-description"
|
createKubernetesClusterCmd.description = name + "-description"
|
||||||
@ -622,11 +702,10 @@ class TestKubernetesCluster(cloudstackTestCase):
|
|||||||
createKubernetesClusterCmd.noderootdisksize = 10
|
createKubernetesClusterCmd.noderootdisksize = 10
|
||||||
createKubernetesClusterCmd.account = self.account.name
|
createKubernetesClusterCmd.account = self.account.name
|
||||||
createKubernetesClusterCmd.domainid = self.domain.id
|
createKubernetesClusterCmd.domainid = self.domain.id
|
||||||
|
createKubernetesClusterCmd.clustertype = cluster_type
|
||||||
if self.default_network:
|
if self.default_network:
|
||||||
createKubernetesClusterCmd.networkid = self.default_network.id
|
createKubernetesClusterCmd.networkid = self.default_network.id
|
||||||
clusterResponse = self.apiclient.createKubernetesCluster(createKubernetesClusterCmd)
|
clusterResponse = self.apiclient.createKubernetesCluster(createKubernetesClusterCmd)
|
||||||
if not clusterResponse:
|
|
||||||
self.cleanup.append(clusterResponse)
|
|
||||||
return clusterResponse
|
return clusterResponse
|
||||||
|
|
||||||
def startKubernetesCluster(self, cluster_id):
|
def startKubernetesCluster(self, cluster_id):
|
||||||
|
|||||||
@ -447,6 +447,7 @@
|
|||||||
"label.clear.list": "Clear list",
|
"label.clear.list": "Clear list",
|
||||||
"label.clear.notification": "Clear notification",
|
"label.clear.notification": "Clear notification",
|
||||||
"label.close": "Close",
|
"label.close": "Close",
|
||||||
|
"label.cloud.managed": "CloudManaged",
|
||||||
"label.cloudian.storage": "Cloudian storage",
|
"label.cloudian.storage": "Cloudian storage",
|
||||||
"label.cluster": "Cluster",
|
"label.cluster": "Cluster",
|
||||||
"label.cluster.name": "Cluster name",
|
"label.cluster.name": "Cluster name",
|
||||||
@ -834,6 +835,7 @@
|
|||||||
"label.expunged": "Expunged",
|
"label.expunged": "Expunged",
|
||||||
"label.expunging": "Expunging",
|
"label.expunging": "Expunging",
|
||||||
"label.export.rules": "Export Rules",
|
"label.export.rules": "Export Rules",
|
||||||
|
"label.external.managed": "ExternalManaged",
|
||||||
"label.external.link": "External link",
|
"label.external.link": "External link",
|
||||||
"label.externalid": "External Id",
|
"label.externalid": "External Id",
|
||||||
"label.externalloadbalanceripaddress": "External load balancer IP address.",
|
"label.externalloadbalanceripaddress": "External load balancer IP address.",
|
||||||
@ -2057,6 +2059,7 @@
|
|||||||
"label.unit": "Usage unit",
|
"label.unit": "Usage unit",
|
||||||
"label.unknown": "Unknown",
|
"label.unknown": "Unknown",
|
||||||
"label.unlimited": "Unlimited",
|
"label.unlimited": "Unlimited",
|
||||||
|
"label.unmanaged": "Unmanaged",
|
||||||
"label.unmanage.instance": "Unmanage instance",
|
"label.unmanage.instance": "Unmanage instance",
|
||||||
"label.unmanaged.instance": "Unmanaged instance",
|
"label.unmanaged.instance": "Unmanaged instance",
|
||||||
"label.unmanaged.instances": "Unmanaged instances",
|
"label.unmanaged.instances": "Unmanaged instances",
|
||||||
|
|||||||
@ -92,6 +92,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="record.clustertype === 'ExternalManaged' && $route.path.split('/')[1] === 'kubernetes' && ['cpunumber', 'memory', 'size'].includes(column.key)">
|
||||||
|
<span>{{ text <= 0 ? 'N/A' : text }}</span>
|
||||||
|
</template>
|
||||||
<template v-if="column.key === 'templatetype'">
|
<template v-if="column.key === 'templatetype'">
|
||||||
<router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
|
<router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -447,7 +447,7 @@ export default {
|
|||||||
docHelp: 'plugins/cloudstack-kubernetes-service.html',
|
docHelp: 'plugins/cloudstack-kubernetes-service.html',
|
||||||
permission: ['listKubernetesClusters'],
|
permission: ['listKubernetesClusters'],
|
||||||
columns: (store) => {
|
columns: (store) => {
|
||||||
var fields = ['name', 'state', 'size', 'cpunumber', 'memory']
|
var fields = ['name', 'state', 'clustertype', 'size', 'cpunumber', 'memory']
|
||||||
if (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) {
|
if (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) {
|
||||||
fields.push('account')
|
fields.push('account')
|
||||||
}
|
}
|
||||||
@ -457,7 +457,11 @@ export default {
|
|||||||
fields.push('zonename')
|
fields.push('zonename')
|
||||||
return fields
|
return fields
|
||||||
},
|
},
|
||||||
details: ['name', 'description', 'zonename', 'kubernetesversionname', 'autoscalingenabled', 'minsize', 'maxsize', 'size', 'controlnodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename', 'created'],
|
filters: () => {
|
||||||
|
const filters = ['cloud.managed', 'external.managed']
|
||||||
|
return filters
|
||||||
|
},
|
||||||
|
details: ['name', 'description', 'zonename', 'kubernetesversionname', 'autoscalingenabled', 'minsize', 'maxsize', 'size', 'controlnodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename', 'clustertype', 'created'],
|
||||||
tabs: [{
|
tabs: [{
|
||||||
name: 'k8s',
|
name: 'k8s',
|
||||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/KubernetesServiceTab.vue')))
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/KubernetesServiceTab.vue')))
|
||||||
@ -480,7 +484,7 @@ export default {
|
|||||||
message: 'message.kubernetes.cluster.start',
|
message: 'message.kubernetes.cluster.start',
|
||||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#starting-a-stopped-kubernetes-cluster',
|
docHelp: 'plugins/cloudstack-kubernetes-service.html#starting-a-stopped-kubernetes-cluster',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
show: (record) => { return ['Stopped'].includes(record.state) },
|
show: (record) => { return ['Stopped'].includes(record.state) && record.clustertype === 'CloudManaged' },
|
||||||
groupAction: true,
|
groupAction: true,
|
||||||
popup: true,
|
popup: true,
|
||||||
groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
|
groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
|
||||||
@ -492,7 +496,7 @@ export default {
|
|||||||
message: 'message.kubernetes.cluster.stop',
|
message: 'message.kubernetes.cluster.stop',
|
||||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#stopping-kubernetes-cluster',
|
docHelp: 'plugins/cloudstack-kubernetes-service.html#stopping-kubernetes-cluster',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
show: (record) => { return !['Stopped', 'Destroyed', 'Destroying'].includes(record.state) },
|
show: (record) => { return !['Stopped', 'Destroyed', 'Destroying'].includes(record.state) && record.clustertype === 'CloudManaged' },
|
||||||
groupAction: true,
|
groupAction: true,
|
||||||
popup: true,
|
popup: true,
|
||||||
groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
|
groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
|
||||||
@ -504,7 +508,7 @@ export default {
|
|||||||
message: 'message.kubernetes.cluster.scale',
|
message: 'message.kubernetes.cluster.scale',
|
||||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#scaling-kubernetes-cluster',
|
docHelp: 'plugins/cloudstack-kubernetes-service.html#scaling-kubernetes-cluster',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
show: (record) => { return ['Created', 'Running', 'Stopped'].includes(record.state) },
|
show: (record) => { return ['Created', 'Running', 'Stopped'].includes(record.state) && record.clustertype === 'CloudManaged' },
|
||||||
popup: true,
|
popup: true,
|
||||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ScaleKubernetesCluster.vue')))
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ScaleKubernetesCluster.vue')))
|
||||||
},
|
},
|
||||||
@ -515,7 +519,7 @@ export default {
|
|||||||
message: 'message.kubernetes.cluster.upgrade',
|
message: 'message.kubernetes.cluster.upgrade',
|
||||||
docHelp: 'plugins/cloudstack-kubernetes-service.html#upgrading-kubernetes-cluster',
|
docHelp: 'plugins/cloudstack-kubernetes-service.html#upgrading-kubernetes-cluster',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
show: (record) => { return ['Created', 'Running'].includes(record.state) },
|
show: (record) => { return ['Created', 'Running'].includes(record.state) && record.clustertype === 'CloudManaged' },
|
||||||
popup: true,
|
popup: true,
|
||||||
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/UpgradeKubernetesCluster.vue')))
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/UpgradeKubernetesCluster.vue')))
|
||||||
},
|
},
|
||||||
@ -529,7 +533,11 @@ export default {
|
|||||||
show: (record) => { return !['Destroyed', 'Destroying'].includes(record.state) },
|
show: (record) => { return !['Destroyed', 'Destroying'].includes(record.state) },
|
||||||
groupAction: true,
|
groupAction: true,
|
||||||
popup: true,
|
popup: true,
|
||||||
groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
|
args: (record, store, group) => {
|
||||||
|
return (['Admin'].includes(store.userInfo.roletype) || store.features.allowuserexpungerecovervm)
|
||||||
|
? ['cleanup', 'expunge'] : ['cleanup']
|
||||||
|
},
|
||||||
|
groupMap: (selection, values) => { return selection.map(x => { return { id: x, expunge: values.expunge, cleanup: values.cleanup } }) }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
<template #suffixIcon><filter-outlined class="ant-select-suffix" /></template>
|
<template #suffixIcon><filter-outlined class="ant-select-suffix" /></template>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-if="['Admin', 'DomainAdmin'].includes($store.getters.userInfo.roletype) &&
|
v-if="['Admin', 'DomainAdmin'].includes($store.getters.userInfo.roletype) &&
|
||||||
['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool'].includes($route.name) ||
|
['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool', 'kubernetes'].includes($route.name) ||
|
||||||
['account'].includes($route.name)"
|
['account'].includes($route.name)"
|
||||||
key="all"
|
key="all"
|
||||||
:label="$t('label.all')">
|
:label="$t('label.all')">
|
||||||
@ -676,7 +676,7 @@ export default {
|
|||||||
return this.$route.query.filter
|
return this.$route.query.filter
|
||||||
}
|
}
|
||||||
const routeName = this.$route.name
|
const routeName = this.$route.name
|
||||||
if ((this.projectView && routeName === 'vm') || (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) && ['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool'].includes(routeName)) || ['account', 'guestnetwork', 'guestvlans', 'guestos', 'guestoshypervisormapping'].includes(routeName)) {
|
if ((this.projectView && routeName === 'vm') || (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) && ['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool'].includes(routeName)) || ['account', 'guestnetwork', 'guestvlans', 'guestos', 'guestoshypervisormapping', 'kubernetes'].includes(routeName)) {
|
||||||
return 'all'
|
return 'all'
|
||||||
}
|
}
|
||||||
if (['publicip'].includes(routeName)) {
|
if (['publicip'].includes(routeName)) {
|
||||||
@ -1657,6 +1657,12 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
query.hypervisor = filter
|
query.hypervisor = filter
|
||||||
}
|
}
|
||||||
|
} else if (this.$route.name === 'kubernetes') {
|
||||||
|
if (filter === 'all') {
|
||||||
|
delete query.clustertype
|
||||||
|
} else {
|
||||||
|
query.clustertype = filter === 'cloud.managed' ? 'CloudManaged' : 'ExternalManaged'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
query.filter = filter
|
query.filter = filter
|
||||||
query.page = '1'
|
query.page = '1'
|
||||||
|
|||||||
@ -459,7 +459,8 @@ export default {
|
|||||||
zoneid: this.zones[values.zoneid].id,
|
zoneid: this.zones[values.zoneid].id,
|
||||||
kubernetesversionid: this.kubernetesVersions[values.kubernetesversionid].id,
|
kubernetesversionid: this.kubernetesVersions[values.kubernetesversionid].id,
|
||||||
serviceofferingid: this.serviceOfferings[values.serviceofferingid].id,
|
serviceofferingid: this.serviceOfferings[values.serviceofferingid].id,
|
||||||
size: values.size
|
size: values.size,
|
||||||
|
clustertype: 'CloudManaged'
|
||||||
}
|
}
|
||||||
if (this.isValidValueForKey(values, 'noderootdisksize') && values.noderootdisksize > 0) {
|
if (this.isValidValueForKey(values, 'noderootdisksize') && values.noderootdisksize > 0) {
|
||||||
params.noderootdisksize = values.noderootdisksize
|
params.noderootdisksize = values.noderootdisksize
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
<a-tab-pane :tab="$t('label.details')" key="details">
|
<a-tab-pane :tab="$t('label.details')" key="details">
|
||||||
<DetailsTab :resource="resource" :loading="loading" />
|
<DetailsTab :resource="resource" :loading="loading" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane :tab="$t('label.access')" key="access">
|
<a-tab-pane v-if="resource.clustertype == 'CloudManaged'" :tab="$t('label.access')" key="access">
|
||||||
<a-card :title="$t('label.kubeconfig.cluster')" :loading="versionLoading">
|
<a-card :title="$t('label.kubeconfig.cluster')" :loading="versionLoading">
|
||||||
<div v-if="clusterConfig !== ''">
|
<div v-if="clusterConfig !== ''">
|
||||||
<a-textarea :value="clusterConfig" :rows="5" readonly />
|
<a-textarea :value="clusterConfig" :rows="5" readonly />
|
||||||
@ -240,6 +240,9 @@ export default {
|
|||||||
if (!isAdmin()) {
|
if (!isAdmin()) {
|
||||||
this.vmColumns = this.vmColumns.filter(x => x.dataIndex !== 'instancename')
|
this.vmColumns = this.vmColumns.filter(x => x.dataIndex !== 'instancename')
|
||||||
}
|
}
|
||||||
|
if (this.resource.clustertype === 'ExternalManaged') {
|
||||||
|
this.vmColumns = this.vmColumns.filter(x => x.dataIndex !== 'port')
|
||||||
|
}
|
||||||
this.handleFetchData()
|
this.handleFetchData()
|
||||||
const self = this
|
const self = this
|
||||||
window.addEventListener('popstate', function () {
|
window.addEventListener('popstate', function () {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user