This is an automated email from the ASF dual-hosted git repository. benjobs pushed a commit to branch k8s-FE in repository https://gitbox.apache.org/repos/asf/incubator-streampark.git
commit 8250fb0a3fb05558fdca6df78729960cc8125274 Author: benjobs <[email protected]> AuthorDate: Sun Jun 23 00:28:32 2024 +0800 [Improve] job name validator improvement --- .../src/locales/lang/en/flink/app.ts | 12 ++++- .../src/locales/lang/zh-CN/flink/app.ts | 39 +++++++++------- .../src/locales/lang/zh-CN/setting/flinkCluster.ts | 14 +++--- .../flink/app/hooks/useCreateAndEditSchema.ts | 52 ++++++++++++++-------- .../src/views/flink/app/hooks/useFlinkRender.tsx | 40 +++++++++++++++++ 5 files changed, 116 insertions(+), 41 deletions(-) diff --git a/streampark-console/streampark-console-webapp/src/locales/lang/en/flink/app.ts b/streampark-console/streampark-console-webapp/src/locales/lang/en/flink/app.ts index ff29d9980..32aa9b540 100644 --- a/streampark-console/streampark-console-webapp/src/locales/lang/en/flink/app.ts +++ b/streampark-console/streampark-console-webapp/src/locales/lang/en/flink/app.ts @@ -275,8 +275,18 @@ export default { 'The application name already exists in YARN, cannot be repeated. Please check', appNameExistsInK8sMessage: 'The application name already exists in Kubernetes,cannot be repeated. Please check', + appNameValid: 'The job name is invalid', + appNameRole: 'The job name must follow these rules: ', appNameNotValid: 'The application name is invalid, must be (Chinese or English or "-" or "_"), two consecutive spaces cannot appear.Please check', + K8sSessionClusterIdRole: 'The K8s clusterId must follow the following rules:', + appNameK8sClusterIdRole: + 'The current deployment mode is K8s Application mode, and the job name will be used as the clusterId in K8s. Therefore, the job name must follow the following rules:', + appNameK8sClusterIdRoleLength: 'must be no more than 45 characters', + appNameK8sClusterIdRoleRegexp: + 'must only contain lowercase alphanumeric characters and "-",The required format is [a-z]([-a-z0-9]*[a-z0-9])', + appNameRoleContent: + 'must be (Chinese or English or "-" or "_"), two consecutive spaces cannot appear.Please check', flinkClusterIsRequiredMessage: 'Flink Cluster is required', flinkSqlIsRequiredMessage: 'Flink SQL is required', tagsPlaceholder: 'Please enter tags,if more than one, separate them with commas(,)', @@ -296,7 +306,7 @@ export default { flinkImagePlaceholder: 'Please enter the tag of Flink base docker image, such as: flink:1.13.0-scala_2.11-java8', flinkImageIsRequiredMessage: 'Flink Base Docker Image is required', - k8sRestExposedTypePlaceholder: 'kubernetes.rest-service.exposed.type', + k8sRestExposedTypePlaceholder: 'Kubernetes Rest-Service Exposed Type', hadoopXmlConfigFileTips: 'Automatically copy configuration files from system environment parameters', dynamicPropertiesPlaceholder: diff --git a/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/flink/app.ts b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/flink/app.ts index 2aee8d0cb..a3d55c7fa 100644 --- a/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/flink/app.ts +++ b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/flink/app.ts @@ -47,10 +47,10 @@ export default { yarnQueue: 'Yarn队列', mavenPom: 'maven pom', uploadJar: '上传依赖Jar文件', - kubernetesNamespace: 'K8S命名空间', - kubernetesClusterId: 'K8S ClusterId', - flinkBaseDockerImage: 'Flink基础docker镜像', - restServiceExposedType: 'K8S服务对外类型', + kubernetesNamespace: 'Kubernetes 命名空间', + kubernetesClusterId: 'Kubernetes ClusterId', + flinkBaseDockerImage: 'Flink 基础docker镜像', + restServiceExposedType: 'Rest-Service Exposed Type', resourceFrom: '资源来源', uploadJobJar: '上传jar文件', selectJobJar: '选择jar文件', @@ -71,7 +71,7 @@ export default { hadoopUser: 'Hadoop User', restoreModeTip: 'flink 1.15开始支持restore模式,一般情况下不用设置该参数', release: { - releaseTitle: '该应用程序的当前启动正在进行中.', + releaseTitle: '该作业正在启动中.', releaseDesc: '您确定要强制进行另一次构建吗', releaseFail: '发布作业失败', releasing: '当前作业正在发布中', @@ -153,11 +153,11 @@ export default { errorLog: '错误日志', errorSummary: '错误摘要', errorStack: '错误堆栈', - logTitle: '启动日志 : 应用名称 [ {0} ]', + logTitle: '启动日志 : 作业名称 [ {0} ]', refreshTime: '上次刷新时间', refresh: '刷新', start: '启动作业', - stop: '停止应用', + stop: '停止作业', savepoint: '触发 Savepoint', recheck: '关联的项目已更新,需要重新发布此作业', changed: '作业已更新', @@ -265,10 +265,19 @@ export default { appNamePlaceholder: '请输入作业名称', appNameIsRequiredMessage: '作业名称必填', appNameNotUniqueMessage: '作业名称必须唯一, 输入的作业名称已经存在', - appNameExistsInYarnMessage: '应用程序名称已经在YARN集群中存在,不能重复。请检查', - appNameExistsInK8sMessage: '该应用程序名称已经在K8S集群中存在,不能重复。请检查', + appNameExistsInYarnMessage: '作业名称已经在YARN集群中存在,不能重复。请检查', + appNameExistsInK8sMessage: '该作业名称已经在 Kubernetes 集群中存在,不能重复。请检查', + appNameValid: '作业名称不合法', + appNameRole: '作业必须遵循以下规则:', + K8sSessionClusterIdRole: 'Kubernetes 集群ID必要遵循以下规则:', + appNameK8sClusterIdRole: + '当前部署模式是 Kubernetes Application 模式,会将作业名称作为 Kubernetes 的 clusterId,因此作业名称要遵循以下规则:', + appNameK8sClusterIdRoleLength: '不应超过 45 个字符', + appNameK8sClusterIdRoleRegexp: + '只能由小写字母、数字、字符、和"-" 组成,必须满足正则格式 [a-z]([-a-z0-9]*[a-z0-9])', + appNameRoleContent: '字符必须是(中文 或 英文 或 "-" 或 "_"),不能出现两个连续的空格', appNameNotValid: - '应用程序名称无效。字符必须是(中文 或 英文 或 "-" 或 "_"),不能出现两个连续的空格,请检查', + '作业名称无效。字符必须是(中文 或 英文 或 "-" 或 "_"),不能出现两个连续的空格,请检查', flinkClusterIsRequiredMessage: 'Flink集群必填', flinkSqlIsRequiredMessage: 'Flink SQL必填', tagsPlaceholder: '请输入标签,如果超过一个,用逗号(,)分隔', @@ -279,15 +288,15 @@ export default { totalMemoryOptionsPlaceholder: '请选择要设置的资源参数', tmPlaceholder: '请选择要设置的资源参数', yarnQueuePlaceholder: '请输入yarn队列标签名称', - descriptionPlaceholder: '请输入此应用程序的描述', - kubernetesNamespacePlaceholder: '请输入K8S命名空间, 如: default', - kubernetesClusterIdPlaceholder: '请选择K8S ClusterId', + descriptionPlaceholder: '请输入此作业的描述', + kubernetesNamespacePlaceholder: '请输入 Kubernetes 命名空间, 如: default', + kubernetesClusterIdPlaceholder: '请选择 Kubernetes ClusterId', kubernetesClusterIdRequire: '小写字母、数字、“-”,并且必须以字母数字字符开头和结尾,并且不超过45个字符', - kubernetesClusterIdIsRequiredMessage: 'K8S ClusterId必填', + kubernetesClusterIdIsRequiredMessage: 'Kubernetes ClusterId 必填', flinkImagePlaceholder: '请输入Flink基础docker镜像的标签,如:flink:1.13.0-scala_2.11-java8', flinkImageIsRequiredMessage: 'Flink基础docker镜像是必填的', - k8sRestExposedTypePlaceholder: 'K8S服务对外类型', + k8sRestExposedTypePlaceholder: 'Kubernetes Rest-Service Exposed Type', hadoopXmlConfigFileTips: '从系统环境参数自动复制配置文件', dynamicPropertiesPlaceholder: '$key=$value,如果有多个参数,可以换行输入(-D <arg>)', }, diff --git a/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/setting/flinkCluster.ts b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/setting/flinkCluster.ts index 4e926d749..9cfdb9b84 100644 --- a/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/setting/flinkCluster.ts +++ b/streampark-console/streampark-console-webapp/src/locales/lang/zh-CN/setting/flinkCluster.ts @@ -32,12 +32,12 @@ export default { addNew: '全新集群', yarnQueue: 'Yarn队列', yarnSessionClusterId: 'Yarn Session模式集群ID', - k8sNamespace: 'k8s命名空间', - k8sClusterId: 'k8s集群ID', - serviceAccount: 'k8s命名空间绑定的服务账号', - k8sConf: 'k8s环境Kube配置文件', - flinkImage: 'Flink基础docker镜像', - k8sRestExposedType: 'K8S服务对外类型', + k8sNamespace: 'Kubernetes 命名空间', + k8sClusterId: 'Kubernetes 集群 ID', + serviceAccount: 'Kubernetes 服务账号', + k8sConf: 'Kube 配置文件', + flinkImage: 'Flink 基础 Docker 镜像', + k8sRestExposedType: 'Kubernetes Rest exposed-type', resolveOrder: '类加载顺序', taskSlots: '任务槽数', jmOptions: 'JM内存', @@ -54,7 +54,7 @@ export default { addressNoRemoteMode: '请输入集群地址,例如:http://host:port', yarnSessionClusterId: '请输入Yarn Session模式集群ID', k8sConf: '示例:~/.kube/config', - flinkImage: '请输入Flink基础docker镜像的标签,如:flink:1.13.0-scala_2.11-java8', + flinkImage: '请输入 Flink 基础 docker 镜像的标签,如:flink:1.13.0-scala_2.11-java8', k8sRestExposedType: 'kubernetes.rest-service.exposed.type', resolveOrder: 'classloader.resolve-order', taskSlots: '每个TaskManager的插槽数', diff --git a/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useCreateAndEditSchema.ts b/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useCreateAndEditSchema.ts index 25847a28f..d3263d2a1 100644 --- a/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useCreateAndEditSchema.ts +++ b/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useCreateAndEditSchema.ts @@ -29,6 +29,7 @@ import { renderTotalMemory, renderYarnQueue, renderFlinkCluster, + renderJobName, } from './useFlinkRender'; import { fetchCheckName } from '/@/api/flink/app'; @@ -279,26 +280,33 @@ export const useCreateAndEditSchema = ( }); /* Detect job name field */ - async function getJobNameCheck(_rule: RuleObject, value: StoreValue) { + async function getJobNameCheck(_rule: RuleObject, value: StoreValue, model: Recordable) { if (value === null || value === undefined || value === '') { return Promise.reject(t('flink.app.addAppTips.appNameIsRequiredMessage')); - } else { - const params = { jobName: value }; - if (edit?.appId) Object.assign(params, { id: edit.appId }); - const res = await fetchCheckName(params); - switch (parseInt(res)) { - case 0: - return Promise.resolve(); - case 1: - return Promise.reject(t('flink.app.addAppTips.appNameNotUniqueMessage')); - case 2: - return Promise.reject(t('flink.app.addAppTips.appNameExistsInYarnMessage')); - case 3: - return Promise.reject(t('flink.app.addAppTips.appNameExistsInK8sMessage')); - default: - return Promise.reject(t('flink.app.addAppTips.appNameNotValid')); + } + if (model.executionMode == ExecModeEnum.KUBERNETES_APPLICATION) { + const regexp = /^(?=.{1,45}$)[a-z]([-a-z0-9]*[a-z0-9])$/; + if (!regexp.test(value)) { + return Promise.reject(t('flink.app.addAppTips.appNameValid')); } } + const params = { jobName: value }; + if (edit?.appId) { + Object.assign(params, { id: edit.appId }); + } + const res = await fetchCheckName(params); + switch (parseInt(res)) { + case 0: + return Promise.resolve(); + case 1: + return Promise.reject(t('flink.app.addAppTips.appNameNotUniqueMessage')); + case 2: + return Promise.reject(t('flink.app.addAppTips.appNameExistsInYarnMessage')); + case 3: + return Promise.reject(t('flink.app.addAppTips.appNameExistsInK8sMessage')); + default: + return Promise.reject(t('flink.app.addAppTips.appNameValid')); + } } const getFlinkFormOtherSchemas = computed((): FormSchema[] => { @@ -313,8 +321,16 @@ export const useCreateAndEditSchema = ( label: t('flink.app.appName'), component: 'Input', componentProps: { placeholder: t('flink.app.addAppTips.appNamePlaceholder') }, - dynamicRules: () => { - return [{ required: true, trigger: 'blur', validator: getJobNameCheck }]; + render: (param) => renderJobName(param), + dynamicRules: ({ model }) => { + return [ + { + required: true, + trigger: 'blur', + validator: (rule: RuleObject, value: StoreValue) => + getJobNameCheck(rule, value, model), + }, + ]; }, }, { diff --git a/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useFlinkRender.tsx b/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useFlinkRender.tsx index 45b22f1d5..62975b584 100644 --- a/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useFlinkRender.tsx +++ b/streampark-console/streampark-console-webapp/src/views/flink/app/hooks/useFlinkRender.tsx @@ -44,6 +44,7 @@ import { FailoverStrategyEnum, RestoreModeEnum, ClusterStateEnum, + ExecModeEnum, } from '/@/enums/flinkEnum'; import { useI18n } from '/@/hooks/web/useI18n'; import { fetchYarnQueueList } from '/@/api/setting/yarnQueue'; @@ -299,6 +300,45 @@ export const renderFlinkCluster = (clusters, { model, field }: RenderCallbackPar ); }; +export const renderJobName = ({ model, field }: RenderCallbackParams) => { + return ( + <div> + <Input + name="jobName" + placeholder={t('flink.app.addAppTips.appNamePlaceholder')} + value={model[field]} + onInput={(e: ChangeEvent) => (model[field] = e?.target?.value)} + /> + <p class="conf-desc mt-10px"> + <span class="note-info"> + <Tag color="#2db7f5" class="tag-note"> + {t('flink.app.noteInfo.note')} + </Tag> + {model.executionMode == ExecModeEnum.KUBERNETES_APPLICATION && ( + <span> + {t('flink.app.addAppTips.appNameK8sClusterIdRole')} + <div> + <Tag color="orange"> 1.</Tag> + {t('flink.app.addAppTips.appNameK8sClusterIdRoleLength')} + </div> + <div> + <Tag color="orange"> 2.</Tag> + {t('flink.app.addAppTips.appNameK8sClusterIdRoleRegexp')} + </div> + </span> + )} + {model.executionMode != ExecModeEnum.KUBERNETES_APPLICATION && ( + <span> + <span>{t('flink.app.addAppTips.appNameRole')}</span> + <span>{t('flink.app.addAppTips.appNameRoleContent')}</span> + </span> + )} + </span> + </p> + </div> + ); +}; + /* render memory option */ export const renderDynamicProperties = ({ model, field }: RenderCallbackParams) => { return (
