mirror of https://github.com/apache/cloudstack.git
Add hypervisor type to CKS cluster creation to fix CKS cluster creation when External hosts added
This commit is contained in:
parent
44991773b9
commit
98389a116d
|
|
@ -558,7 +558,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||
}
|
||||
|
||||
private DeployDestination plan(final long nodesCount, final DataCenter zone, final ServiceOffering offering,
|
||||
final Long domainId, final Long accountId) throws InsufficientServerCapacityException {
|
||||
final Long domainId, final Long accountId, Hypervisor.HypervisorType hypervisorType) throws InsufficientServerCapacityException {
|
||||
final int cpu_requested = offering.getCpu() * offering.getSpeed();
|
||||
final long ram_requested = offering.getRamSize() * 1024L * 1024L;
|
||||
boolean useDedicatedHosts = false;
|
||||
|
|
@ -579,6 +579,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||
if (hosts.isEmpty()) {
|
||||
hosts = resourceManager.listAllHostsInOneZoneByType(Host.Type.Routing, zone.getId());
|
||||
}
|
||||
if (hypervisorType != null) {
|
||||
hosts = hosts.stream().filter(x -> x.getHypervisorType() == hypervisorType).collect(Collectors.toList());
|
||||
}
|
||||
final Map<String, Pair<HostVO, Integer>> hosts_with_resevered_capacity = new ConcurrentHashMap<String, Pair<HostVO, Integer>>();
|
||||
for (HostVO h : hosts) {
|
||||
hosts_with_resevered_capacity.put(h.getUuid(), new Pair<HostVO, Integer>(h, 0));
|
||||
|
|
@ -1412,6 +1415,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||
CONTROL.name(), controlNodeCount, ETCD.name(), etcdNodes);
|
||||
final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
||||
final KubernetesSupportedVersion clusterKubernetesVersion = kubernetesSupportedVersionDao.findById(cmd.getKubernetesVersionId());
|
||||
final Hypervisor.HypervisorType hypervisor = cmd.getHypervisorType();
|
||||
|
||||
Map<String, Long> serviceOfferingNodeTypeMap = cmd.getServiceOfferingNodeTypeMap();
|
||||
Long defaultServiceOfferingId = cmd.getServiceOfferingId();
|
||||
|
|
@ -1424,7 +1428,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||
accountId = account.getId();
|
||||
}
|
||||
}
|
||||
Hypervisor.HypervisorType hypervisorType = getHypervisorTypeAndValidateNodeDeployments(serviceOfferingNodeTypeMap, defaultServiceOfferingId, nodeTypeCount, zone, domainId, accountId);
|
||||
Hypervisor.HypervisorType hypervisorType = getHypervisorTypeAndValidateNodeDeployments(serviceOfferingNodeTypeMap, defaultServiceOfferingId, nodeTypeCount, zone, domainId, accountId, hypervisor);
|
||||
|
||||
SecurityGroup securityGroup = null;
|
||||
if (zone.isSecurityGroupEnabled()) {
|
||||
|
|
@ -1510,8 +1514,9 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||
protected Hypervisor.HypervisorType getHypervisorTypeAndValidateNodeDeployments(Map<String, Long> serviceOfferingNodeTypeMap,
|
||||
Long defaultServiceOfferingId,
|
||||
Map<String, Long> nodeTypeCount,
|
||||
DataCenter zone, Long domainId, Long accountId) {
|
||||
Hypervisor.HypervisorType hypervisorType = null;
|
||||
DataCenter zone, Long domainId, Long accountId,
|
||||
Hypervisor.HypervisorType hypervisorType) {
|
||||
Hypervisor.HypervisorType deploymentHypervisor = null;
|
||||
for (String nodeType : CLUSTER_NODES_TYPES_LIST) {
|
||||
if (!nodeTypeCount.containsKey(nodeType)) {
|
||||
continue;
|
||||
|
|
@ -1524,18 +1529,23 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne
|
|||
(!serviceOfferingNodeTypeMap.containsKey(ETCD.name()) || nodes == 0)) {
|
||||
continue;
|
||||
}
|
||||
DeployDestination deployDestination = plan(nodes, zone, serviceOffering, domainId, accountId);
|
||||
DeployDestination deployDestination = plan(nodes, zone, serviceOffering, domainId, accountId, hypervisorType);
|
||||
if (deployDestination.getCluster() == null) {
|
||||
logAndThrow(Level.ERROR, String.format("Creating Kubernetes cluster failed due to error while finding suitable deployment plan for cluster in zone : %s", zone.getName()));
|
||||
}
|
||||
if (hypervisorType == null) {
|
||||
hypervisorType = deployDestination.getCluster().getHypervisorType();
|
||||
if (deploymentHypervisor == null) {
|
||||
deploymentHypervisor = deployDestination.getCluster().getHypervisorType();
|
||||
if (hypervisorType != deploymentHypervisor) {
|
||||
String msg = String.format("The hypervisor type planned for the CKS cluster deployment %s is different " +
|
||||
"from the selected hypervisor %s", deployDestination.getCluster().getHypervisorType(), hypervisorType);
|
||||
LOGGER.warn(msg);
|
||||
}
|
||||
}
|
||||
} catch (InsufficientCapacityException e) {
|
||||
logAndThrow(Level.ERROR, String.format("Creating Kubernetes cluster failed due to insufficient capacity for %d nodes cluster in zone : %s with service offering : %s", nodes, zone.getName(), serviceOffering.getName()));
|
||||
}
|
||||
}
|
||||
return hypervisorType;
|
||||
return deploymentHypervisor;
|
||||
}
|
||||
|
||||
private SecurityGroup getOrCreateSecurityGroupForAccount(Account owner) {
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
|||
}
|
||||
|
||||
protected DeployDestination plan(final long nodesCount, final DataCenter zone, final ServiceOffering offering,
|
||||
final Long domainId, final Long accountId) throws InsufficientServerCapacityException {
|
||||
final Long domainId, final Long accountId, final Hypervisor.HypervisorType hypervisorType) throws InsufficientServerCapacityException {
|
||||
final int cpu_requested = offering.getCpu() * offering.getSpeed();
|
||||
final long ram_requested = offering.getRamSize() * 1024L * 1024L;
|
||||
boolean useDedicatedHosts = false;
|
||||
|
|
@ -195,6 +195,9 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
|||
if (hosts.isEmpty()) {
|
||||
hosts = resourceManager.listAllHostsInOneZoneByType(Host.Type.Routing, zone.getId());
|
||||
}
|
||||
if (hypervisorType != null) {
|
||||
hosts = hosts.stream().filter(x -> x.getHypervisorType() == hypervisorType).collect(Collectors.toList());
|
||||
}
|
||||
final Map<String, Pair<HostVO, Integer>> hosts_with_resevered_capacity = new ConcurrentHashMap<String, Pair<HostVO, Integer>>();
|
||||
for (HostVO h : hosts) {
|
||||
hosts_with_resevered_capacity.put(h.getUuid(), new Pair<HostVO, Integer>(h, 0));
|
||||
|
|
@ -257,13 +260,13 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
|||
throw new InsufficientServerCapacityException(msg, DataCenter.class, zone.getId());
|
||||
}
|
||||
|
||||
protected DeployDestination plan(Long domainId, Long accountId) throws InsufficientServerCapacityException {
|
||||
protected DeployDestination plan(Long domainId, Long accountId, Hypervisor.HypervisorType hypervisorType) throws InsufficientServerCapacityException {
|
||||
ServiceOffering offering = serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
|
||||
DataCenter zone = dataCenterDao.findById(kubernetesCluster.getZoneId());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Checking deployment destination for Kubernetes cluster : %s in zone : %s", kubernetesCluster.getName(), zone.getName()));
|
||||
}
|
||||
return plan(kubernetesCluster.getTotalNodeCount(), zone, offering, domainId, accountId);
|
||||
return plan(kubernetesCluster.getTotalNodeCount(), zone, offering, domainId, accountId, hypervisorType);
|
||||
}
|
||||
|
||||
protected void resizeNodeVolume(final UserVm vm) throws ManagementServerException {
|
||||
|
|
@ -300,7 +303,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
|||
if (Objects.nonNull(domainId) && !listDedicatedHostsInDomain(domainId).isEmpty()) {
|
||||
DeployDestination dest = null;
|
||||
try {
|
||||
dest = plan(domainId, accountId);
|
||||
dest = plan(domainId, accountId, vm.getHypervisorType());
|
||||
} catch (InsufficientCapacityException e) {
|
||||
logTransitStateAndThrow(Level.ERROR, String.format("Provisioning the cluster failed due to insufficient capacity in the Kubernetes cluster: %s", kubernetesCluster.getUuid()), kubernetesCluster.getId(), KubernetesCluster.Event.CreateFailed, e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import javax.inject.Inject;
|
|||
|
||||
import com.cloud.kubernetes.cluster.KubernetesClusterHelper.KubernetesClusterNodeType;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
|
@ -331,11 +332,12 @@ public class KubernetesClusterScaleWorker extends KubernetesClusterResourceModif
|
|||
}
|
||||
if (newVmRequiredCount > 0) {
|
||||
final DataCenter zone = dataCenterDao.findById(kubernetesCluster.getZoneId());
|
||||
VMTemplateVO clusterTemplate = templateDao.findById(kubernetesCluster.getTemplateId());
|
||||
try {
|
||||
if (originalState.equals(KubernetesCluster.State.Running)) {
|
||||
plan(newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId());
|
||||
plan(newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId(), clusterTemplate.getHypervisorType());
|
||||
} else {
|
||||
plan(kubernetesCluster.getTotalNodeCount() + newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId());
|
||||
plan(kubernetesCluster.getTotalNodeCount() + newVmRequiredCount, zone, clusterServiceOffering, kubernetesCluster.getDomainId(), kubernetesCluster.getAccountId(), clusterTemplate.getHypervisorType());
|
||||
}
|
||||
} catch (InsufficientCapacityException e) {
|
||||
logTransitStateToFailedIfNeededAndThrow(Level.WARN, String.format("Scaling failed for Kubernetes cluster : %s in zone : %s, insufficient capacity", kubernetesCluster.getName(), zone.getName()));
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import java.util.Objects;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import com.cloud.exception.NetworkRuleConflictException;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
import org.apache.cloudstack.framework.ca.Certificate;
|
||||
|
|
@ -685,7 +686,8 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||
stateTransitTo(kubernetesCluster.getId(), KubernetesCluster.Event.StartRequested);
|
||||
DeployDestination dest = null;
|
||||
try {
|
||||
dest = plan(domainId, accountId);
|
||||
VMTemplateVO clusterTemplate = templateDao.findById(kubernetesCluster.getTemplateId());
|
||||
dest = plan(domainId, accountId, clusterTemplate.getHypervisorType());
|
||||
} catch (InsufficientCapacityException e) {
|
||||
logTransitStateAndThrow(Level.ERROR, String.format("Provisioning the cluster failed due to insufficient capacity in the Kubernetes cluster: %s", kubernetesCluster.getUuid()), kubernetesCluster.getId(), KubernetesCluster.Event.CreateFailed, e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import com.cloud.exception.InsufficientCapacityException;
|
|||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ManagementServerException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.kubernetes.cluster.KubernetesClusterHelper;
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
|
|
@ -170,6 +171,9 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||
@Parameter(name = ApiConstants.CLUSTER_TYPE, type = CommandType.STRING, description = "type of the cluster: CloudManaged, ExternalManaged. The default value is CloudManaged.", since="4.19.0")
|
||||
private String clusterType;
|
||||
|
||||
@Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, description = "(optional) the hypervisor on which to deploy the CKS cluster nodes.")
|
||||
private String hypervisor;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -278,6 +282,10 @@ public class CreateKubernetesClusterCmd extends BaseAsyncCreateCmd {
|
|||
return kubernetesClusterHelper.getTemplateNodeTypeMap(templateNodeTypeMap);
|
||||
}
|
||||
|
||||
public Hypervisor.HypervisorType getHypervisorType() {
|
||||
return hypervisor == null ? null : Hypervisor.HypervisorType.getType(hypervisor);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -65,6 +65,25 @@
|
|||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item ref="hypervisor" name="hypervisor">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.hypervisor')" :tooltip="apiParams.hypervisor.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="form.hypervisor"
|
||||
:loading="hypervisorLoading"
|
||||
:placeholder="apiParams.hypervisor.description"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
@change="val => { handleZoneHypervisorChange(val) }">
|
||||
:filterOption="(input, option) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option v-for="(opt, optIndex) in selectedZoneHypervisors" :key="optIndex" :label="opt.name || opt.description">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item name="kubernetesversionid" ref="kubernetesversionid">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.kubernetesversionid')" :tooltip="apiParams.kubernetesversionid.description"/>
|
||||
|
|
@ -386,7 +405,9 @@ export default {
|
|||
keyPairLoading: false,
|
||||
loading: false,
|
||||
templates: [],
|
||||
templateLoading: false
|
||||
templateLoading: false,
|
||||
selectedZoneHypervisors: [],
|
||||
hypervisorLoading: false
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -408,7 +429,8 @@ export default {
|
|||
this.form = reactive({
|
||||
controlnodes: 3,
|
||||
size: 1,
|
||||
noderootdisksize: 8
|
||||
noderootdisksize: 8,
|
||||
hypervisor: null
|
||||
})
|
||||
this.rules = reactive({
|
||||
name: [{ required: true, message: this.$t('message.error.kubecluster.name') }],
|
||||
|
|
@ -483,6 +505,7 @@ export default {
|
|||
this.selectedZone = zone
|
||||
this.fetchKubernetesVersionData()
|
||||
this.fetchNetworkData()
|
||||
this.fetchZoneHypervisors()
|
||||
},
|
||||
fetchKubernetesVersionData () {
|
||||
this.kubernetesVersions = []
|
||||
|
|
@ -595,6 +618,24 @@ export default {
|
|||
}
|
||||
})
|
||||
},
|
||||
fetchZoneHypervisors () {
|
||||
const params = {
|
||||
zoneid: this.selectedZone.id
|
||||
}
|
||||
this.hypervisorLoading = true
|
||||
|
||||
api('listHypervisors', params).then(json => {
|
||||
const listResponse = json.listhypervisorsresponse.hypervisor || []
|
||||
if (listResponse) {
|
||||
this.selectedZoneHypervisors = listResponse
|
||||
}
|
||||
}).finally(() => {
|
||||
this.hypervisorLoading = false
|
||||
})
|
||||
},
|
||||
handleZoneHypervisorChange (index) {
|
||||
this.form.hypervisor = index
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
if (this.loading) return
|
||||
|
|
@ -611,6 +652,9 @@ export default {
|
|||
size: values.size,
|
||||
clustertype: 'CloudManaged'
|
||||
}
|
||||
if (values.hypervisor !== null) {
|
||||
params.hypervisor = this.selectedZoneHypervisors[values.hypervisor].name.toLowerCase()
|
||||
}
|
||||
var advancedOfferings = 0
|
||||
if (this.isValidValueForKey(values, 'advancedmode') && values.advancedmode && this.isValidValueForKey(values, 'controlofferingid') && this.arrayHasItems(this.serviceOfferings) && this.serviceOfferings[values.controlofferingid].id != null) {
|
||||
params['nodeofferings[' + advancedOfferings + '].node'] = 'control'
|
||||
|
|
|
|||
Loading…
Reference in New Issue