Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ public interface ClusterBrokersManager {
*/
PaginationResult<ClusterBrokersOverviewVO> getClusterPhyBrokersOverview(Long clusterPhyId, ClusterBrokersOverviewDTO dto);

/**
* 删除status == 0 的所有broker -> 获取缓存查询结果 & broker 表查询结果并集
* 获取缓存查询结果 & broker 表查询结果并集
* @param clusterPhyId kafka 物理集群 id
* @param dto 封装分页查询参数对象
* @return 返回获取到的缓存查询结果 & broker 表查询结果并集
*/
PaginationResult<ClusterBrokersOverviewVO> clearInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto);


/**
* 根据物理集群id获取集群对应broker状态信息
* @param clusterPhyId 物理集群 id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ public PaginationResult<ClusterBrokersOverviewVO> getClusterPhyBrokersOverview(L
);
}

@Override
public PaginationResult<ClusterBrokersOverviewVO> clearInactiveClusterPhyBrokers(Long clusterPhyId, ClusterBrokersOverviewDTO dto) {
brokerService.clearInactiveClusterPhyBrokers(clusterPhyId);
return this.getClusterPhyBrokersOverview(clusterPhyId, dto);
}

@Override
public ClusterBrokersStateVO getClusterPhyBrokersState(Long clusterPhyId) {
ClusterBrokersStateVO clusterBrokersStateVO = new ClusterBrokersStateVO();
Expand Down
2 changes: 2 additions & 0 deletions km-console/packages/layout-clusters-fe/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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」
Expand Down
2 changes: 2 additions & 0 deletions km-console/packages/layout-clusters-fe/src/constants/reg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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密码:支持大小写字母、数字、下划线、短划线
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down Expand Up @@ -107,6 +143,12 @@ const BrokerList: React.FC = (props: any) => {
>
<IconFont className={`${tableHeaderPrefix}-left-refresh-icon`} type="icon-shuaxin1" />
</div>
<div
className={`${tableHeaderPrefix}-left-clear`}
onClick={() => clearInactiveBrokers({ pageNo: pagination.current, pageSize: pagination.pageSize })}
>
<IconFont className={`${tableHeaderPrefix}-left-clear-icon`} type="icon-Operation" />
</div>
</div>
<div className={`${tableHeaderPrefix}-right`}>
<SearchInput
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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字符');
Expand Down Expand Up @@ -360,15 +369,15 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => {
<InputNumber addonAfter="个" min={0} max={99999} style={{ width: 124 }} />
</Form.Item>
</div>
<Form.Item name="openSSL" label="Security :">
<Form.Item name="hasPasswordAuth" label="Security :">
<Radio.Group>
<Radio value={false}>None</Radio>
<Radio value={true}>Password Authentication</Radio>
</Radio.Group>
</Form.Item>
<Form.Item dependencies={['openSSL']} noStyle>
<Form.Item dependencies={['hasPasswordAuth']} noStyle>
{({ getFieldValue }) => {
return getFieldValue('openSSL') ? (
return getFieldValue('hasPasswordAuth') ? (
<div className="user-info-form-items">
<Form.Item className="user-info-label" label="User Info :" required />
<div className="inline-items">
Expand All @@ -379,6 +388,7 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => {
validator: validators.securityUserName,
},
]}
style={{ width: '140px', marginRight: '8px' }}
>
<Input placeholder="请输入用户名" />
</Form.Item>
Expand All @@ -390,9 +400,13 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => {
validator: validators.securityToken,
},
]}
style={{ width: '140px', marginRight: '8px' }}
>
<Input placeholder="请输入密码" />
</Form.Item>
<Form.Item name="openSSL" valuePropName="checked" style={{ marginBottom: 0, alignSelf: 'center' }}>
<Checkbox>启用 SSL</Checkbox>
</Form.Item>
</div>
</div>
) : null;
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,6 @@ public interface BrokerService {
boolean allServerDown(Long clusterPhyId);

boolean existServerDown(Long clusterPhyId);

void clearInactiveClusterPhyBrokers(Long clusterPhyId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,20 @@ public List<Broker> 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=clearInactiveClusterPhyBrokers||clusterPhyId={}||errMsg=exception!", clusterPhyId, e);
}
}
@Override
public List<Broker> listAllBrokersFromDB(Long clusterPhyId) {
return this.listAllBrokersAndUpdateCache(clusterPhyId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,12 @@ public PaginationResult<ClusterBrokersOverviewVO> getClusterPhyBrokersOverview(@
@RequestBody ClusterBrokersOverviewDTO dto) {
return clusterBrokersManager.getClusterPhyBrokersOverview(clusterPhyId, dto);
}

@ApiOperation(value = "集群无效brokers清理")
@PostMapping(value = "clusters/{clusterPhyId}/brokers-clear")
@ResponseBody
public PaginationResult<ClusterBrokersOverviewVO> clearInactiveClusterPhyBrokers(@PathVariable Long clusterPhyId,
@RequestBody ClusterBrokersOverviewDTO dto) {
return clusterBrokersManager.clearInactiveClusterPhyBrokers(clusterPhyId, dto);
}
}
Loading