From 33c2245c8c33d9d9cbaa70adb64f240ef69787e8 Mon Sep 17 00:00:00 2001 From: "jianjun.xu" <128395511+jianjun159@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:57:44 +0800 Subject: [PATCH] [Feature][dinky-geteway] Feature Obtain job information using the ingress address #3871 (#3887) Co-authored-by: jianjun.xu --- .../org/dinky/gateway/config/K8sConfig.java | 9 + .../KubernetesApplicationGateway.java | 162 +++++++++++++++++- .../ingress/DinkyKubernetesIngress.java | 136 +++++++++++++++ .../utils/DinkyKubernetsConstants.java | 3 + .../gateway/model/ingress/JobDetails.java | 36 ++++ .../model/ingress/JobOverviewInfo.java | 46 +++++ .../model/ingress/JobOverviewTaskInfo.java | 52 ++++++ dinky-web/src/locales/en-US/pages.ts | 6 + dinky-web/src/locales/zh-CN/pages.ts | 6 + .../ConfigurationForm/FlinkK8s/index.tsx | 26 ++- dinky-web/src/types/Studio/data.d.ts | 1 + 11 files changed, 481 insertions(+), 2 deletions(-) create mode 100644 dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/ingress/DinkyKubernetesIngress.java create mode 100644 dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobDetails.java create mode 100644 dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewInfo.java create mode 100644 dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewTaskInfo.java diff --git a/dinky-gateway/src/main/java/org/dinky/gateway/config/K8sConfig.java b/dinky-gateway/src/main/java/org/dinky/gateway/config/K8sConfig.java index e4951e75c3..a5dc20d995 100644 --- a/dinky-gateway/src/main/java/org/dinky/gateway/config/K8sConfig.java +++ b/dinky-gateway/src/main/java/org/dinky/gateway/config/K8sConfig.java @@ -22,6 +22,8 @@ import java.util.HashMap; import java.util.Map; +import com.google.common.collect.Maps; + import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -67,4 +69,11 @@ public class K8sConfig { @ApiModelProperty(value = "KubeConfig", dataType = "String", example = "kubeconfig.yaml", notes = "KubeConfig file") private String kubeConfig; + + @ApiModelProperty( + value = "Ingress configuration", + dataType = "Map", + example = "{\"key1\": \"value1\", \"key2\": \"value2\"}", + notes = "Ingress configuration properties") + private Map ingressConfig = Maps.newHashMap(); } diff --git a/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/KubernetesApplicationGateway.java b/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/KubernetesApplicationGateway.java index 3eb24bc76d..3e96aa2e50 100644 --- a/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/KubernetesApplicationGateway.java +++ b/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/KubernetesApplicationGateway.java @@ -19,6 +19,9 @@ package org.dinky.gateway.kubernetes; +import static org.dinky.gateway.kubernetes.utils.DinkyKubernetsConstants.DINKY_K8S_INGRESS_DOMAIN_KEY; +import static org.dinky.gateway.kubernetes.utils.DinkyKubernetsConstants.DINKY_K8S_INGRESS_ENABLED_KEY; + import org.dinky.assertion.Asserts; import org.dinky.context.FlinkUdfPathContextHolder; import org.dinky.data.enums.GatewayType; @@ -26,10 +29,17 @@ import org.dinky.executor.ClusterDescriptorAdapterImpl; import org.dinky.gateway.config.AppConfig; import org.dinky.gateway.exception.GatewayException; +import org.dinky.gateway.kubernetes.ingress.DinkyKubernetesIngress; import org.dinky.gateway.kubernetes.utils.IgnoreNullRepresenter; +import org.dinky.gateway.kubernetes.utils.K8sClientHelper; +import org.dinky.gateway.model.ingress.JobDetails; +import org.dinky.gateway.model.ingress.JobOverviewInfo; import org.dinky.gateway.result.GatewayResult; import org.dinky.gateway.result.KubernetesResult; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.flink.api.common.JobStatus; import org.apache.flink.client.deployment.ClusterDeploymentException; import org.apache.flink.client.deployment.ClusterSpecification; @@ -45,15 +55,24 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; import org.yaml.snakeyaml.Yaml; +import com.alibaba.fastjson2.JSONObject; + +import cn.hutool.core.date.SystemClock; import cn.hutool.core.text.StrFormatter; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpStatus; +import cn.hutool.http.HttpUtil; import io.fabric8.kubernetes.api.model.ContainerStatus; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.networking.v1.Ingress; import io.fabric8.kubernetes.client.KubernetesClient; import lombok.extern.slf4j.Slf4j; @@ -87,7 +106,23 @@ public GatewayResult submitJar(FlinkUdfPathContextHolder udfPathContextHolder) { Deployment deployment = getK8sClientHelper().createDinkyResource(); - KubernetesResult kubernetesResult = waitForJmAndJobStart(kubernetesClient, deployment, clusterClient); + KubernetesResult kubernetesResult; + + String ingressDomain = checkUseIngress(); + // if ingress is enabled and ingress domain is not empty, create an ingress service + if (StringUtils.isNotEmpty(ingressDomain)) { + K8sClientHelper k8sClientHelper = getK8sClientHelper(); + long ingressStart = SystemClock.now(); + DinkyKubernetesIngress ingress = new DinkyKubernetesIngress(k8sClientHelper); + ingress.configureIngress( + k8sClientHelper.getConfiguration().getString(KubernetesConfigOptions.CLUSTER_ID), + ingressDomain, + k8sClientHelper.getConfiguration().getString(KubernetesConfigOptions.NAMESPACE)); + log.info("Create dinky ingress service success, cost time:{} ms", SystemClock.now() - ingressStart); + kubernetesResult = waitForJmAndJobStartByIngress(kubernetesClient, deployment, clusterClient); + } else { + kubernetesResult = waitForJmAndJobStart(kubernetesClient, deployment, clusterClient); + } kubernetesResult.success(); return kubernetesResult; } catch (Exception ex) { @@ -214,4 +249,129 @@ public KubernetesResult waitForJmAndJobStart( throw new GatewayException( "The number of retries exceeds the limit, check the K8S cluster for more information"); } + + /** + * Waits for the JobManager and the Job to start in Kubernetes by ingress. + * + * @param deployment The deployment in Kubernetes. + * @param clusterClient The ClusterClientProvider object for accessing the Kubernetes cluster. + * @return A KubernetesResult object containing the Kubernetes gateway's Web URL, the Job ID, and the cluster ID. + * @throws InterruptedException if waiting is interrupted. + */ + public KubernetesResult waitForJmAndJobStartByIngress( + KubernetesClient kubernetesClient, Deployment deployment, ClusterClientProvider clusterClient) + throws InterruptedException { + KubernetesResult result = KubernetesResult.build(getType()); + long waitSends = SystemConfiguration.getInstances().getJobIdWait() * 1000L; + long startTime = System.currentTimeMillis(); + + while (System.currentTimeMillis() - startTime < waitSends) { + List pods = kubernetesClient + .pods() + .inNamespace(deployment.getMetadata().getNamespace()) + .withLabelSelector(deployment.getSpec().getSelector()) + .list() + .getItems(); + for (Pod pod : pods) { + if (!checkPodStatus(pod)) { + logger.info("Kubernetes Pod have not ready, reTry at 5 sec later"); + continue; + } + try { + logger.info("Start get job list ...."); + JobDetails jobDetails = fetchApplicationJob(kubernetesClient, deployment); + if (Objects.isNull(jobDetails) || CollectionUtils.isEmpty(jobDetails.getJobs())) { + logger.error("Get job is empty, will be reconnect alter 5 sec later...."); + Thread.sleep(5000); + continue; + } + JobOverviewInfo jobOverviewInfo = + jobDetails.getJobs().stream().findFirst().get(); + // To create a cluster ID, you need to combine the cluster ID with the jobID to ensure uniqueness + String cid = configuration.getString(KubernetesConfigOptions.CLUSTER_ID) + jobOverviewInfo.getJid(); + logger.info("Success get job status: {}", jobOverviewInfo.getState()); + + return result.setJids(Collections.singletonList(jobOverviewInfo.getJid())) + .setWebURL(jobDetails.getWebUrl()) + .setId(cid); + } catch (GatewayException e) { + throw e; + } catch (Exception ex) { + logger.error("Get job status failed,{}", ex.getMessage()); + } + } + Thread.sleep(5000); + } + throw new GatewayException( + "The number of retries exceeds the limit, check the K8S cluster for more information"); + } + + private JobDetails fetchApplicationJob(KubernetesClient kubernetesClient, Deployment deployment) { + // 判断是不是存在ingress, 如果存在ingress的话返回ingress地址 + Ingress ingress = kubernetesClient + .network() + .v1() + .ingresses() + .inNamespace(deployment.getMetadata().getNamespace()) + .withName(deployment.getMetadata().getName()) + .get(); + String ingressUrl = getIngressUrl( + ingress, + deployment.getMetadata().getNamespace(), + deployment.getMetadata().getName()); + logger.info("Get dinky ingress url:{}", ingressUrl); + return invokeJobsOverviewApi(ingressUrl); + } + + private JobDetails invokeJobsOverviewApi(String restUrl) { + try { + String body; + try (HttpResponse execute = HttpUtil.createGet(restUrl + "/jobs/overview") + .timeout(10000) + .execute()) { + // 判断状态码,如果是504的话可能是因为task manage节点还未启动 + if (Objects.equals(execute.getStatus(), HttpStatus.HTTP_GATEWAY_TIMEOUT)) { + return null; + } + body = execute.body(); + } + if (StringUtils.isNotEmpty(body)) { + JobDetails jobDetails = JSONObject.parseObject(body, JobDetails.class); + jobDetails.setWebUrl(restUrl); + return jobDetails; + } + } catch (Exception e) { + logger.warn("Get job overview warning, task manage is enabled and can be ignored"); + } + return null; + } + + private String getIngressUrl(Ingress ingress, String namespace, String clusterId) { + if (Objects.nonNull(ingress) + && Objects.nonNull(ingress.getSpec()) + && Objects.nonNull(ingress.getSpec().getRules()) + && !ingress.getSpec().getRules().isEmpty()) { + String host = ingress.getSpec().getRules().get(0).getHost(); + return StrFormatter.format("http://{}/{}/{}", host, namespace, clusterId); + } + throw new GatewayException( + StrFormatter.format("Dinky clusterId {} ingress not found in namespace {}", clusterId, namespace)); + } + + /** + * Determine whether to use the ingress agent service + * @return ingress domain + */ + private String checkUseIngress() { + Map ingressConfig = k8sConfig.getIngressConfig(); + if (MapUtils.isNotEmpty(ingressConfig)) { + boolean ingressEnable = + Boolean.parseBoolean(ingressConfig.getOrDefault(DINKY_K8S_INGRESS_ENABLED_KEY, "false")); + String ingressDomain = ingressConfig.getOrDefault(DINKY_K8S_INGRESS_DOMAIN_KEY, StringUtils.EMPTY); + if (ingressEnable && StringUtils.isNotEmpty(ingressDomain)) { + return ingressDomain; + } + } + return StringUtils.EMPTY; + } } diff --git a/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/ingress/DinkyKubernetesIngress.java b/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/ingress/DinkyKubernetesIngress.java new file mode 100644 index 0000000000..5035b9a5b2 --- /dev/null +++ b/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/ingress/DinkyKubernetesIngress.java @@ -0,0 +1,136 @@ +/* + * + * 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.dinky.gateway.kubernetes.ingress; + +import static org.dinky.assertion.Asserts.checkNotNull; + +import org.dinky.gateway.kubernetes.utils.K8sClientHelper; + +import java.util.Map; + +import com.google.common.collect.Maps; + +import cn.hutool.core.text.StrFormatter; +import io.fabric8.kubernetes.api.model.OwnerReference; +import io.fabric8.kubernetes.api.model.OwnerReferenceBuilder; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.networking.v1.Ingress; +import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DinkyKubernetesIngress { + + private final K8sClientHelper k8sClientHelper; + + public DinkyKubernetesIngress(K8sClientHelper k8sClientHelper) { + this.k8sClientHelper = k8sClientHelper; + } + + public void configureIngress(String clusterId, String domain, String namespace) { + log.info("Dinky ingress configure ingress for cluster {} in namespace {}", clusterId, namespace); + OwnerReference ownerReference = getOwnerReference(namespace, clusterId); + Ingress ingress = new IngressBuilder() + .withNewMetadata() + .withName(clusterId) + .addToAnnotations(buildIngressAnnotations(clusterId, namespace)) + .addToLabels(buildIngressLabels(clusterId)) + .addToOwnerReferences(ownerReference) // Add OwnerReference + .endMetadata() + .withNewSpec() + .addNewRule() + .withHost(domain) + .withNewHttp() + .addNewPath() + .withPath(StrFormatter.format("/{}/{}/", namespace, clusterId)) + .withPathType("ImplementationSpecific") + .withNewBackend() + .withNewService() + .withName(StrFormatter.format("{}-rest", clusterId)) + .withNewPort() + .withNumber(8081) + .endPort() + .endService() + .endBackend() + .endPath() + .addNewPath() + .withPath(StrFormatter.format("/{}/{}(/|$)(.*)", namespace, clusterId)) + .withPathType("ImplementationSpecific") + .withNewBackend() + .withNewService() + .withName(StrFormatter.format("{}-rest", clusterId)) + .withNewPort() + .withNumber(8081) + .endPort() + .endService() + .endBackend() + .endPath() + .endHttp() + .endRule() + .endSpec() + .build(); + try (KubernetesClient kubernetesClient = k8sClientHelper.getKubernetesClient()) { + kubernetesClient.network().v1().ingresses().inNamespace(namespace).create(ingress); + } + } + + private Map buildIngressAnnotations(String clusterId, String namespace) { + Map annotations = Maps.newConcurrentMap(); + annotations.put("nginx.ingress.kubernetes.io/rewrite-target", "/$2"); + annotations.put("nginx.ingress.kubernetes.io/proxy-body-size", "1024m"); + // Build the configuration snippet + String configurationSnippet = + "rewrite ^(/" + clusterId + ")$ $1/ permanent; " + "sub_filter '' ''; " + "sub_filter_once off;"; + annotations.put("nginx.ingress.kubernetes.io/configuration-snippet", configurationSnippet); + annotations.put("kubernetes.io/ingress.class", "nginx"); + return annotations; + } + + private Map buildIngressLabels(String clusterId) { + Map labels = Maps.newConcurrentMap(); + labels.put("app", clusterId); + labels.put("type", "flink-native-kubernetes"); + labels.put("component", "ingress"); + return labels; + } + + private OwnerReference getOwnerReference(String namespace, String clusterId) { + log.info("Dinky ingress get owner reference for cluster {} in namespace {}", clusterId, namespace); + KubernetesClient client = k8sClientHelper.getKubernetesClient(); + Deployment deployment = client.apps() + .deployments() + .inNamespace(namespace) + .withName(clusterId) + .get(); + checkNotNull( + deployment, + StrFormatter.format("Deployment with name {} not found in namespace {}", clusterId, namespace)); + return new OwnerReferenceBuilder() + .withUid(deployment.getMetadata().getUid()) + .withApiVersion("apps/v1") + .withKind("Deployment") + .withName(clusterId) + .withController(true) + .withBlockOwnerDeletion(true) + .build(); + } +} diff --git a/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/utils/DinkyKubernetsConstants.java b/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/utils/DinkyKubernetsConstants.java index 58a6804e9b..bb7f228b99 100644 --- a/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/utils/DinkyKubernetsConstants.java +++ b/dinky-gateway/src/main/java/org/dinky/gateway/kubernetes/utils/DinkyKubernetsConstants.java @@ -23,4 +23,7 @@ public class DinkyKubernetsConstants { public static final String DINKY_CONF_VOLUME = "dinky-config-volume"; public static final String DINKY_CONF_VOLUME_PERFIX = "dinky-config-"; + + public static final String DINKY_K8S_INGRESS_ENABLED_KEY = "kubernetes.ingress.enabled"; + public static final String DINKY_K8S_INGRESS_DOMAIN_KEY = "kubernetes.ingress.domain"; } diff --git a/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobDetails.java b/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobDetails.java new file mode 100644 index 0000000000..0308e1c48c --- /dev/null +++ b/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobDetails.java @@ -0,0 +1,36 @@ +/* + * + * 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.dinky.gateway.model.ingress; + +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobDetails { + + private List jobs; + + private String webUrl; +} diff --git a/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewInfo.java b/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewInfo.java new file mode 100644 index 0000000000..c4901f7313 --- /dev/null +++ b/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewInfo.java @@ -0,0 +1,46 @@ +/* + * + * 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.dinky.gateway.model.ingress; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobOverviewInfo { + + private String jid; + + private String name; + + private String state; + + private Long startTime; + + private Long endTime; + + private Long duration; + + private Long lastModification; + + private JobOverviewTaskInfo tasks; +} diff --git a/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewTaskInfo.java b/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewTaskInfo.java new file mode 100644 index 0000000000..4074a701fc --- /dev/null +++ b/dinky-gateway/src/main/java/org/dinky/gateway/model/ingress/JobOverviewTaskInfo.java @@ -0,0 +1,52 @@ +/* + * + * 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.dinky.gateway.model.ingress; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class JobOverviewTaskInfo { + + private Integer running; + + private Integer canceling; + + private Integer canceled; + + private Integer total; + + private Integer created; + + private Integer scheduled; + + private Integer deploying; + + private Integer reconciling; + + private Integer finished; + + private Integer initializing; + + private Integer failed; +} diff --git a/dinky-web/src/locales/en-US/pages.ts b/dinky-web/src/locales/en-US/pages.ts index 5c1f9af960..47b1564a8a 100644 --- a/dinky-web/src/locales/en-US/pages.ts +++ b/dinky-web/src/locales/en-US/pages.ts @@ -1113,6 +1113,11 @@ export default { 'rc.udf.register.deleteConfirm': 'Are you sure you want to delete this UDF? ', 'rc.udf.register': 'Register UDF', 'rc.udf.register.select': 'Please select a non-directory node', + // ingress + 'rc.cc.k8s.ingress.enabled': 'Kubernetes ingress enable', + 'rc.cc.k8s.ingress.enabledHelp': 'Kubernetes ingress enable! eg', + 'rc.cc.k8s.ingress.domain': 'Kubernetes ingress domain address', + 'rc.cc.k8s.ingress.domainHelp': 'Kubernetes ingress domain address! eg', /** * * role @@ -1217,6 +1222,7 @@ export default { 'sys.ldap.settings.keyword': 'You can enter your username/nickname for search, support fuzzy queries, enter keywords and press enter to complete the search', 'sys.ldap.settings.loadable': 'Whether it can be imported', + 'sys.setting.ingress': 'Ingress configuration', /** * * tenant diff --git a/dinky-web/src/locales/zh-CN/pages.ts b/dinky-web/src/locales/zh-CN/pages.ts index 408dad8cd9..19bea6a9a7 100644 --- a/dinky-web/src/locales/zh-CN/pages.ts +++ b/dinky-web/src/locales/zh-CN/pages.ts @@ -1032,6 +1032,11 @@ export default { 'rc.udf.register.deleteConfirm': '确定删除该 UDF 吗?', 'rc.udf.register': '注册 UDF', 'rc.udf.register.select': '请选择非目录节点!', + // ingress + 'rc.cc.k8s.ingress.enabled': '是否启用Ingress', + 'rc.cc.k8s.ingress.enabledHelp': '是否启用Ingress! eg', + 'rc.cc.k8s.ingress.domain': 'Ingress域名地址', + 'rc.cc.k8s.ingress.domainHelp': 'Ingress域名地址! eg', /** * @@ -1134,6 +1139,7 @@ export default { 'sys.ldap.settings.loadUser': '导入用户', 'sys.ldap.settings.keyword': '可输入用户名/昵称进行搜索,支持模糊查询,输入关键词后回车即可', 'sys.ldap.settings.loadable': '是否可以导入', + 'sys.setting.ingress': 'Ingress 配置', /** * * tenant diff --git a/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationModal/ConfigurationForm/FlinkK8s/index.tsx b/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationModal/ConfigurationForm/FlinkK8s/index.tsx index 67dea51668..51a8400816 100644 --- a/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationModal/ConfigurationForm/FlinkK8s/index.tsx +++ b/dinky-web/src/pages/RegCenter/Cluster/Configuration/components/ConfigurationModal/ConfigurationForm/FlinkK8s/index.tsx @@ -36,9 +36,10 @@ import { ProFormItem, ProFormList, ProFormSelect, + ProFormSwitch, ProFormText } from '@ant-design/pro-components'; -import { Button, Col, Divider, Row, Space, Typography, Upload, UploadProps } from 'antd'; +import { Button, Col, Divider, Form, Row, Space, Typography, Upload, UploadProps } from 'antd'; import { FormInstance } from 'antd/es/form/hooks/useForm'; import { RcFile } from 'antd/es/upload/interface'; import { Values } from 'async-validator'; @@ -152,6 +153,11 @@ const FlinkK8s = (props: { type: string; value: any; form: FormInstance } ]; + const ingressEnabled = Form.useWatch( + ['config', 'kubernetesConfig', 'ingressConfig', 'kubernetes.ingress.enabled'], + form + ); + return ( <> {l('rc.cc.k8sConfig')} @@ -191,6 +197,24 @@ const FlinkK8s = (props: { type: string; value: any; form: FormInstance placeholder={l('rc.cc.flinkConfigPathPlaceholder')} tooltip={l('rc.cc.flinkConfigPathHelp')} /> + {type && type === ClusterType.KUBERNETES_APPLICATION && ( + + )} + {type && type === ClusterType.KUBERNETES_APPLICATION && ingressEnabled && ( + + )} ; }; export type FlinkConfig = {