From 43aca84be579a041fe81f6de46075a3a8476c8a0 Mon Sep 17 00:00:00 2001 From: weidong_chang <51365967+chang-wd@users.noreply.github.com> Date: Wed, 20 Nov 2024 21:40:43 +0800 Subject: [PATCH 1/5] [Feature] #1121 support clearInactiveClusterPhyBrokers --- .../km/biz/cluster/ClusterBrokersManager.java | 10 +++++ .../impl/ClusterBrokersManagerImpl.java | 6 +++ .../layout-clusters-fe/src/api/index.ts | 2 + .../src/pages/BrokerList/index.tsx | 42 +++++++++++++++++++ .../km/core/service/broker/BrokerService.java | 2 + .../broker/impl/BrokerServiceImpl.java | 14 +++++++ .../v3/cluster/ClusterBrokersController.java | 8 ++++ 7 files changed, 84 insertions(+) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java index 8427c1ef0..68a5b7b95 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java @@ -17,6 +17,16 @@ public interface ClusterBrokersManager { */ PaginationResult getClusterPhyBrokersOverview(Long clusterPhyId, ClusterBrokersOverviewDTO dto); + /** + * 删除status == 0 的所有broker -> 获取缓存查询结果 & broker 表查询结果并集 + * 获取缓存查询结果 & broker 表查询结果并集 + * @param clusterPhyId kafka 物理集群 id + * @param dto 封装分页查询参数对象 + * @return 返回获取到的缓存查询结果 & broker 表查询结果并集 + */ + PaginationResult deleteInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto); + + /** * 根据物理集群id获取集群对应broker状态信息 * @param clusterPhyId 物理集群 id diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java index c77724dd8..3254731d3 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java @@ -107,6 +107,12 @@ public PaginationResult getClusterPhyBrokersOverview(L ); } + @Override + public PaginationResult deleteInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto) { + brokerService.deleteInactiveClusterPhyBrokers(clusterPhyId); + return this.getClusterPhyBrokersOverview(clusterPhyId, dto); + } + @Override public ClusterBrokersStateVO getClusterPhyBrokersState(Long clusterPhyId) { ClusterBrokersStateVO clusterBrokersStateVO = new ClusterBrokersStateVO(); diff --git a/km-console/packages/layout-clusters-fe/src/api/index.ts b/km-console/packages/layout-clusters-fe/src/api/index.ts index d07599524..97db801a0 100755 --- a/km-console/packages/layout-clusters-fe/src/api/index.ts +++ b/km-console/packages/layout-clusters-fe/src/api/index.ts @@ -120,6 +120,8 @@ const api = { getTopicMetricPoints: (clusterPhyId: number, topicName: string) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/metric-points`), // Broker列表接口 getBrokersList: (clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/brokers-overview`), + // 删除失效Broker + clearInactiveBrokers: (clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/brokers-clear`), // Broker列表页健康检查指标 getBrokerMetricPoints: (clusterPhyId: number) => getApi(`/physical-clusters/${clusterPhyId}/latest-metrics`), // Controller列表接口 /api/v3/clusters/{clusterPhyId}/controller-history「controller-change-log」 diff --git a/km-console/packages/layout-clusters-fe/src/pages/BrokerList/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/BrokerList/index.tsx index 9d5dd0537..7d6402117 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/BrokerList/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/BrokerList/index.tsx @@ -66,6 +66,42 @@ const BrokerList: React.FC = (props: any) => { }); }; + // 请求接口获取数据 + const clearInactiveBrokers = async ({ pageNo, pageSize, filters, sorter }: any) => { + if (urlParams?.clusterId === undefined) return; + // filters = filters || filteredInfo; + setLoading(true); + const params = { + searchKeywords: searchKeywords.slice(0, 128), + pageNo, + pageSize, + latestMetricNames: ['PartitionsSkew', 'Leaders', 'LeadersSkew', 'LogSize'], + sortField: sorter?.field || 'brokerId', + sortType: sorter?.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : 'asc', + }; + + request(API.clearInactiveBrokers(urlParams?.clusterId), { method: 'POST', data: params }) + .then((res: any) => { + setPagination({ + current: res.pagination?.pageNo, + pageSize: res.pagination?.pageSize, + total: res.pagination?.total, + }); + const newData = + res?.bizData.map((item: any) => { + return { + ...item, + ...item?.latestMetrics?.metrics, + }; + }) || []; + setData(newData); + setLoading(false); + }) + .catch((err) => { + setLoading(false); + }); + }; + const onTableChange = (pagination: any, filters: any, sorter: any) => { // setFilteredInfo(filters); genData({ pageNo: pagination.current, pageSize: pagination.pageSize, filters, sorter }); @@ -107,6 +143,12 @@ const BrokerList: React.FC = (props: any) => { > +
clearInactiveBrokers({ pageNo: pagination.current, pageSize: pagination.pageSize })} + > + +
listNotAliveBrokersFromDB(Long clusterPhyId) { return this.listAllBrokersAndUpdateCache(clusterPhyId).stream().filter( elem -> !elem.alive()).collect(Collectors.toList()); } + /** + * 清理对应集群中下线的broker记录 + * @param clusterPhyId + */ + @Override + public void clearInactiveClusterPhyBrokers(Long clusterPhyId) { + try { + this.getAllBrokerPOsFromDB(clusterPhyId).stream() + .filter(elem -> elem.getStatus().equals(Constant.DOWN)) + .forEach(elem -> brokerDAO.deleteById(elem.getId())); + } catch (Exception e) { + log.error("method=deleteInactiveClusterPhyBrokers||clusterPhyId={}||errMsg=exception!", clusterPhyId, e); + } + } @Override public List listAllBrokersFromDB(Long clusterPhyId) { return this.listAllBrokersAndUpdateCache(clusterPhyId); diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterBrokersController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterBrokersController.java index db9c933a4..3bfe5c6ad 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterBrokersController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/cluster/ClusterBrokersController.java @@ -62,4 +62,12 @@ public PaginationResult getClusterPhyBrokersOverview(@ @RequestBody ClusterBrokersOverviewDTO dto) { return clusterBrokersManager.getClusterPhyBrokersOverview(clusterPhyId, dto); } + + @ApiOperation(value = "集群无效brokers清理") + @PostMapping(value = "clusters/{clusterPhyId}/brokers-clear") + @ResponseBody + public PaginationResult clearInactiveClusterPhyBrokers(@PathVariable Long clusterPhyId, + @RequestBody ClusterBrokersOverviewDTO dto) { + return clusterBrokersManager.clearInactiveClusterPhyBrokers(clusterPhyId, dto); + } } \ No newline at end of file From aaf10ae3cad85587da996f2ab29ddaeb424056d1 Mon Sep 17 00:00:00 2001 From: weidong_chang <51365967+chang-wd@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:02:16 +0800 Subject: [PATCH 2/5] [Feature] #1121 support clearInactiveClusterPhyBrokers --- .../know/streaming/km/biz/cluster/ClusterBrokersManager.java | 2 +- .../km/biz/cluster/impl/ClusterBrokersManagerImpl.java | 4 ++-- .../km/core/service/broker/impl/BrokerServiceImpl.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java index 68a5b7b95..0eba136b1 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/ClusterBrokersManager.java @@ -24,7 +24,7 @@ public interface ClusterBrokersManager { * @param dto 封装分页查询参数对象 * @return 返回获取到的缓存查询结果 & broker 表查询结果并集 */ - PaginationResult deleteInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto); + PaginationResult clearInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto); /** diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java index 3254731d3..d8796dcdd 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/cluster/impl/ClusterBrokersManagerImpl.java @@ -108,8 +108,8 @@ public PaginationResult getClusterPhyBrokersOverview(L } @Override - public PaginationResult deleteInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto) { - brokerService.deleteInactiveClusterPhyBrokers(clusterPhyId); + public PaginationResult clearInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto) { + brokerService.clearInactiveClusterPhyBrokers(clusterPhyId); return this.getClusterPhyBrokersOverview(clusterPhyId, dto); } diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java index aad774730..105019f74 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/broker/impl/BrokerServiceImpl.java @@ -187,7 +187,7 @@ public void clearInactiveClusterPhyBrokers(Long clusterPhyId) { .filter(elem -> elem.getStatus().equals(Constant.DOWN)) .forEach(elem -> brokerDAO.deleteById(elem.getId())); } catch (Exception e) { - log.error("method=deleteInactiveClusterPhyBrokers||clusterPhyId={}||errMsg=exception!", clusterPhyId, e); + log.error("method=clearInactiveClusterPhyBrokers||clusterPhyId={}||errMsg=exception!", clusterPhyId, e); } } @Override From e0fc2109628771a42807f990bec3da30c092991f Mon Sep 17 00:00:00 2001 From: weidong_chang Date: Fri, 21 Nov 2025 16:40:06 +0800 Subject: [PATCH 3/5] =?UTF-8?q?[Bugfix]=20fix=20#887=20=E8=A7=A3=E9=99=A4j?= =?UTF-8?q?mx=E7=9A=84SSL=E5=92=8C=E5=AF=86=E7=A0=81=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E8=80=A6=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/constants/reg.ts | 2 ++ .../pages/MutliClusterPage/AccessCluster.tsx | 36 +++++++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/constants/reg.ts b/km-console/packages/layout-clusters-fe/src/constants/reg.ts index 7463882a1..995ba2ccd 100644 --- a/km-console/packages/layout-clusters-fe/src/constants/reg.ts +++ b/km-console/packages/layout-clusters-fe/src/constants/reg.ts @@ -22,3 +22,5 @@ export const regTemplateName = /^[a-z0-9\._-]*$/; // 仅支持小写字母、数 export const regIp = /((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}/g; // ip export const regKafkaPassword = /^[A-Za-z0-9_\-!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]*$/; + +export const regJmxPassword = /^[_a-zA-Z0-9-]*$/; // JMX密码:支持大小写字母、数字、下划线、短划线 diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx index fec1a8a6b..04238e4a9 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx @@ -1,9 +1,9 @@ -import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils, Tabs, Collapse, Empty } from 'knowdesign'; +import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils, Tabs, Collapse, Empty, Checkbox } from 'knowdesign'; import message from '@src/components/Message'; import React, { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react'; import { useIntl } from 'react-intl'; import api from '@src/api'; -import { regClusterName, regIpAndPort, regUsername } from '@src/constants/reg'; +import { regClusterName, regIpAndPort, regUsername, regJmxPassword } from '@src/constants/reg'; import { bootstrapServersErrCodes, jmxErrCodes, zkErrCodes } from './config'; import CodeMirrorFormItem from '@src/components/CodeMirrorFormItem'; import { IconFont } from '@knowdesign/icons'; @@ -169,7 +169,16 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { const originValue = obj?.jmxProperties; if (originValue) { const jmxProperties = JSON.parse(originValue); - typeof jmxProperties === 'object' && jmxProperties !== null && Object.assign(res, jmxProperties); + if (typeof jmxProperties === 'object' && jmxProperties !== null) { + Object.assign(res, jmxProperties); + // 根据是否有 username/token 判断是否启用密码认证 + const hasPasswordAuth = !!(jmxProperties.username && jmxProperties.token); + res.hasPasswordAuth = hasPasswordAuth; + // 如果没有密码认证,确保 openSSL 为 false + if (!hasPasswordAuth) { + res.openSSL = false; + } + } } } catch (err) { console.error('jmxProperties not JSON: ', err); @@ -257,8 +266,8 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { if (!value) { return Promise.reject('密码不能为空'); } - if (!new RegExp(regUsername).test(value)) { - return Promise.reject('密码只能由大小写、下划线、短划线(-)组成'); + if (!new RegExp(regJmxPassword).test(value)) { + return Promise.reject('密码只能由大小写字母、数字、下划线、短划线(-)组成'); } if (value.length < 6 || value.length > 32) { return Promise.reject('密码长度限制在6~32字符'); @@ -360,15 +369,15 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => {
- + None Password Authentication - + {({ getFieldValue }) => { - return getFieldValue('openSSL') ? ( + return getFieldValue('hasPasswordAuth') ? (
@@ -379,6 +388,7 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { validator: validators.securityUserName, }, ]} + style={{ width: '140px', marginRight: '8px' }} > @@ -390,9 +400,13 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { validator: validators.securityToken, }, ]} + style={{ width: '140px', marginRight: '8px' }} > + + 启用 SSL +
) : null; @@ -759,9 +773,9 @@ const AccessClusterDrawer = (props: AccessClusterDrawerProps) => { jmxProperties: { jmxPort: res.jmxPort, maxConn: res.maxConn, - openSSL: res.openSSL || false, - token: res.token, - username: res.username, + openSSL: res.hasPasswordAuth ? (res.openSSL || false) : false, + token: res.hasPasswordAuth ? res.token : '', + username: res.hasPasswordAuth ? res.username : '', }, kafkaVersion: res.kafkaVersion, name: res.name, From 69ec8b5c781f39139f13daf6b36b99469f00ce9b Mon Sep 17 00:00:00 2001 From: weidong_chang <51365967+chang-wd@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:44:27 +0800 Subject: [PATCH 4/5] =?UTF-8?q?Revert=20"[Bugfix]=20fix=20#887=20=E8=A7=A3?= =?UTF-8?q?=E9=99=A4jmx=E7=9A=84SSL=E5=92=8C=E5=AF=86=E7=A0=81=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E9=BB=98=E8=AE=A4=E8=80=A6=E5=90=88"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e0fc2109628771a42807f990bec3da30c092991f. --- .../layout-clusters-fe/src/constants/reg.ts | 2 -- .../pages/MutliClusterPage/AccessCluster.tsx | 36 ++++++------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/constants/reg.ts b/km-console/packages/layout-clusters-fe/src/constants/reg.ts index 995ba2ccd..7463882a1 100644 --- a/km-console/packages/layout-clusters-fe/src/constants/reg.ts +++ b/km-console/packages/layout-clusters-fe/src/constants/reg.ts @@ -22,5 +22,3 @@ export const regTemplateName = /^[a-z0-9\._-]*$/; // 仅支持小写字母、数 export const regIp = /((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}/g; // ip export const regKafkaPassword = /^[A-Za-z0-9_\-!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]*$/; - -export const regJmxPassword = /^[_a-zA-Z0-9-]*$/; // JMX密码:支持大小写字母、数字、下划线、短划线 diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx index 04238e4a9..fec1a8a6b 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx @@ -1,9 +1,9 @@ -import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils, Tabs, Collapse, Empty, Checkbox } from 'knowdesign'; +import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils, Tabs, Collapse, Empty } from 'knowdesign'; import message from '@src/components/Message'; import React, { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react'; import { useIntl } from 'react-intl'; import api from '@src/api'; -import { regClusterName, regIpAndPort, regUsername, regJmxPassword } from '@src/constants/reg'; +import { regClusterName, regIpAndPort, regUsername } from '@src/constants/reg'; import { bootstrapServersErrCodes, jmxErrCodes, zkErrCodes } from './config'; import CodeMirrorFormItem from '@src/components/CodeMirrorFormItem'; import { IconFont } from '@knowdesign/icons'; @@ -169,16 +169,7 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { const originValue = obj?.jmxProperties; if (originValue) { const jmxProperties = JSON.parse(originValue); - if (typeof jmxProperties === 'object' && jmxProperties !== null) { - Object.assign(res, jmxProperties); - // 根据是否有 username/token 判断是否启用密码认证 - const hasPasswordAuth = !!(jmxProperties.username && jmxProperties.token); - res.hasPasswordAuth = hasPasswordAuth; - // 如果没有密码认证,确保 openSSL 为 false - if (!hasPasswordAuth) { - res.openSSL = false; - } - } + typeof jmxProperties === 'object' && jmxProperties !== null && Object.assign(res, jmxProperties); } } catch (err) { console.error('jmxProperties not JSON: ', err); @@ -266,8 +257,8 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { if (!value) { return Promise.reject('密码不能为空'); } - if (!new RegExp(regJmxPassword).test(value)) { - return Promise.reject('密码只能由大小写字母、数字、下划线、短划线(-)组成'); + if (!new RegExp(regUsername).test(value)) { + return Promise.reject('密码只能由大小写、下划线、短划线(-)组成'); } if (value.length < 6 || value.length > 32) { return Promise.reject('密码长度限制在6~32字符'); @@ -369,15 +360,15 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => {
- + None Password Authentication - + {({ getFieldValue }) => { - return getFieldValue('hasPasswordAuth') ? ( + return getFieldValue('openSSL') ? (
@@ -388,7 +379,6 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { validator: validators.securityUserName, }, ]} - style={{ width: '140px', marginRight: '8px' }} > @@ -400,13 +390,9 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { validator: validators.securityToken, }, ]} - style={{ width: '140px', marginRight: '8px' }} > - - 启用 SSL -
) : null; @@ -773,9 +759,9 @@ const AccessClusterDrawer = (props: AccessClusterDrawerProps) => { jmxProperties: { jmxPort: res.jmxPort, maxConn: res.maxConn, - openSSL: res.hasPasswordAuth ? (res.openSSL || false) : false, - token: res.hasPasswordAuth ? res.token : '', - username: res.hasPasswordAuth ? res.username : '', + openSSL: res.openSSL || false, + token: res.token, + username: res.username, }, kafkaVersion: res.kafkaVersion, name: res.name, From e9486bea27c80dfe6bb3d42b950667745891b788 Mon Sep 17 00:00:00 2001 From: weidong_chang <51365967+chang-wd@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:48:32 +0800 Subject: [PATCH 5/5] =?UTF-8?q?[Bugfix]=20fix=20#887=20=E8=A7=A3=E9=99=A4j?= =?UTF-8?q?mx=E7=9A=84SSL=E5=92=8C=E5=AF=86=E7=A0=81=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E8=80=A6=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/constants/reg.ts | 2 ++ .../pages/MutliClusterPage/AccessCluster.tsx | 36 +++++++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/constants/reg.ts b/km-console/packages/layout-clusters-fe/src/constants/reg.ts index 7463882a1..995ba2ccd 100644 --- a/km-console/packages/layout-clusters-fe/src/constants/reg.ts +++ b/km-console/packages/layout-clusters-fe/src/constants/reg.ts @@ -22,3 +22,5 @@ export const regTemplateName = /^[a-z0-9\._-]*$/; // 仅支持小写字母、数 export const regIp = /((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}/g; // ip export const regKafkaPassword = /^[A-Za-z0-9_\-!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]*$/; + +export const regJmxPassword = /^[_a-zA-Z0-9-]*$/; // JMX密码:支持大小写字母、数字、下划线、短划线 diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx index fec1a8a6b..04238e4a9 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx @@ -1,9 +1,9 @@ -import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils, Tabs, Collapse, Empty } from 'knowdesign'; +import { Button, Divider, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Space, Utils, Tabs, Collapse, Empty, Checkbox } from 'knowdesign'; import message from '@src/components/Message'; import React, { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react'; import { useIntl } from 'react-intl'; import api from '@src/api'; -import { regClusterName, regIpAndPort, regUsername } from '@src/constants/reg'; +import { regClusterName, regIpAndPort, regUsername, regJmxPassword } from '@src/constants/reg'; import { bootstrapServersErrCodes, jmxErrCodes, zkErrCodes } from './config'; import CodeMirrorFormItem from '@src/components/CodeMirrorFormItem'; import { IconFont } from '@knowdesign/icons'; @@ -169,7 +169,16 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { const originValue = obj?.jmxProperties; if (originValue) { const jmxProperties = JSON.parse(originValue); - typeof jmxProperties === 'object' && jmxProperties !== null && Object.assign(res, jmxProperties); + if (typeof jmxProperties === 'object' && jmxProperties !== null) { + Object.assign(res, jmxProperties); + // 根据是否有 username/token 判断是否启用密码认证 + const hasPasswordAuth = !!(jmxProperties.username && jmxProperties.token); + res.hasPasswordAuth = hasPasswordAuth; + // 如果没有密码认证,确保 openSSL 为 false + if (!hasPasswordAuth) { + res.openSSL = false; + } + } } } catch (err) { console.error('jmxProperties not JSON: ', err); @@ -257,8 +266,8 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { if (!value) { return Promise.reject('密码不能为空'); } - if (!new RegExp(regUsername).test(value)) { - return Promise.reject('密码只能由大小写、下划线、短划线(-)组成'); + if (!new RegExp(regJmxPassword).test(value)) { + return Promise.reject('密码只能由大小写字母、数字、下划线、短划线(-)组成'); } if (value.length < 6 || value.length > 32) { return Promise.reject('密码长度限制在6~32字符'); @@ -360,15 +369,15 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => {
- + None Password Authentication - + {({ getFieldValue }) => { - return getFieldValue('openSSL') ? ( + return getFieldValue('hasPasswordAuth') ? (
@@ -379,6 +388,7 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { validator: validators.securityUserName, }, ]} + style={{ width: '140px', marginRight: '8px' }} > @@ -390,9 +400,13 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => { validator: validators.securityToken, }, ]} + style={{ width: '140px', marginRight: '8px' }} > + + 启用 SSL +
) : null; @@ -759,9 +773,9 @@ const AccessClusterDrawer = (props: AccessClusterDrawerProps) => { jmxProperties: { jmxPort: res.jmxPort, maxConn: res.maxConn, - openSSL: res.openSSL || false, - token: res.token, - username: res.username, + openSSL: res.hasPasswordAuth ? (res.openSSL || false) : false, + token: res.hasPasswordAuth ? res.token : '', + username: res.hasPasswordAuth ? res.username : '', }, kafkaVersion: res.kafkaVersion, name: res.name,