mirror of
https://github.com/didi/KnowStreaming.git
synced 2025-12-26 13:42:13 +08:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b74612fa41 | ||
|
|
22e0c20dcd | ||
|
|
08f92e1100 | ||
|
|
bb12ece46e | ||
|
|
0065438305 | ||
|
|
7f115c1b3e | ||
|
|
0ef64fa4bd | ||
|
|
84dbc17c22 | ||
|
|
16e16e356d | ||
|
|
978ee885c4 | ||
|
|
850d43df63 | ||
|
|
fc109fd1b1 | ||
|
|
2829947b93 | ||
|
|
0c2af89a1c | ||
|
|
14c2dc9624 | ||
|
|
4f35d710a6 | ||
|
|
fdb5e018e5 | ||
|
|
6001fde25c | ||
|
|
ae63c0adaf | ||
|
|
ad1539c8f6 | ||
|
|
634a0c8cd0 | ||
|
|
773f9a0c63 | ||
|
|
e4e320e9e3 | ||
|
|
3b4b400e6b | ||
|
|
f3a5e3f5ed | ||
|
|
e685e621f3 | ||
|
|
2cd2be9b67 | ||
|
|
e73d9e8a03 | ||
|
|
476f74a604 | ||
|
|
ab0d1d99e6 | ||
|
|
d5680ffd5d | ||
|
|
3c091a88d4 | ||
|
|
49b70b33de | ||
|
|
c5ff2716fb | ||
|
|
400fdf0896 | ||
|
|
cbb8c7323c | ||
|
|
60e79f8f77 | ||
|
|
0e829d739a | ||
|
|
62abb274e0 | ||
|
|
e4028785de | ||
|
|
2bb44bcb76 | ||
|
|
684599f81b | ||
|
|
b56d28f5df | ||
|
|
02b9ac04c8 | ||
|
|
2fc283990a | ||
|
|
abb652ebd5 | ||
|
|
55786cb7f7 | ||
|
|
447a575f4f | ||
|
|
49280a8617 |
10
README.md
10
README.md
@@ -9,6 +9,8 @@
|
||||
|
||||
## 主要功能特性
|
||||
|
||||
### 快速体验
|
||||
- 体验地址 http://117.51.146.109:8080 账号密码 admin/admin
|
||||
|
||||
### 集群监控维度
|
||||
|
||||
@@ -32,7 +34,7 @@
|
||||
|
||||
## kafka-manager架构图
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## 相关文档
|
||||
@@ -45,13 +47,17 @@
|
||||
## 钉钉交流群
|
||||
|
||||

|
||||
钉钉群ID:32821440
|
||||
|
||||
## OCE认证
|
||||
OCE是一个认证机制和交流平台,为Logi-KafkaManager生产用户量身打造,我们会为OCE企业提供更好的技术支持,比如专属的技术沙龙、企业一对一的交流机会、专属的答疑群等,如果贵司Logi-KafkaManager上了生产,[快来加入吧](http://obsuite.didiyun.com/open/openAuth)
|
||||
|
||||
|
||||
## 项目成员
|
||||
|
||||
### 内部核心人员
|
||||
|
||||
`iceyuhui`、`liuyaguang`、`limengmonty`、`zhangliangmike`、`nullhuangyiming`、`zengqiao`、`eilenexuzhe`、`huangjiaweihjw`
|
||||
`iceyuhui`、`liuyaguang`、`limengmonty`、`zhangliangmike`、`nullhuangyiming`、`zengqiao`、`eilenexuzhe`、`huangjiaweihjw`、`zhaoyinrui`、`marzkonglingxu`、`joysunchao`
|
||||
|
||||
|
||||
### 外部贡献者
|
||||
|
||||
65
build.sh
65
build.sh
@@ -3,72 +3,53 @@ workspace=$(cd $(dirname $0) && pwd -P)
|
||||
cd $workspace
|
||||
|
||||
## constant
|
||||
app_name=kafka-manager
|
||||
output_dir=output
|
||||
OUTPUT_DIR=./output
|
||||
KM_VERSION=2.2.0
|
||||
APP_NAME=kafka-manager
|
||||
APP_DIR=${APP_NAME}-${KM_VERSION}
|
||||
|
||||
gitversion=.gitversion
|
||||
control=./control.sh
|
||||
create_mysql_table=./docs/install_guide/create_mysql_table.sql
|
||||
app_config_file=./kafka-manager-web/src/main/resources/application.yml
|
||||
MYSQL_TABLE_SQL_FILE=./docs/install_guide/create_mysql_table.sql
|
||||
CONFIG_FILE=./kafka-manager-web/src/main/resources/application.yml
|
||||
|
||||
## function
|
||||
function build() {
|
||||
# 进行编译
|
||||
# # cmd 设置使用的JDK, 按需选择, 默认已安装了JDK 8
|
||||
# JVERSION=`java -version 2>&1 | awk 'NR==1{gsub(/"/,"");print $3}'`
|
||||
# major=`echo $JVERSION | awk -F. '{print $1}'`
|
||||
# mijor=`echo $JVERSION | awk -F. '{print $2}'`
|
||||
# if [ $major -le 1 ] && [ $mijor -lt 8 ]; then
|
||||
# export JAVA_HOME=/usr/local/jdk1.8.0_65 #(使用jdk8请设置)
|
||||
# export PATH=$JAVA_HOME/bin:$PATH
|
||||
# fi
|
||||
|
||||
# 编译命令
|
||||
mvn -U clean package -Dmaven.test.skip=true
|
||||
mvn -U clean package -Dmaven.test.skip=true
|
||||
|
||||
local sc=$?
|
||||
if [ $sc -ne 0 ];then
|
||||
## 编译失败, 退出码为 非0
|
||||
echo "$app_name build error"
|
||||
echo "$APP_NAME build error"
|
||||
exit $sc
|
||||
else
|
||||
echo -n "$app_name build ok, vsn="`gitversion`
|
||||
echo "$APP_NAME build ok"
|
||||
fi
|
||||
}
|
||||
|
||||
function make_output() {
|
||||
# 新建output目录
|
||||
rm -rf $output_dir &>/dev/null
|
||||
mkdir -p $output_dir &>/dev/null
|
||||
# 新建output目录
|
||||
rm -rf ${OUTPUT_DIR} &>/dev/null
|
||||
mkdir -p ${OUTPUT_DIR}/${APP_DIR} &>/dev/null
|
||||
|
||||
# 填充output目录, output内的内容 即为 线上部署内容
|
||||
(
|
||||
# cp -rf $control $output_dir && # 拷贝 control.sh 脚本 至output目录
|
||||
cp -rf $create_mysql_table $output_dir && # 拷贝 sql 初始化脚本 至output目录
|
||||
cp -rf $app_config_file $output_dir && # 拷贝 application.yml 至output目录
|
||||
# 填充output目录, output内的内容
|
||||
(
|
||||
cp -rf ${MYSQL_TABLE_SQL_FILE} ${OUTPUT_DIR}/${APP_DIR} && # 拷贝 sql 初始化脚本 至output目录
|
||||
cp -rf ${CONFIG_FILE} ${OUTPUT_DIR}/${APP_DIR} && # 拷贝 application.yml 至output目录
|
||||
|
||||
# 拷贝程序包到output路径
|
||||
cp kafka-manager-web/target/${app_name}-*-SNAPSHOT.jar ${output_dir}/${app_name}.jar
|
||||
echo -e "make output ok."
|
||||
) || { echo -e "make output error"; exit 2; } # 填充output目录失败后, 退出码为 非0
|
||||
# 拷贝程序包到output路径
|
||||
cp kafka-manager-web/target/kafka-manager-web-${KM_VERSION}-SNAPSHOT.jar ${OUTPUT_DIR}/${APP_DIR}/${APP_NAME}.jar
|
||||
echo -e "make output ok."
|
||||
) || { echo -e "make output error"; exit 2; } # 填充output目录失败后, 退出码为 非0
|
||||
}
|
||||
|
||||
function make_package() {
|
||||
# 压缩output目录
|
||||
(
|
||||
tar cvzf ${app_name}.tar.gz ${output_dir}
|
||||
echo -e "make package ok."
|
||||
cd ${OUTPUT_DIR} && tar cvzf ${APP_DIR}.tar.gz ${APP_DIR}
|
||||
echo -e "make package ok."
|
||||
) || { echo -e "make package error"; exit 2; } # 压缩output目录失败后, 退出码为 非0
|
||||
}
|
||||
|
||||
## internals
|
||||
function gitversion() {
|
||||
git log -1 --pretty=%h > $gitversion
|
||||
local gv=`cat $gitversion`
|
||||
echo "$gv"
|
||||
}
|
||||
|
||||
|
||||
##########################################
|
||||
## main
|
||||
## 其中,
|
||||
@@ -88,4 +69,4 @@ make_package
|
||||
|
||||
# 编译成功
|
||||
echo -e "build done"
|
||||
exit 0
|
||||
exit 0
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 270 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 589 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 652 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 511 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 672 KiB |
65
docs/dev_guide/dynamic_config_manager.md
Normal file
65
docs/dev_guide/dynamic_config_manager.md
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
---
|
||||
|
||||
# 动态配置管理
|
||||
|
||||
## 1、Topic定时同步任务
|
||||
|
||||
### 1.1、配置的用途
|
||||
`Logi-KafkaManager`在设计上,所有的资源都是挂在应用(app)下面。 如果接入的Kafka集群已经存在Topic了,那么会导致这些Topic不属于任何的应用,从而导致很多管理上的不便。
|
||||
|
||||
因此,需要有一个方式将这些无主的Topic挂到某个应用下面。
|
||||
|
||||
这里提供了一个配置,会定时自动将集群无主的Topic挂到某个应用下面下面。
|
||||
|
||||
### 1.2、相关实现
|
||||
|
||||
就是一个定时任务,该任务会定期做同步的工作。具体代码的位置在`com.xiaojukeji.kafka.manager.task.dispatch.op`包下面的`SyncTopic2DB`类。
|
||||
|
||||
### 1.3、配置说明
|
||||
|
||||
**步骤一:开启该功能**
|
||||
|
||||
在application.yml文件中,增加如下配置,已经有该配置的话,直接把false修改为true即可
|
||||
```yml
|
||||
# 任务相关的开关
|
||||
task:
|
||||
op:
|
||||
sync-topic-enabled: true # 无主的Topic定期同步到DB中
|
||||
```
|
||||
|
||||
**步骤二:配置管理中指定挂在那个应用下面**
|
||||
|
||||
配置的位置:
|
||||
|
||||

|
||||
|
||||
配置键:`SYNC_TOPIC_2_DB_CONFIG_KEY`
|
||||
|
||||
配置值(JSON数组):
|
||||
- clusterId:需要进行定时同步的集群ID
|
||||
- defaultAppId:该集群无主的Topic将挂在哪个应用下面
|
||||
- addAuthority:是否需要加上权限, 默认是false。因为考虑到这个挂载只是临时的,我们不希望用户使用这个App,同时后续可能移交给真正的所属的应用,因此默认是不加上权限。
|
||||
|
||||
**注意,这里的集群ID,或者是应用ID不存在的话,会导致配置不生效。该任务对已经在DB中的Topic不会进行修改**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"clusterId": 1234567,
|
||||
"defaultAppId": "ANONYMOUS",
|
||||
"addAuthority": false
|
||||
},
|
||||
{
|
||||
"clusterId": 7654321,
|
||||
"defaultAppId": "ANONYMOUS",
|
||||
"addAuthority": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
---
|
||||
|
||||
# 夜莺监控集成
|
||||
# 监控系统集成——夜莺
|
||||
|
||||
- `Kafka-Manager`通过将 监控的数据 以及 监控的规则 都提交给夜莺,然后依赖夜莺的监控系统从而实现监控告警功能。
|
||||
|
||||
@@ -22,10 +22,13 @@ monitor:
|
||||
n9e:
|
||||
nid: 2
|
||||
user-token: 123456
|
||||
# 夜莺 mon监控服务 地址
|
||||
mon:
|
||||
base-url: http://127.0.0.1:8032
|
||||
sink:
|
||||
base-url: http://127.0.0.1:8006
|
||||
# 夜莺 transfer上传服务 地址
|
||||
sink:
|
||||
base-url: http://127.0.0.1:8008
|
||||
# 夜莺 rdb资源服务 地址
|
||||
rdb:
|
||||
base-url: http://127.0.0.1:80
|
||||
|
||||
54
docs/dev_guide/monitor_system_integrate_with_self.md
Normal file
54
docs/dev_guide/monitor_system_integrate_with_self.md
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
---
|
||||
|
||||
# 监控系统集成
|
||||
|
||||
- 监控系统默认与 [夜莺] (https://github.com/didi/nightingale) 进行集成;
|
||||
- 对接自有的监控系统需要进行简单的二次开发,即实现部分监控告警模块的相关接口即可;
|
||||
- 集成会有两块内容,一个是指标数据上报的集成,还有一个是监控告警规则的集成;
|
||||
|
||||
## 1、指标数据上报集成
|
||||
|
||||
仅完成这一步的集成之后,即可将监控数据上报到监控系统中,此时已能够在自己的监控系统进行监控告警规则的配置了。
|
||||
|
||||
**步骤一:实现指标上报的接口**
|
||||
|
||||
- 按照自己内部监控系统的数据格式要求,将数据进行组装成符合自己内部监控系统要求的数据进行上报,具体的可以参考夜莺集成的实现代码。
|
||||
- 至于会上报哪些指标,可以查看有哪些地方调用了该接口。
|
||||
|
||||

|
||||
|
||||
**步骤二:相关配置修改**
|
||||
|
||||

|
||||
|
||||
**步骤三:开启上报任务**
|
||||
|
||||

|
||||
|
||||
|
||||
## 2、监控告警规则集成
|
||||
|
||||
完成**1、指标数据上报集成**之后,即可在自己的监控系统进行监控告警规则的配置了。完成该步骤的集成之后,可以在`Logi-KafkaManager`中进行监控告警规则的增删改查等等。
|
||||
|
||||
大体上和**1、指标数据上报集成**一致,
|
||||
|
||||
**步骤一:实现相关接口**
|
||||
|
||||

|
||||
|
||||
实现完成步骤一之后,接下来的步骤和**1、指标数据上报集成**中的步骤二、步骤三一致,都需要进行相关配置的修改即可。
|
||||
|
||||
|
||||
## 3、总结
|
||||
|
||||
简单介绍了一下监控告警的集成,嫌麻烦的同学可以仅做 **1、指标数据上报集成** 这一节的内容即可满足一定场景下的需求。
|
||||
|
||||
|
||||
**集成过程中,有任何觉得文档没有说清楚的地方或者建议,欢迎入群交流,也欢迎贡献代码,觉得好也辛苦给个star。**
|
||||
27
docs/dev_guide/upgrade_manual/logi-km-v2.2.0.md
Normal file
27
docs/dev_guide/upgrade_manual/logi-km-v2.2.0.md
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
---
|
||||
|
||||
# 升级至`2.2.0`版本
|
||||
|
||||
`2.2.0`版本在`cluster`表及`logical_cluster`各增加了一个字段,因此需要执行下面的sql进行字段的增加。
|
||||
|
||||
```sql
|
||||
# 往cluster表中增加jmx_properties字段, 这个字段会用于存储jmx相关的认证以及配置信息
|
||||
ALTER TABLE `cluster` ADD COLUMN `jmx_properties` TEXT NULL COMMENT 'JMX配置' AFTER `security_properties`;
|
||||
|
||||
# 往logical_cluster中增加identification字段, 同时数据和原先name数据相同, 最后增加一个唯一键.
|
||||
# 此后, name字段还是表示集群名称, 而identification字段表示的是集群标识, 只能是字母数字及下划线组成,
|
||||
# 数据上报到监控系统时, 集群这个标识采用的字段就是identification字段, 之前使用的是name字段.
|
||||
ALTER TABLE `logical_cluster` ADD COLUMN `identification` VARCHAR(192) NOT NULL DEFAULT '' COMMENT '逻辑集群标识' AFTER `name`;
|
||||
|
||||
UPDATE `logical_cluster` SET `identification`=`name` WHERE id>=0;
|
||||
|
||||
ALTER TABLE `logical_cluster` ADD INDEX `uniq_identification` (`identification` ASC);
|
||||
```
|
||||
|
||||
104
docs/install_guide/config_description.md
Normal file
104
docs/install_guide/config_description.md
Normal file
@@ -0,0 +1,104 @@
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
---
|
||||
|
||||
# 配置说明
|
||||
|
||||
```yaml
|
||||
server:
|
||||
port: 8080 # 服务端口
|
||||
tomcat:
|
||||
accept-count: 1000
|
||||
max-connections: 10000
|
||||
max-threads: 800
|
||||
min-spare-threads: 100
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: kafkamanager
|
||||
datasource:
|
||||
kafka-manager: # 数据库连接配置
|
||||
jdbc-url: jdbc:mysql://127.0.0.1:3306/kafka_manager?characterEncoding=UTF-8&serverTimezone=GMT%2B8 #数据库的地址
|
||||
username: admin # 用户名
|
||||
password: admin # 密码
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
|
||||
profiles:
|
||||
active: dev # 启用的配置
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 100MB
|
||||
max-request-size: 100MB
|
||||
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
|
||||
custom:
|
||||
idc: cn # 部署的数据中心, 忽略该配置, 后续会进行删除
|
||||
jmx:
|
||||
max-conn: 10 # 和单台 broker 的最大JMX连接数
|
||||
store-metrics-task:
|
||||
community:
|
||||
broker-metrics-enabled: true # 社区部分broker metrics信息收集开关, 关闭之后metrics信息将不会进行收集及写DB
|
||||
topic-metrics-enabled: true # 社区部分topic的metrics信息收集开关, 关闭之后metrics信息将不会进行收集及写DB
|
||||
didi:
|
||||
app-topic-metrics-enabled: false # 滴滴埋入的指标, 社区AK不存在该指标,因此默认关闭
|
||||
topic-request-time-metrics-enabled: false # 滴滴埋入的指标, 社区AK不存在该指标,因此默认关闭
|
||||
topic-throttled-metrics: false # 滴滴埋入的指标, 社区AK不存在该指标,因此默认关闭
|
||||
save-days: 7 #指标在DB中保持的天数,-1表示永久保存,7表示保存近7天的数据
|
||||
|
||||
# 任务相关的开关
|
||||
task:
|
||||
op:
|
||||
sync-topic-enabled: false # 未落盘的Topic定期同步到DB中
|
||||
|
||||
account: # ldap相关的配置, 社区版本暂时支持不够完善,可以先忽略,欢迎贡献代码对这块做优化
|
||||
ldap:
|
||||
|
||||
kcm: # 集群升级部署相关的功能,需要配合夜莺及S3进行使用,这块我们后续专门补充一个文档细化一下,牵扯到kcm_script.sh脚本的修改
|
||||
enabled: false # 默认关闭
|
||||
storage:
|
||||
base-url: http://127.0.0.1 # 存储地址
|
||||
n9e:
|
||||
base-url: http://127.0.0.1:8004 # 夜莺任务中心的地址
|
||||
user-token: 12345678 # 夜莺用户的token
|
||||
timeout: 300 # 集群任务的超时时间,单位秒
|
||||
account: root # 集群任务使用的账号
|
||||
script-file: kcm_script.sh # 集群任务的脚本
|
||||
|
||||
monitor: # 监控告警相关的功能,需要配合夜莺进行使用
|
||||
enabled: false # 默认关闭,true就是开启
|
||||
n9e:
|
||||
nid: 2
|
||||
user-token: 1234567890
|
||||
mon:
|
||||
# 夜莺 mon监控服务 地址
|
||||
base-url: http://127.0.0.1:8032
|
||||
sink:
|
||||
# 夜莺 transfer上传服务 地址
|
||||
base-url: http://127.0.0.1:8006
|
||||
rdb:
|
||||
# 夜莺 rdb资源服务 地址
|
||||
base-url: http://127.0.0.1:80
|
||||
|
||||
# enabled: 表示是否开启监控告警的功能, true: 开启, false: 不开启
|
||||
# n9e.nid: 夜莺的节点ID
|
||||
# n9e.user-token: 用户的密钥,在夜莺的个人设置中
|
||||
# n9e.mon.base-url: 监控地址
|
||||
# n9e.sink.base-url: 数据上报地址
|
||||
# n9e.rdb.base-url: 用户资源中心地址
|
||||
|
||||
notify: # 通知的功能
|
||||
kafka: # 默认通知发送到kafka的指定Topic中
|
||||
cluster-id: 95 # Topic的集群ID
|
||||
topic-name: didi-kafka-notify # Topic名称
|
||||
order: # 部署的KM的地址
|
||||
detail-url: http://127.0.0.1
|
||||
```
|
||||
@@ -1,3 +1,8 @@
|
||||
-- create database
|
||||
CREATE DATABASE logi_kafka_manager;
|
||||
|
||||
USE logi_kafka_manager;
|
||||
|
||||
--
|
||||
-- Table structure for table `account`
|
||||
--
|
||||
@@ -104,7 +109,8 @@ CREATE TABLE `cluster` (
|
||||
`zookeeper` varchar(512) NOT NULL DEFAULT '' COMMENT 'zk地址',
|
||||
`bootstrap_servers` varchar(512) NOT NULL DEFAULT '' COMMENT 'server地址',
|
||||
`kafka_version` varchar(32) NOT NULL DEFAULT '' COMMENT 'kafka版本',
|
||||
`security_properties` text COMMENT '安全认证参数',
|
||||
`security_properties` text COMMENT 'Kafka安全认证参数',
|
||||
`jmx_properties` text COMMENT 'JMX配置',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT ' 监控标记, 0表示未监控, 1表示监控中',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
@@ -302,20 +308,22 @@ INSERT INTO kafka_user(app_id, password, user_type, operation) VALUES ('dkm_admi
|
||||
-- Table structure for table `logical_cluster`
|
||||
--
|
||||
|
||||
-- DROP TABLE IF EXISTS `logical_cluster`;
|
||||
CREATE TABLE `logical_cluster` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`name` varchar(192) NOT NULL DEFAULT '' COMMENT '逻辑集群名称',
|
||||
`mode` int(16) NOT NULL DEFAULT '0' COMMENT '逻辑集群类型, 0:共享集群, 1:独享集群, 2:独立集群',
|
||||
`app_id` varchar(64) NOT NULL DEFAULT '' COMMENT '所属应用',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id',
|
||||
`region_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'regionid列表',
|
||||
`description` text COMMENT '备注说明',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='逻辑集群信息表';
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`name` varchar(192) NOT NULL DEFAULT '' COMMENT '逻辑集群名称',
|
||||
`identification` varchar(192) NOT NULL DEFAULT '' COMMENT '逻辑集群标识',
|
||||
`mode` int(16) NOT NULL DEFAULT '0' COMMENT '逻辑集群类型, 0:共享集群, 1:独享集群, 2:独立集群',
|
||||
`app_id` varchar(64) NOT NULL DEFAULT '' COMMENT '所属应用',
|
||||
`cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id',
|
||||
`region_list` varchar(256) NOT NULL DEFAULT '' COMMENT 'regionid列表',
|
||||
`description` text COMMENT '备注说明',
|
||||
`gmt_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_name` (`name`),
|
||||
UNIQUE KEY `uniq_identification` (`identification`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='逻辑集群信息表';
|
||||
|
||||
|
||||
--
|
||||
-- Table structure for table `monitor_rule`
|
||||
|
||||
@@ -9,19 +9,39 @@
|
||||
|
||||
# 安装手册
|
||||
|
||||
## 1、环境依赖
|
||||
|
||||
## 环境依赖
|
||||
如果是以Release包进行安装的,则仅安装`Java`及`MySQL`即可。如果是要先进行源码包进行打包,然后再使用,则需要安装`Maven`及`Node`环境。
|
||||
|
||||
- `Maven 3.5+`(后端打包依赖)
|
||||
- `node 10+`(前端打包依赖)
|
||||
- `Java 8+`(运行环境需要)
|
||||
- `MySQL 5.7`(数据存储)
|
||||
- `Maven 3.5+`(后端打包依赖)
|
||||
- `Node 10+`(前端打包依赖)
|
||||
|
||||
---
|
||||
|
||||
## 环境初始化
|
||||
## 2、获取安装包
|
||||
|
||||
执行[create_mysql_table.sql](create_mysql_table.sql)中的SQL命令,从而创建所需的MySQL库及表,默认创建的库名是`kafka_manager`。
|
||||
**1、Release直接下载**
|
||||
|
||||
这里如果觉得麻烦,然后也不想进行二次开发,则可以直接下载Release包,下载地址:[Github Release包下载地址](https://github.com/didi/Logi-KafkaManager/releases)
|
||||
|
||||
如果觉得Github的下载地址太慢了,也可以进入`Logi-KafkaManager`的用户群获取,群地址在README中。
|
||||
|
||||
|
||||
**2、源代码进行打包**
|
||||
|
||||
下载好代码之后,进入`Logi-KafkaManager`的主目录,执行`sh build.sh`命令即可,执行完成之后会在`output/kafka-manager-xxx`目录下面生成一个jar包。
|
||||
|
||||
对于`windows`环境的用户,估计执行不了`sh build.sh`命令,因此可以直接执行`mvn install`,然后在`kafka-manager-web/target`目录下生成一个kafka-manager-web-xxx.jar的包。
|
||||
|
||||
获取到jar包之后,我们继续下面的步骤。
|
||||
|
||||
---
|
||||
|
||||
## 3、MySQL-DB初始化
|
||||
|
||||
执行[create_mysql_table.sql](create_mysql_table.sql)中的SQL命令,从而创建所需的MySQL库及表,默认创建的库名是`logi_kafka_manager`。
|
||||
|
||||
```
|
||||
# 示例:
|
||||
@@ -30,29 +50,15 @@ mysql -uXXXX -pXXX -h XXX.XXX.XXX.XXX -PXXXX < ./create_mysql_table.sql
|
||||
|
||||
---
|
||||
|
||||
## 打包
|
||||
|
||||
```bash
|
||||
|
||||
# 一次性打包
|
||||
cd ..
|
||||
mvn install
|
||||
## 4、启动
|
||||
|
||||
```
|
||||
# application.yml 是配置文件,最简单的是仅修改MySQL相关的配置即可启动
|
||||
|
||||
---
|
||||
|
||||
## 启动
|
||||
|
||||
```
|
||||
# application.yml 是配置文件
|
||||
|
||||
cp kafka-manager-web/src/main/resources/application.yml kafka-manager-web/target/
|
||||
cd kafka-manager-web/target/
|
||||
nohup java -jar kafka-manager-web-2.0.0-SNAPSHOT.jar --spring.config.location=./application.yml > /dev/null 2>&1 &
|
||||
nohup java -jar kafka-manager.jar --spring.config.location=./application.yml > /dev/null 2>&1 &
|
||||
```
|
||||
|
||||
## 使用
|
||||
### 5、使用
|
||||
|
||||
本地启动的话,访问`http://localhost:8080`,输入帐号及密码(默认`admin/admin`)进行登录。更多参考:[kafka-manager 用户使用手册](../user_guide/user_guide_cn.md)
|
||||
|
||||
|
||||
25
docs/user_guide/alarm_rules.md
Normal file
25
docs/user_guide/alarm_rules.md
Normal file
@@ -0,0 +1,25 @@
|
||||
)
|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 报警策略-报警函数介绍
|
||||
|
||||
|
||||
|
||||
| 类别 | 函数 | 含义 |函数文案 |备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 发生次数 |all,n | 最近$n个周期内,全发生 | 连续发生(all) | |
|
||||
| 发生次数 | happen, n, m | 最近$n个周期内,发生m次 | 出现(happen) | null点也计算在n内 |
|
||||
| 数学统计 | sum, n | 最近$n个周期取值 的 和 | 求和(sum) | sum_over_time |
|
||||
| 数学统计 | avg, n | 最近$n个周期取值 的 平均值 | 平均值(avg) | avg_over_time |
|
||||
| 数学统计 | min, n | 最近$n个周期取值 的 最小值 | 最小值(min) | min_over_time |
|
||||
| 数学统计 | max, n | 最近$n个周期取值 的 最大值 | 最大值(max | max_over_time |
|
||||
| 变化率 | pdiff, n | 最近$n个点的变化率, 有一个满足 则触发 | 突增突降率(pdiff) | 假设, 最近3个周期的值分别为 v, v2, v3(v为最新值)那么计算公式为 any( (v-v2)/v2, (v-v3)/v3 )**区分正负** |
|
||||
| 变化量 | diff, n | 最近$n个点的变化量, 有一个满足 则触发 | 突增突降值(diff) | 假设, 最近3个周期的值分别为 v, v2, v3(v为最新值)那么计算公式为 any( (v-v2), (v-v3) )**区分正负** |
|
||||
| 变化量 | ndiff | 最近n个周期,发生m次 v(t) - v(t-1) $OP threshold其中 v(t) 为最新值 | 连续变化(区分正负) - ndiff | |
|
||||
| 数据中断 | nodata, t | 最近 $t 秒内 无数据上报 | 数据上报中断(nodata) | |
|
||||
| 同环比 | c_avg_rate_abs, n | 最近$n个周期的取值,相比 1天或7天前取值 的变化率 的绝对值 | 同比变化率(c_avg_rate_abs) | 假设最近的n个值为 v1, v2, v3历史取到的对应n'个值为 v1', v2'那么计算公式为abs((avg(v1,v2,v3) / avg(v1',v2') -1)* 100%) |
|
||||
| 同环比 | c_avg_rate, n | 最近$n个周期的取值,相比 1天或7天前取值 的变化率(**区分正负**) | 同比变化率(c_avg_rate) | 假设最近的n个值为 v1, v2, v3历史取到的对应n'个值为 v1', v2'那么计算公式为(avg(v1,v2,v3) / avg(v1',v2') -1)* 100% |
|
||||
@@ -29,7 +29,7 @@
|
||||
主要用途是进行大集群的管理 & 集群细节的屏蔽。
|
||||
|
||||
- 逻辑集群:通过逻辑集群概念,将集群Broker按业务进行归类,方便管理;
|
||||
- Region:通过引入Region,同时Topic按Region纬度创建,减少Broker间的连接;
|
||||
- Region:通过引入Region,同时Topic按Region维度创建,减少Broker间的连接;
|
||||
|
||||
---
|
||||
|
||||
@@ -53,13 +53,13 @@
|
||||
|
||||
- 3、数据库时区问题。
|
||||
|
||||
检查MySQL的topic表,查看是否有数据,如果有数据,那么再检查设置的时区是否正确。
|
||||
检查MySQL的topic_metrics、broker_metrics表,查看是否有数据,如果有数据,那么再检查设置的时区是否正确。
|
||||
|
||||
---
|
||||
|
||||
### 5、如何对接夜莺的监控告警功能?
|
||||
|
||||
- 参看 [kafka-manager 对接夜莺监控](../dev_guide/Intergration_n9e_monitor.md) 说明。
|
||||
- 参看 [kafka-manager 对接夜莺监控](../dev_guide/monitor_system_integrate_with_n9e.md) 说明。
|
||||
|
||||
---
|
||||
|
||||
|
||||
72
docs/user_guide/kafka_metrics_desc.md
Normal file
72
docs/user_guide/kafka_metrics_desc.md
Normal file
@@ -0,0 +1,72 @@
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
**一站式`Apache Kafka`集群指标监控与运维管控平台**
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
# Topic 指标说明
|
||||
|
||||
## 1. 实时流量指标说明
|
||||
|
||||
|
||||
| 指标名称| 单位| 指标含义|
|
||||
|-- |---- |---|
|
||||
| messagesIn| 条/s | 每秒发送到kafka的消息条数 |
|
||||
| byteIn| B/s | 每秒发送到kafka的字节数 |
|
||||
| byteOut| B/s | 每秒流出kafka的字节数(所有消费组消费的流量,如果是Kafka版本较低,这个还包括副本同步的流量) |
|
||||
| byteRejected| B/s | 每秒被拒绝的字节数 |
|
||||
| failedFetchRequest| qps | 每秒拉取失败的请求数 |
|
||||
| failedProduceRequest| qps | 每秒发送失败的请求数 |
|
||||
| totalProduceRequest| qps | 每秒总共发送的请求数,与messagesIn的区别是一个是发送请求里面可能会有多条消息 |
|
||||
| totalFetchRequest| qps | 每秒总共拉取消息的请求数 |
|
||||
|
||||
|
||||
|
||||
## 2. 历史流量指标说明
|
||||
|
||||
| 指标名称| 单位| 指标含义|
|
||||
|-- |---- |---|
|
||||
| messagesIn| 条/s | 近一分钟每秒发送到kafka的消息条数 |
|
||||
| byteIn| B/s | 近一分钟每秒发送到kafka的字节数 |
|
||||
| byteOut| B/s | 近一分钟每秒流出kafka的字节数(所有消费组消费的流量,如果是Kafka版本较低,副本同步的流量) |
|
||||
| byteRejected| B/s | 近一分钟每秒被拒绝的字节数 |
|
||||
| totalProduceRequest| qps | 近一分钟每秒总共发送的请求数,与messagesIn的区别是一个是发送请求里面可能会有多条消息 |
|
||||
|
||||
|
||||
|
||||
## 3. 实时耗时指标说明
|
||||
|
||||
**基于滴滴加强版Kafka引擎的特性,可以获取Broker的实时耗时信息和历史耗时信息**
|
||||
|
||||
| 指标名称| 单位 | 指标含义 | 耗时高原因 | 解决方案|
|
||||
|-- |-- |-- |-- |--|
|
||||
| RequestQueueTimeMs| ms | 请求队列排队时间 | 请求多,服务端处理不过来 | 联系运维人员处理 |
|
||||
| LocalTimeMs| ms | Broker本地处理时间 | 服务端读写数据慢,可能是读写锁竞争 | 联系运维人员处理 |
|
||||
| RemoteTimeMs| ms | 请求等待远程完成时间,对于发送请求,如果ack=-1,该时间表示副本同步时间,对于消费请求,如果当前没有数据,该时间为等待新数据时间,如果请求的版本与topic存储的版本不同,需要做版本转换,也会拉高该时间 | 对于生产,ack=-1必然会导致该指标耗时高,对于消费,如果topic数据写入很慢,该指标高也正常。如果需要版本转换,该指标耗时也会高 | 对于生产,可以考虑修改ack=1,消费端问题可以联系运维人员具体分析 |
|
||||
| ThrottleTimeMs| ms | 请求限流时间 | 生产/消费被限流 | 申请提升限流值 |
|
||||
| ResponseQueueTimeMs| ms | 响应队列排队时间 | 响应多,服务端处理不过来 | 联系运维人员处理 |
|
||||
| ResponseSendTimeMs| ms | 响应返回客户端时间 | 1:下游消费能力差,导致向consumer发送数据时写网络缓冲区过慢;2:消费lag过大,一直从磁盘读取数据 | 1:提升客户端消费性能;2: 联系运维人员确认是否读取磁盘问题 |
|
||||
| TotalTimeMs| ms | 接收到请求到完成总时间,理论上该时间等于上述六项时间之和,但由于各时间都是单独统计,总时间只是约等于上述六部分时间之和 | 上面六项有些耗时高 | 具体针对高的指标解决 |
|
||||
|
||||
**备注:由于kafka消费端实现方式,消费端一次会发送多个Fetch请求,在接收到一个Response之后就会开始处理数据,使Broker端返回其他Response等待,因此ResponseSendTimeMs并不完全是服务端发送时间,有时会包含一部分消费端处理数据时间**
|
||||
|
||||
## 4. 历史耗时指标说明
|
||||
|
||||
**基于滴滴加强版Kafka引擎的特性,可以获取Broker的实时耗时信息和历史耗时信息**
|
||||
|
||||
| 指标名称| 单位| 指标含义|
|
||||
|-- | ---- |---|
|
||||
| produceRequestTime99thPercentile|ms|Topic近一分钟发送99分位耗时|
|
||||
| fetchRequestTime99thPercentile|ms|Topic近一分钟拉取99分位耗时|
|
||||
| produceRequestTime95thPercentile|ms|Topic近一分钟发送95分位耗时|
|
||||
| fetchRequestTime95thPercentile|ms|Topic近一分钟拉取95分位耗时|
|
||||
| produceRequestTime75thPercentile|ms|Topic近一分钟发送75分位耗时|
|
||||
| fetchRequestTime75thPercentile|ms|Topic近一分钟拉取75分位耗时|
|
||||
| produceRequestTime50thPercentile|ms|Topic近一分钟发送50分位耗时|
|
||||
| fetchRequestTime50thPercentile|ms|Topic近一分钟拉取50分位耗时|
|
||||
|
||||
@@ -622,6 +622,9 @@ Lag:表示该消费客户端是否有堆积;等于 partition offset-consume
|
||||
|
||||
<font size=2>步骤3:</font>填写完成后,点击提交即可提交申请。
|
||||
|
||||
备注说明:集群创建后,还需在此基础上创建region、逻辑集群。具体操作可参照 [集群接入手册](https://github.com/didi/Logi-KafkaManager/blob/master/docs/user_guide/add_cluster/add_cluster.md)
|
||||
|
||||
|
||||

|
||||
|
||||
#### 申请集群下线 ####
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<artifactId>kafka-manager-common</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<version>${kafka-manager.revision}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<version>${kafka-manager.revision}</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -6,8 +6,6 @@ package com.xiaojukeji.kafka.manager.common.bizenum;
|
||||
*/
|
||||
public enum IDCEnum {
|
||||
CN("cn", "国内"),
|
||||
US("us", "美东"),
|
||||
RU("ru", "俄罗斯"),
|
||||
;
|
||||
|
||||
private String idc;
|
||||
|
||||
@@ -21,6 +21,8 @@ public enum ModuleEnum {
|
||||
|
||||
PARTITION(5, "分区"),
|
||||
|
||||
GATEWAY_CONFIG(6, "Gateway配置"),
|
||||
|
||||
UNKNOWN(-1, "未知")
|
||||
;
|
||||
ModuleEnum(int code, String message) {
|
||||
|
||||
@@ -10,6 +10,7 @@ public enum RebalanceDimensionEnum {
|
||||
REGION(1, "Region维度"),
|
||||
BROKER(2, "Broker维度"),
|
||||
TOPIC(3, "Topic维度"),
|
||||
PARTITION(4, "Partition维度"),
|
||||
;
|
||||
|
||||
private Integer code;
|
||||
|
||||
@@ -45,4 +45,13 @@ public enum GatewayConfigKeyEnum {
|
||||
", configName='" + configName + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static GatewayConfigKeyEnum getByConfigType(String configType) {
|
||||
for (GatewayConfigKeyEnum configKeyEnum: GatewayConfigKeyEnum.values()) {
|
||||
if (configKeyEnum.getConfigType().equals(configType)) {
|
||||
return configKeyEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ package com.xiaojukeji.kafka.manager.common.constant;
|
||||
public class KafkaConstant {
|
||||
public static final String COORDINATOR_TOPIC_NAME = "__consumer_offsets";
|
||||
|
||||
public static final String TRANSACTION_TOPIC_NAME = "__transaction_state";
|
||||
|
||||
public static final String BROKER_HOST_NAME_SUFFIX = ".diditaxi.com";
|
||||
|
||||
public static final String CLIENT_VERSION_CODE_UNKNOWN = "-1";
|
||||
|
||||
@@ -12,11 +12,6 @@ public class TopicCreationConstant {
|
||||
*/
|
||||
public static final String LOG_X_CREATE_TOPIC_CONFIG_KEY_NAME = "LOG_X_CREATE_TOPIC_CONFIG";
|
||||
|
||||
/**
|
||||
* 治理平台创建Topic配置KEY
|
||||
*/
|
||||
public static final String CHORUS_CREATE_TOPIC_CONFIG_KEY_NAME = "CHORUS_CREATE_TOPIC_CONFIG";
|
||||
|
||||
/**
|
||||
* 内部创建Topic配置KEY
|
||||
*/
|
||||
@@ -30,6 +25,8 @@ public class TopicCreationConstant {
|
||||
|
||||
public static final String TOPIC_RETENTION_TIME_KEY_NAME = "retention.ms";
|
||||
|
||||
public static final Long DEFAULT_QUOTA = 3 * 1024 * 1024L;
|
||||
|
||||
public static Properties createNewProperties(Long retentionTime) {
|
||||
Properties properties = new Properties();
|
||||
properties.put(TOPIC_RETENTION_TIME_KEY_NAME, String.valueOf(retentionTime));
|
||||
@@ -46,4 +43,15 @@ public class TopicCreationConstant {
|
||||
public static final String TOPIC_NAME_PREFIX_RU = "ru01_";
|
||||
|
||||
public static final Integer TOPIC_NAME_MAX_LENGTH = 255;
|
||||
|
||||
|
||||
/**
|
||||
* 单次自动化审批, 默认允许的通过单子
|
||||
*/
|
||||
public static final Integer DEFAULT_MAX_PASSED_ORDER_NUM_PER_TASK = 1;
|
||||
|
||||
/**
|
||||
* 单次自动化审批, 最多允许的通过单子
|
||||
*/
|
||||
public static final Integer MAX_PASSED_ORDER_NUM_PER_TASK = 200;
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.xiaojukeji.kafka.manager.common.entity;
|
||||
import kafka.admin.AdminClient;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author zengqiao
|
||||
@@ -16,17 +15,12 @@ public class ConsumerMetadata {
|
||||
|
||||
private Map<String, AdminClient.ConsumerGroupSummary> consumerGroupSummaryMap = new HashMap<>();
|
||||
|
||||
private Map<String, List<String>> consumerGroupAppMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public ConsumerMetadata(Set<String> consumerGroupSet,
|
||||
Map<String, Set<String>> topicNameConsumerGroupMap,
|
||||
Map<String, AdminClient.ConsumerGroupSummary> consumerGroupSummaryMap,
|
||||
Map<String, List<String>> consumerGroupAppMap) {
|
||||
Map<String, AdminClient.ConsumerGroupSummary> consumerGroupSummaryMap) {
|
||||
this.consumerGroupSet = consumerGroupSet;
|
||||
this.topicNameConsumerGroupMap = topicNameConsumerGroupMap;
|
||||
this.consumerGroupSummaryMap = consumerGroupSummaryMap;
|
||||
this.consumerGroupAppMap = consumerGroupAppMap;
|
||||
}
|
||||
|
||||
public Set<String> getConsumerGroupSet() {
|
||||
@@ -40,8 +34,4 @@ public class ConsumerMetadata {
|
||||
public Map<String, AdminClient.ConsumerGroupSummary> getConsumerGroupSummaryMap() {
|
||||
return consumerGroupSummaryMap;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getConsumerGroupAppMap() {
|
||||
return consumerGroupAppMap;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.xiaojukeji.kafka.manager.common.constant.Constant;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -118,4 +119,9 @@ public class Result<T> implements Serializable {
|
||||
result.setData(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean failed() {
|
||||
return !Constant.SUCCESS.equals(code);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ public enum ResultStatus {
|
||||
APP_ID_OR_PASSWORD_ILLEGAL(1000, "app or password illegal"),
|
||||
SYSTEM_CODE_ILLEGAL(1000, "system code illegal"),
|
||||
|
||||
CLUSTER_TASK_HOST_LIST_ILLEGAL(1000, "主机列表错误,请检查主机列表"),
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.ao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,8 @@ public class RdTopicBasic {
|
||||
|
||||
private String description;
|
||||
|
||||
private List<String> regionNameList;
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
@@ -87,6 +90,14 @@ public class RdTopicBasic {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public List<String> getRegionNameList() {
|
||||
return regionNameList;
|
||||
}
|
||||
|
||||
public void setRegionNameList(List<String> regionNameList) {
|
||||
this.regionNameList = regionNameList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RdTopicBasic{" +
|
||||
@@ -98,6 +109,7 @@ public class RdTopicBasic {
|
||||
", appName='" + appName + '\'' +
|
||||
", properties=" + properties +
|
||||
", description='" + description + '\'' +
|
||||
", regionNameList='" + regionNameList + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.ao.cluster;
|
||||
|
||||
public class ControllerPreferredCandidate {
|
||||
private Integer brokerId;
|
||||
|
||||
private String host;
|
||||
|
||||
private Long startTime;
|
||||
|
||||
private Integer status;
|
||||
|
||||
public Integer getBrokerId() {
|
||||
return brokerId;
|
||||
}
|
||||
|
||||
public void setBrokerId(Integer brokerId) {
|
||||
this.brokerId = brokerId;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public Long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ControllerPreferredBroker{" +
|
||||
"brokerId=" + brokerId +
|
||||
", host='" + host + '\'' +
|
||||
", startTime=" + startTime +
|
||||
", status=" + status +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ public class LogicalCluster {
|
||||
|
||||
private String logicalClusterName;
|
||||
|
||||
private String logicalClusterIdentification;
|
||||
|
||||
private Integer mode;
|
||||
|
||||
private Integer topicNum;
|
||||
@@ -41,6 +43,14 @@ public class LogicalCluster {
|
||||
this.logicalClusterName = logicalClusterName;
|
||||
}
|
||||
|
||||
public String getLogicalClusterIdentification() {
|
||||
return logicalClusterIdentification;
|
||||
}
|
||||
|
||||
public void setLogicalClusterIdentification(String logicalClusterIdentification) {
|
||||
this.logicalClusterIdentification = logicalClusterIdentification;
|
||||
}
|
||||
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
@@ -81,6 +91,14 @@ public class LogicalCluster {
|
||||
this.bootstrapServers = bootstrapServers;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Long getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
@@ -97,19 +115,12 @@ public class LogicalCluster {
|
||||
this.gmtModify = gmtModify;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LogicalCluster{" +
|
||||
"logicalClusterId=" + logicalClusterId +
|
||||
", logicalClusterName='" + logicalClusterName + '\'' +
|
||||
", logicalClusterIdentification='" + logicalClusterIdentification + '\'' +
|
||||
", mode=" + mode +
|
||||
", topicNum=" + topicNum +
|
||||
", clusterVersion='" + clusterVersion + '\'' +
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.ao.config;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.constant.TopicCreationConstant;
|
||||
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -7,8 +10,27 @@ import java.util.List;
|
||||
* @date 20/7/24
|
||||
*/
|
||||
public class CreateTopicConfig {
|
||||
/**
|
||||
* 单次自动化审批, 允许的通过单子
|
||||
*/
|
||||
private Integer maxPassedOrderNumPerTask;
|
||||
|
||||
private List<CreateTopicElemConfig> configList;
|
||||
|
||||
public Integer getMaxPassedOrderNumPerTask() {
|
||||
if (ValidateUtils.isNull(maxPassedOrderNumPerTask)) {
|
||||
return TopicCreationConstant.DEFAULT_MAX_PASSED_ORDER_NUM_PER_TASK;
|
||||
}
|
||||
if (maxPassedOrderNumPerTask > TopicCreationConstant.MAX_PASSED_ORDER_NUM_PER_TASK) {
|
||||
return TopicCreationConstant.MAX_PASSED_ORDER_NUM_PER_TASK;
|
||||
}
|
||||
return maxPassedOrderNumPerTask;
|
||||
}
|
||||
|
||||
public void setMaxPassedOrderNumPerTask(Integer maxPassedOrderNumPerTask) {
|
||||
this.maxPassedOrderNumPerTask = maxPassedOrderNumPerTask;
|
||||
}
|
||||
|
||||
public List<CreateTopicElemConfig> getConfigList() {
|
||||
return configList;
|
||||
}
|
||||
@@ -20,7 +42,8 @@ public class CreateTopicConfig {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CreateTopicConfig{" +
|
||||
"configList=" + configList +
|
||||
"maxPassedOrderNumPerTask=" + maxPassedOrderNumPerTask +
|
||||
", configList=" + configList +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -2,30 +2,18 @@ package com.xiaojukeji.kafka.manager.common.entity.ao.consumer;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.bizenum.OffsetLocationEnum;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 消费组信息
|
||||
* @author zengqiao
|
||||
* @date 19/4/18
|
||||
*/
|
||||
public class ConsumerGroupDTO {
|
||||
public class ConsumerGroup {
|
||||
private Long clusterId;
|
||||
|
||||
private String consumerGroup;
|
||||
|
||||
private List<String> appIdList;
|
||||
|
||||
private OffsetLocationEnum offsetStoreLocation;
|
||||
|
||||
public ConsumerGroupDTO(Long clusterId,
|
||||
String consumerGroup,
|
||||
List<String> appIdList,
|
||||
OffsetLocationEnum offsetStoreLocation) {
|
||||
public ConsumerGroup(Long clusterId, String consumerGroup, OffsetLocationEnum offsetStoreLocation) {
|
||||
this.clusterId = clusterId;
|
||||
this.consumerGroup = consumerGroup;
|
||||
this.appIdList = appIdList;
|
||||
this.offsetStoreLocation = offsetStoreLocation;
|
||||
}
|
||||
|
||||
@@ -45,14 +33,6 @@ public class ConsumerGroupDTO {
|
||||
this.consumerGroup = consumerGroup;
|
||||
}
|
||||
|
||||
public List<String> getAppIdList() {
|
||||
return appIdList;
|
||||
}
|
||||
|
||||
public void setAppIdList(List<String> appIdList) {
|
||||
this.appIdList = appIdList;
|
||||
}
|
||||
|
||||
public OffsetLocationEnum getOffsetStoreLocation() {
|
||||
return offsetStoreLocation;
|
||||
}
|
||||
@@ -63,10 +43,9 @@ public class ConsumerGroupDTO {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConsumerGroupDTO{" +
|
||||
return "ConsumerGroup{" +
|
||||
"clusterId=" + clusterId +
|
||||
", consumerGroup='" + consumerGroup + '\'' +
|
||||
", appIdList=" + appIdList +
|
||||
", offsetStoreLocation=" + offsetStoreLocation +
|
||||
'}';
|
||||
}
|
||||
@@ -79,7 +58,7 @@ public class ConsumerGroupDTO {
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ConsumerGroupDTO that = (ConsumerGroupDTO) o;
|
||||
ConsumerGroup that = (ConsumerGroup) o;
|
||||
return clusterId.equals(that.clusterId)
|
||||
&& consumerGroup.equals(that.consumerGroup)
|
||||
&& offsetStoreLocation == that.offsetStoreLocation;
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.ao.consumer;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.bizenum.OffsetLocationEnum;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConsumerGroupSummary {
|
||||
private Long clusterId;
|
||||
|
||||
private String consumerGroup;
|
||||
|
||||
private OffsetLocationEnum offsetStoreLocation;
|
||||
|
||||
private List<String> appIdList;
|
||||
|
||||
private String state;
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
public void setClusterId(Long clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public String getConsumerGroup() {
|
||||
return consumerGroup;
|
||||
}
|
||||
|
||||
public void setConsumerGroup(String consumerGroup) {
|
||||
this.consumerGroup = consumerGroup;
|
||||
}
|
||||
|
||||
public OffsetLocationEnum getOffsetStoreLocation() {
|
||||
return offsetStoreLocation;
|
||||
}
|
||||
|
||||
public void setOffsetStoreLocation(OffsetLocationEnum offsetStoreLocation) {
|
||||
this.offsetStoreLocation = offsetStoreLocation;
|
||||
}
|
||||
|
||||
public List<String> getAppIdList() {
|
||||
return appIdList;
|
||||
}
|
||||
|
||||
public void setAppIdList(List<String> appIdList) {
|
||||
this.appIdList = appIdList;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConsumerGroupSummary{" +
|
||||
"clusterId=" + clusterId +
|
||||
", consumerGroup='" + consumerGroup + '\'' +
|
||||
", offsetStoreLocation=" + offsetStoreLocation +
|
||||
", appIdList=" + appIdList +
|
||||
", state='" + state + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.ao.topic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author arthur
|
||||
* @date 2018/09/03
|
||||
@@ -17,7 +19,7 @@ public class TopicBasicDTO {
|
||||
|
||||
private String description;
|
||||
|
||||
private String region;
|
||||
private List<String> regionNameList;
|
||||
|
||||
private Integer score;
|
||||
|
||||
@@ -83,12 +85,12 @@ public class TopicBasicDTO {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getRegion() {
|
||||
return region;
|
||||
public List<String> getRegionNameList() {
|
||||
return regionNameList;
|
||||
}
|
||||
|
||||
public void setRegion(String region) {
|
||||
this.region = region;
|
||||
public void setRegionNameList(List<String> regionNameList) {
|
||||
this.regionNameList = regionNameList;
|
||||
}
|
||||
|
||||
public Integer getScore() {
|
||||
@@ -164,7 +166,7 @@ public class TopicBasicDTO {
|
||||
", principals='" + principals + '\'' +
|
||||
", topicName='" + topicName + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", region='" + region + '\'' +
|
||||
", regionNameList='" + regionNameList + '\'' +
|
||||
", score=" + score +
|
||||
", topicCodeC='" + topicCodeC + '\'' +
|
||||
", partitionNum=" + partitionNum +
|
||||
|
||||
@@ -18,6 +18,8 @@ public class TopicOverview {
|
||||
|
||||
private Object byteIn;
|
||||
|
||||
private Object byteOut;
|
||||
|
||||
private Object produceRequest;
|
||||
|
||||
private String appName;
|
||||
@@ -78,6 +80,14 @@ public class TopicOverview {
|
||||
this.byteIn = byteIn;
|
||||
}
|
||||
|
||||
public Object getByteOut() {
|
||||
return byteOut;
|
||||
}
|
||||
|
||||
public void setByteOut(Object byteOut) {
|
||||
this.byteOut = byteOut;
|
||||
}
|
||||
|
||||
public Object getProduceRequest() {
|
||||
return produceRequest;
|
||||
}
|
||||
@@ -135,6 +145,7 @@ public class TopicOverview {
|
||||
", partitionNum=" + partitionNum +
|
||||
", retentionTime=" + retentionTime +
|
||||
", byteIn=" + byteIn +
|
||||
", byteOut=" + byteOut +
|
||||
", produceRequest=" + produceRequest +
|
||||
", appName='" + appName + '\'' +
|
||||
", appId='" + appId + '\'' +
|
||||
|
||||
@@ -25,7 +25,10 @@ public class RebalanceDTO {
|
||||
@ApiModelProperty(value = "TopicName")
|
||||
private String topicName;
|
||||
|
||||
@ApiModelProperty(value = "维度[0: Cluster维度, 1: Region维度, 2:Broker维度, 3:Topic维度]")
|
||||
@ApiModelProperty(value = "分区ID")
|
||||
private Integer partitionId;
|
||||
|
||||
@ApiModelProperty(value = "维度[0: Cluster维度, 1: Region维度, 2:Broker维度, 3:Topic维度, 4:Partition纬度]")
|
||||
private Integer dimension;
|
||||
|
||||
public Long getClusterId() {
|
||||
@@ -60,6 +63,14 @@ public class RebalanceDTO {
|
||||
this.topicName = topicName;
|
||||
}
|
||||
|
||||
public Integer getPartitionId() {
|
||||
return partitionId;
|
||||
}
|
||||
|
||||
public void setPartitionId(Integer partitionId) {
|
||||
this.partitionId = partitionId;
|
||||
}
|
||||
|
||||
public Integer getDimension() {
|
||||
return dimension;
|
||||
}
|
||||
@@ -68,22 +79,12 @@ public class RebalanceDTO {
|
||||
this.dimension = dimension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RebalanceDTO{" +
|
||||
"clusterId=" + clusterId +
|
||||
", regionId=" + regionId +
|
||||
", brokerId=" + brokerId +
|
||||
", topicName='" + topicName + '\'' +
|
||||
", dimension=" + dimension +
|
||||
'}';
|
||||
}
|
||||
|
||||
public boolean paramLegal() {
|
||||
if (ValidateUtils.isNull(clusterId)
|
||||
|| RebalanceDimensionEnum.REGION.getCode().equals(dimension) && ValidateUtils.isNull(regionId)
|
||||
|| RebalanceDimensionEnum.BROKER.getCode().equals(dimension) && ValidateUtils.isNull(brokerId)
|
||||
|| RebalanceDimensionEnum.TOPIC.getCode().equals(dimension) && ValidateUtils.isNull(topicName) ) {
|
||||
|| (RebalanceDimensionEnum.REGION.getCode().equals(dimension) && ValidateUtils.isNull(regionId))
|
||||
|| (RebalanceDimensionEnum.BROKER.getCode().equals(dimension) && ValidateUtils.isNull(brokerId))
|
||||
|| (RebalanceDimensionEnum.TOPIC.getCode().equals(dimension) && ValidateUtils.isNull(topicName))
|
||||
|| (RebalanceDimensionEnum.PARTITION.getCode().equals(dimension) && (ValidateUtils.isNull(topicName) || ValidateUtils.isNull(partitionId))) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -27,9 +27,12 @@ public class ClusterDTO {
|
||||
@ApiModelProperty(value="数据中心")
|
||||
private String idc;
|
||||
|
||||
@ApiModelProperty(value="安全配置参数")
|
||||
@ApiModelProperty(value="Kafka安全配置")
|
||||
private String securityProperties;
|
||||
|
||||
@ApiModelProperty(value="Jmx配置")
|
||||
private String jmxProperties;
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
@@ -78,6 +81,14 @@ public class ClusterDTO {
|
||||
this.securityProperties = securityProperties;
|
||||
}
|
||||
|
||||
public String getJmxProperties() {
|
||||
return jmxProperties;
|
||||
}
|
||||
|
||||
public void setJmxProperties(String jmxProperties) {
|
||||
this.jmxProperties = jmxProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterDTO{" +
|
||||
@@ -87,6 +98,7 @@ public class ClusterDTO {
|
||||
", bootstrapServers='" + bootstrapServers + '\'' +
|
||||
", idc='" + idc + '\'' +
|
||||
", securityProperties='" + securityProperties + '\'' +
|
||||
", jmxProperties='" + jmxProperties + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.dto.rd;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.xiaojukeji.kafka.manager.common.bizenum.ClusterModeEnum;
|
||||
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@@ -20,6 +21,9 @@ public class LogicalClusterDTO {
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "集群标识, 用于告警的上报")
|
||||
private String identification;
|
||||
|
||||
@ApiModelProperty(value = "集群模式")
|
||||
private Integer mode;
|
||||
|
||||
@@ -51,6 +55,14 @@ public class LogicalClusterDTO {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getIdentification() {
|
||||
return identification;
|
||||
}
|
||||
|
||||
public void setIdentification(String identification) {
|
||||
this.identification = identification;
|
||||
}
|
||||
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
@@ -96,6 +108,7 @@ public class LogicalClusterDTO {
|
||||
return "LogicalClusterDTO{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", identification='" + identification + '\'' +
|
||||
", mode=" + mode +
|
||||
", clusterId=" + clusterId +
|
||||
", regionIdList=" + regionIdList +
|
||||
@@ -108,11 +121,15 @@ public class LogicalClusterDTO {
|
||||
if (ValidateUtils.isNull(clusterId)
|
||||
|| ValidateUtils.isNull(clusterId)
|
||||
|| ValidateUtils.isEmptyList(regionIdList)
|
||||
|| ValidateUtils.isNull(appId)
|
||||
|| ValidateUtils.isNull(mode)) {
|
||||
return false;
|
||||
}
|
||||
if (!ClusterModeEnum.SHARED_MODE.getCode().equals(mode) && ValidateUtils.isNull(appId)) {
|
||||
return false;
|
||||
}
|
||||
appId = ValidateUtils.isNull(appId)? "": appId;
|
||||
description = ValidateUtils.isNull(description)? "": description;
|
||||
identification = ValidateUtils.isNull(identification)? name: identification;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.metrics;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zengqiao
|
||||
* @date 20/6/17
|
||||
@@ -11,6 +13,8 @@ public class TopicMetrics extends BaseMetrics {
|
||||
|
||||
private String topicName;
|
||||
|
||||
private List<BrokerMetrics> brokerMetricsList;
|
||||
|
||||
public TopicMetrics(Long clusterId, String topicName) {
|
||||
super();
|
||||
this.clusterId = clusterId;
|
||||
@@ -24,6 +28,14 @@ public class TopicMetrics extends BaseMetrics {
|
||||
this.topicName = topicName;
|
||||
}
|
||||
|
||||
public TopicMetrics(String appId, Long clusterId, String topicName, List<BrokerMetrics> brokerMetricsList) {
|
||||
super();
|
||||
this.appId = appId;
|
||||
this.clusterId = clusterId;
|
||||
this.topicName = topicName;
|
||||
this.brokerMetricsList = brokerMetricsList;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
@@ -36,6 +48,14 @@ public class TopicMetrics extends BaseMetrics {
|
||||
return topicName;
|
||||
}
|
||||
|
||||
public void setBrokerMetricsList(List<BrokerMetrics> brokerMetricsList) {
|
||||
this.brokerMetricsList = brokerMetricsList;
|
||||
}
|
||||
|
||||
public List<BrokerMetrics> getBrokerMetricsList() {
|
||||
return brokerMetricsList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TopicMetrics{" +
|
||||
|
||||
@@ -17,6 +17,8 @@ public class ClusterDO implements Comparable<ClusterDO> {
|
||||
|
||||
private String securityProperties;
|
||||
|
||||
private String jmxProperties;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Date gmtCreate;
|
||||
@@ -31,30 +33,6 @@ public class ClusterDO implements Comparable<ClusterDO> {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModify() {
|
||||
return gmtModify;
|
||||
}
|
||||
|
||||
public void setGmtModify(Date gmtModify) {
|
||||
this.gmtModify = gmtModify;
|
||||
}
|
||||
|
||||
public String getClusterName() {
|
||||
return clusterName;
|
||||
}
|
||||
@@ -87,6 +65,38 @@ public class ClusterDO implements Comparable<ClusterDO> {
|
||||
this.securityProperties = securityProperties;
|
||||
}
|
||||
|
||||
public String getJmxProperties() {
|
||||
return jmxProperties;
|
||||
}
|
||||
|
||||
public void setJmxProperties(String jmxProperties) {
|
||||
this.jmxProperties = jmxProperties;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Date getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(Date gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Date getGmtModify() {
|
||||
return gmtModify;
|
||||
}
|
||||
|
||||
public void setGmtModify(Date gmtModify) {
|
||||
this.gmtModify = gmtModify;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClusterDO{" +
|
||||
@@ -95,6 +105,7 @@ public class ClusterDO implements Comparable<ClusterDO> {
|
||||
", zookeeper='" + zookeeper + '\'' +
|
||||
", bootstrapServers='" + bootstrapServers + '\'' +
|
||||
", securityProperties='" + securityProperties + '\'' +
|
||||
", jmxProperties='" + jmxProperties + '\'' +
|
||||
", status=" + status +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModify=" + gmtModify +
|
||||
|
||||
@@ -11,6 +11,8 @@ public class LogicalClusterDO {
|
||||
|
||||
private String name;
|
||||
|
||||
private String identification;
|
||||
|
||||
private Integer mode;
|
||||
|
||||
private String appId;
|
||||
@@ -41,6 +43,14 @@ public class LogicalClusterDO {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getIdentification() {
|
||||
return identification;
|
||||
}
|
||||
|
||||
public void setIdentification(String identification) {
|
||||
this.identification = identification;
|
||||
}
|
||||
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
@@ -102,6 +112,7 @@ public class LogicalClusterDO {
|
||||
return "LogicalClusterDO{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", identification='" + identification + '\'' +
|
||||
", mode=" + mode +
|
||||
", appId='" + appId + '\'' +
|
||||
", clusterId=" + clusterId +
|
||||
|
||||
@@ -28,6 +28,9 @@ public class TopicOverviewVO {
|
||||
@ApiModelProperty(value = "每秒流入流量(B)")
|
||||
private Object byteIn;
|
||||
|
||||
@ApiModelProperty(value = "每秒流出流量(B)")
|
||||
private Object byteOut;
|
||||
|
||||
@ApiModelProperty(value = "发送请求数(个/秒)")
|
||||
private Object produceRequest;
|
||||
|
||||
@@ -94,6 +97,14 @@ public class TopicOverviewVO {
|
||||
this.byteIn = byteIn;
|
||||
}
|
||||
|
||||
public Object getByteOut() {
|
||||
return byteOut;
|
||||
}
|
||||
|
||||
public void setByteOut(Object byteOut) {
|
||||
this.byteOut = byteOut;
|
||||
}
|
||||
|
||||
public Object getProduceRequest() {
|
||||
return produceRequest;
|
||||
}
|
||||
@@ -151,6 +162,7 @@ public class TopicOverviewVO {
|
||||
", partitionNum=" + partitionNum +
|
||||
", retentionTime=" + retentionTime +
|
||||
", byteIn=" + byteIn +
|
||||
", byteOut=" + byteOut +
|
||||
", produceRequest=" + produceRequest +
|
||||
", appName='" + appName + '\'' +
|
||||
", appId='" + appId + '\'' +
|
||||
|
||||
@@ -15,6 +15,9 @@ public class LogicClusterVO {
|
||||
@ApiModelProperty(value="逻辑集群名称")
|
||||
private String clusterName;
|
||||
|
||||
@ApiModelProperty(value="逻辑标识")
|
||||
private String clusterIdentification;
|
||||
|
||||
@ApiModelProperty(value="逻辑集群类型, 0:共享集群, 1:独享集群, 2:独立集群")
|
||||
private Integer mode;
|
||||
|
||||
@@ -24,9 +27,6 @@ public class LogicClusterVO {
|
||||
@ApiModelProperty(value="集群版本")
|
||||
private String clusterVersion;
|
||||
|
||||
@ApiModelProperty(value="物理集群ID")
|
||||
private Long physicalClusterId;
|
||||
|
||||
@ApiModelProperty(value="集群服务地址")
|
||||
private String bootstrapServers;
|
||||
|
||||
@@ -55,6 +55,22 @@ public class LogicClusterVO {
|
||||
this.clusterName = clusterName;
|
||||
}
|
||||
|
||||
public String getClusterIdentification() {
|
||||
return clusterIdentification;
|
||||
}
|
||||
|
||||
public void setClusterIdentification(String clusterIdentification) {
|
||||
this.clusterIdentification = clusterIdentification;
|
||||
}
|
||||
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(Integer mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public Integer getTopicNum() {
|
||||
return topicNum;
|
||||
}
|
||||
@@ -71,14 +87,6 @@ public class LogicClusterVO {
|
||||
this.clusterVersion = clusterVersion;
|
||||
}
|
||||
|
||||
public Long getPhysicalClusterId() {
|
||||
return physicalClusterId;
|
||||
}
|
||||
|
||||
public void setPhysicalClusterId(Long physicalClusterId) {
|
||||
this.physicalClusterId = physicalClusterId;
|
||||
}
|
||||
|
||||
public String getBootstrapServers() {
|
||||
return bootstrapServers;
|
||||
}
|
||||
@@ -87,6 +95,14 @@ public class LogicClusterVO {
|
||||
this.bootstrapServers = bootstrapServers;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Long getGmtCreate() {
|
||||
return gmtCreate;
|
||||
}
|
||||
@@ -103,32 +119,15 @@ public class LogicClusterVO {
|
||||
this.gmtModify = gmtModify;
|
||||
}
|
||||
|
||||
public Integer getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(Integer mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LogicClusterVO{" +
|
||||
"clusterId=" + clusterId +
|
||||
", clusterName='" + clusterName + '\'' +
|
||||
", clusterIdentification='" + clusterIdentification + '\'' +
|
||||
", mode=" + mode +
|
||||
", topicNum=" + topicNum +
|
||||
", clusterVersion='" + clusterVersion + '\'' +
|
||||
", physicalClusterId=" + physicalClusterId +
|
||||
", bootstrapServers='" + bootstrapServers + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.vo.normal.consumer;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zengqiao
|
||||
* @date 21/01/14
|
||||
*/
|
||||
@ApiModel(value = "Topic消费组概要信息")
|
||||
public class ConsumerGroupSummaryVO {
|
||||
@ApiModelProperty(value = "消费组名称")
|
||||
private String consumerGroup;
|
||||
|
||||
@ApiModelProperty(value = "使用的AppID")
|
||||
private String appIds;
|
||||
|
||||
@ApiModelProperty(value = "offset存储位置")
|
||||
private String location;
|
||||
|
||||
@ApiModelProperty(value = "消费组状态")
|
||||
private String state;
|
||||
|
||||
public String getConsumerGroup() {
|
||||
return consumerGroup;
|
||||
}
|
||||
|
||||
public void setConsumerGroup(String consumerGroup) {
|
||||
this.consumerGroup = consumerGroup;
|
||||
}
|
||||
|
||||
public String getAppIds() {
|
||||
return appIds;
|
||||
}
|
||||
|
||||
public void setAppIds(String appIds) {
|
||||
this.appIds = appIds;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConsumerGroupSummaryVO{" +
|
||||
"consumerGroup='" + consumerGroup + '\'' +
|
||||
", appIds=" + appIds +
|
||||
", location='" + location + '\'' +
|
||||
", state='" + state + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Topic的基本信息
|
||||
* @author zengqiao
|
||||
@@ -49,6 +51,9 @@ public class TopicBasicVO {
|
||||
@ApiModelProperty(value = "集群地址")
|
||||
private String bootstrapServers;
|
||||
|
||||
@ApiModelProperty(value = "所属region")
|
||||
private List<String> regionNameList;
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
@@ -153,6 +158,14 @@ public class TopicBasicVO {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public List<String> getRegionNameList() {
|
||||
return regionNameList;
|
||||
}
|
||||
|
||||
public void setRegionNameList(List<String> regionNameList) {
|
||||
this.regionNameList = regionNameList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TopicBasicVO{" +
|
||||
@@ -169,6 +182,7 @@ public class TopicBasicVO {
|
||||
", topicCodeC='" + topicCodeC + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", bootstrapServers='" + bootstrapServers + '\'' +
|
||||
", regionNameList=" + regionNameList +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic;
|
||||
|
||||
/**
|
||||
* author: mrazkonglingxu
|
||||
* Date: 2020/12/7
|
||||
* Time: 7:40 下午
|
||||
*/
|
||||
public class TopicBrokerRequestTimeVO {
|
||||
|
||||
private Long clusterId;
|
||||
|
||||
private Integer brokerId;
|
||||
|
||||
private TopicRequestTimeDetailVO brokerRequestTime;
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
public void setClusterId(Long clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public Integer getBrokerId() {
|
||||
return brokerId;
|
||||
}
|
||||
|
||||
public void setBrokerId(Integer brokerId) {
|
||||
this.brokerId = brokerId;
|
||||
}
|
||||
|
||||
public TopicRequestTimeDetailVO getBrokerRequestTime() {
|
||||
return brokerRequestTime;
|
||||
}
|
||||
|
||||
public void setBrokerRequestTime(TopicRequestTimeDetailVO brokerRequestTime) {
|
||||
this.brokerRequestTime = brokerRequestTime;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.xiaojukeji.kafka.manager.common.entity.vo.normal.topic;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zengqiao
|
||||
* @date 20/4/8
|
||||
@@ -33,6 +35,8 @@ public class TopicRequestTimeDetailVO {
|
||||
@ApiModelProperty(value = "totalTimeMs")
|
||||
private Object totalTimeMs;
|
||||
|
||||
private List<TopicBrokerRequestTimeVO> brokerRequestTimeList;
|
||||
|
||||
public String getRequestTimeType() {
|
||||
return requestTimeType;
|
||||
}
|
||||
@@ -97,6 +101,14 @@ public class TopicRequestTimeDetailVO {
|
||||
this.totalTimeMs = totalTimeMs;
|
||||
}
|
||||
|
||||
public List<TopicBrokerRequestTimeVO> getBrokerRequestTimeList() {
|
||||
return brokerRequestTimeList;
|
||||
}
|
||||
|
||||
public void setBrokerRequestTimeList(List<TopicBrokerRequestTimeVO> brokerRequestTimeList) {
|
||||
this.brokerRequestTimeList = brokerRequestTimeList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TopicRequestTimeDetailVO{" +
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.vo.rd;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author zengqiao
|
||||
* @date 20/3/19
|
||||
*/
|
||||
@ApiModel(value = "GatewayConfigVO", description = "Gateway配置信息")
|
||||
public class GatewayConfigVO {
|
||||
@ApiModelProperty(value="ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value="配置类型")
|
||||
private String type;
|
||||
|
||||
@ApiModelProperty(value="配置名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value="配置值")
|
||||
private String value;
|
||||
|
||||
@ApiModelProperty(value="版本")
|
||||
private Long version;
|
||||
|
||||
@ApiModelProperty(value="创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty(value="修改时间")
|
||||
private Date modifyTime;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public Date getModifyTime() {
|
||||
return modifyTime;
|
||||
}
|
||||
|
||||
public void setModifyTime(Date modifyTime) {
|
||||
this.modifyTime = modifyTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GatewayConfigVO{" +
|
||||
"id=" + id +
|
||||
", type='" + type + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", value='" + value + '\'' +
|
||||
", version=" + version +
|
||||
", createTime=" + createTime +
|
||||
", modifyTime=" + modifyTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.xiaojukeji.kafka.manager.common.entity.vo.rd;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,9 @@ public class RdTopicBasicVO {
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String description;
|
||||
|
||||
@ApiModelProperty(value = "所属region")
|
||||
private List<String> regionNameList;
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
@@ -99,6 +103,14 @@ public class RdTopicBasicVO {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public List<String> getRegionNameList() {
|
||||
return regionNameList;
|
||||
}
|
||||
|
||||
public void setRegionNameList(List<String> regionNameList) {
|
||||
this.regionNameList = regionNameList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RdTopicBasicVO{" +
|
||||
@@ -110,6 +122,7 @@ public class RdTopicBasicVO {
|
||||
", appName='" + appName + '\'' +
|
||||
", properties=" + properties +
|
||||
", description='" + description + '\'' +
|
||||
", regionNameList='" + regionNameList + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,12 @@ public class ClusterBaseVO {
|
||||
@ApiModelProperty(value="集群类型")
|
||||
private Integer mode;
|
||||
|
||||
@ApiModelProperty(value="安全配置参数")
|
||||
@ApiModelProperty(value="Kafka安全配置")
|
||||
private String securityProperties;
|
||||
|
||||
@ApiModelProperty(value="Jmx配置")
|
||||
private String jmxProperties;
|
||||
|
||||
@ApiModelProperty(value="1:监控中, 0:暂停监控")
|
||||
private Integer status;
|
||||
|
||||
@@ -108,6 +111,14 @@ public class ClusterBaseVO {
|
||||
this.securityProperties = securityProperties;
|
||||
}
|
||||
|
||||
public String getJmxProperties() {
|
||||
return jmxProperties;
|
||||
}
|
||||
|
||||
public void setJmxProperties(String jmxProperties) {
|
||||
this.jmxProperties = jmxProperties;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
@@ -141,8 +152,9 @@ public class ClusterBaseVO {
|
||||
", bootstrapServers='" + bootstrapServers + '\'' +
|
||||
", kafkaVersion='" + kafkaVersion + '\'' +
|
||||
", idc='" + idc + '\'' +
|
||||
", mode='" + mode + '\'' +
|
||||
", mode=" + mode +
|
||||
", securityProperties='" + securityProperties + '\'' +
|
||||
", jmxProperties='" + jmxProperties + '\'' +
|
||||
", status=" + status +
|
||||
", gmtCreate=" + gmtCreate +
|
||||
", gmtModify=" + gmtModify +
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.xiaojukeji.kafka.manager.common.entity.vo.rd.cluster;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ApiModel(description = "Broker基本信息")
|
||||
public class ControllerPreferredCandidateVO {
|
||||
@ApiModelProperty(value = "brokerId")
|
||||
private Integer brokerId;
|
||||
|
||||
@ApiModelProperty(value = "主机名")
|
||||
private String host;
|
||||
|
||||
@ApiModelProperty(value = "启动时间")
|
||||
private Long startTime;
|
||||
|
||||
@ApiModelProperty(value = "broker状态[0:在线, -1:不在线]")
|
||||
private Integer status;
|
||||
|
||||
public Integer getBrokerId() {
|
||||
return brokerId;
|
||||
}
|
||||
|
||||
public void setBrokerId(Integer brokerId) {
|
||||
this.brokerId = brokerId;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public Long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(Long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ControllerPreferredBrokerVO{" +
|
||||
"brokerId=" + brokerId +
|
||||
", host='" + host + '\'' +
|
||||
", startTime=" + startTime +
|
||||
", status=" + status +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,9 @@ public class LogicalClusterVO {
|
||||
@ApiModelProperty(value = "逻辑集群名称")
|
||||
private String logicalClusterName;
|
||||
|
||||
@ApiModelProperty(value = "逻辑集群标识")
|
||||
private String logicalClusterIdentification;
|
||||
|
||||
@ApiModelProperty(value = "物理集群ID")
|
||||
private Long physicalClusterId;
|
||||
|
||||
@@ -55,6 +58,14 @@ public class LogicalClusterVO {
|
||||
this.logicalClusterName = logicalClusterName;
|
||||
}
|
||||
|
||||
public String getLogicalClusterIdentification() {
|
||||
return logicalClusterIdentification;
|
||||
}
|
||||
|
||||
public void setLogicalClusterIdentification(String logicalClusterIdentification) {
|
||||
this.logicalClusterIdentification = logicalClusterIdentification;
|
||||
}
|
||||
|
||||
public Long getPhysicalClusterId() {
|
||||
return physicalClusterId;
|
||||
}
|
||||
@@ -116,6 +127,7 @@ public class LogicalClusterVO {
|
||||
return "LogicalClusterVO{" +
|
||||
"logicalClusterId=" + logicalClusterId +
|
||||
", logicalClusterName='" + logicalClusterName + '\'' +
|
||||
", logicalClusterIdentification='" + logicalClusterIdentification + '\'' +
|
||||
", physicalClusterId=" + physicalClusterId +
|
||||
", regionIdList=" + regionIdList +
|
||||
", mode=" + mode +
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.xiaojukeji.kafka.manager.common.entity.pojo.gateway.TopicConnectionDO
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,14 @@ public class JsonUtils {
|
||||
return JSON.toJSONString(obj);
|
||||
}
|
||||
|
||||
public static List<TopicConnectionDO> parseTopicConnections(Long clusterId, JSONObject jsonObject) {
|
||||
public static <T> T stringToObj(String src, Class<T> clazz) {
|
||||
if (ValidateUtils.isBlank(src)) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parseObject(src, clazz);
|
||||
}
|
||||
|
||||
public static List<TopicConnectionDO> parseTopicConnections(Long clusterId, JSONObject jsonObject, long postTime) {
|
||||
List<TopicConnectionDO> connectionDOList = new ArrayList<>();
|
||||
for (String clientType: jsonObject.keySet()) {
|
||||
JSONObject topicObject = jsonObject.getJSONObject(clientType);
|
||||
@@ -64,7 +72,7 @@ public class JsonUtils {
|
||||
TopicConnectionDO connectionDO = new TopicConnectionDO();
|
||||
|
||||
String[] appIdDetailArray = appIdDetail.toString().split("#");
|
||||
if (appIdDetailArray.length == 3) {
|
||||
if (appIdDetailArray.length >= 3) {
|
||||
connectionDO.setAppId(appIdDetailArray[0]);
|
||||
connectionDO.setIp(appIdDetailArray[1]);
|
||||
connectionDO.setClientVersion(appIdDetailArray[2]);
|
||||
@@ -73,6 +81,7 @@ public class JsonUtils {
|
||||
connectionDO.setClusterId(clusterId);
|
||||
connectionDO.setTopicName(topicName);
|
||||
connectionDO.setType(clientType);
|
||||
connectionDO.setCreateTime(new Date(postTime));
|
||||
connectionDOList.add(connectionDO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.xiaojukeji.kafka.manager.common.utils;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.bizenum.IDCEnum;
|
||||
import com.xiaojukeji.kafka.manager.common.constant.TopicCreationConstant;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
@@ -83,23 +81,4 @@ public class ValidateUtils {
|
||||
public static boolean isNullOrLessThanZero(Double value) {
|
||||
return value == null || value < 0;
|
||||
}
|
||||
|
||||
public static boolean topicNameLegal(String idc, String topicName) {
|
||||
if (ValidateUtils.isNull(idc) || ValidateUtils.isNull(topicName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验Topic的长度
|
||||
if (topicName.length() >= TopicCreationConstant.TOPIC_NAME_MAX_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验前缀
|
||||
if (IDCEnum.CN.getIdc().equals(idc) ||
|
||||
(IDCEnum.US.getIdc().equals(idc) && topicName.startsWith(TopicCreationConstant.TOPIC_NAME_PREFIX_US)) ||
|
||||
(IDCEnum.RU.getIdc().equals(idc) && topicName.startsWith(TopicCreationConstant.TOPIC_NAME_PREFIX_RU))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.xiaojukeji.kafka.manager.common.utils.jmx;
|
||||
|
||||
public class JmxConfig {
|
||||
/**
|
||||
* 单台最大连接数
|
||||
*/
|
||||
private Integer maxConn;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 开启SSL
|
||||
*/
|
||||
private Boolean openSSL;
|
||||
|
||||
public Integer getMaxConn() {
|
||||
return maxConn;
|
||||
}
|
||||
|
||||
public void setMaxConn(Integer maxConn) {
|
||||
this.maxConn = maxConn;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Boolean isOpenSSL() {
|
||||
return openSSL;
|
||||
}
|
||||
|
||||
public void setOpenSSL(Boolean openSSL) {
|
||||
this.openSSL = openSSL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JmxConfig{" +
|
||||
"maxConn=" + maxConn +
|
||||
", username='" + username + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", openSSL=" + openSSL +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.xiaojukeji.kafka.manager.common.utils.jmx;
|
||||
|
||||
import com.xiaojukeji.kafka.manager.common.utils.ValidateUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -7,8 +8,14 @@ import javax.management.*;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnectorServer;
|
||||
import javax.naming.Context;
|
||||
import javax.rmi.ssl.SslRMIClientSocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@@ -28,13 +35,19 @@ public class JmxConnectorWrap {
|
||||
|
||||
private AtomicInteger atomicInteger;
|
||||
|
||||
public JmxConnectorWrap(String host, int port, int maxConn) {
|
||||
private JmxConfig jmxConfig;
|
||||
|
||||
public JmxConnectorWrap(String host, int port, JmxConfig jmxConfig) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
if (maxConn <= 0) {
|
||||
maxConn = 1;
|
||||
this.jmxConfig = jmxConfig;
|
||||
if (ValidateUtils.isNull(this.jmxConfig)) {
|
||||
this.jmxConfig = new JmxConfig();
|
||||
}
|
||||
this.atomicInteger = new AtomicInteger(maxConn);
|
||||
if (ValidateUtils.isNullOrLessThanZero(this.jmxConfig.getMaxConn())) {
|
||||
this.jmxConfig.setMaxConn(1);
|
||||
}
|
||||
this.atomicInteger = new AtomicInteger(this.jmxConfig.getMaxConn());
|
||||
}
|
||||
|
||||
public boolean checkJmxConnectionAndInitIfNeed() {
|
||||
@@ -64,8 +77,18 @@ public class JmxConnectorWrap {
|
||||
}
|
||||
String jmxUrl = String.format("service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi", host, port);
|
||||
try {
|
||||
JMXServiceURL url = new JMXServiceURL(jmxUrl);
|
||||
jmxConnector = JMXConnectorFactory.connect(url, null);
|
||||
Map<String, Object> environment = new HashMap<String, Object>();
|
||||
if (!ValidateUtils.isBlank(this.jmxConfig.getUsername()) && !ValidateUtils.isBlank(this.jmxConfig.getPassword())) {
|
||||
environment.put(javax.management.remote.JMXConnector.CREDENTIALS, Arrays.asList(this.jmxConfig.getUsername(), this.jmxConfig.getPassword()));
|
||||
}
|
||||
if (jmxConfig.isOpenSSL() != null && this.jmxConfig.isOpenSSL()) {
|
||||
environment.put(Context.SECURITY_PROTOCOL, "ssl");
|
||||
SslRMIClientSocketFactory clientSocketFactory = new SslRMIClientSocketFactory();
|
||||
environment.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, clientSocketFactory);
|
||||
environment.put("com.sun.jndi.rmi.factory.socket", clientSocketFactory);
|
||||
}
|
||||
|
||||
jmxConnector = JMXConnectorFactory.connect(new JMXServiceURL(jmxUrl), environment);
|
||||
LOGGER.info("JMX connect success, host:{} port:{}.", host, port);
|
||||
return true;
|
||||
} catch (MalformedURLException e) {
|
||||
|
||||
@@ -170,7 +170,10 @@ public class MbeanNameUtilV2 {
|
||||
new MbeanV2(
|
||||
"TopicCodeC",
|
||||
JmxAttributeEnum.VALUE_ATTRIBUTE,
|
||||
"kafka.server:type=ReplicaManager,name=TopicCodeC"
|
||||
Arrays.asList(
|
||||
new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_0_10_3, "kafka.server:type=ReplicaManager,name=TopicCodeC"),
|
||||
new AbstractMap.SimpleEntry<>(KafkaVersion.VERSION_MAX, "kafka.server:type=AppIdTopicMetrics,name=RecordCompression,appId=")
|
||||
)
|
||||
),
|
||||
Arrays.asList(
|
||||
KafkaMetricsCollections.TOPIC_BASIC_PAGE_METRICS
|
||||
|
||||
@@ -8,7 +8,7 @@ package com.xiaojukeji.kafka.manager.common.zookeeper;
|
||||
public class ZkPathUtil {
|
||||
private static final String ZOOKEEPER_SEPARATOR = "/";
|
||||
|
||||
private static final String BROKER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "brokers";
|
||||
public static final String BROKER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "brokers";
|
||||
|
||||
public static final String CONTROLLER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "controller";
|
||||
|
||||
@@ -18,6 +18,8 @@ public class ZkPathUtil {
|
||||
|
||||
public static final String CONSUMER_ROOT_NODE = ZOOKEEPER_SEPARATOR + "consumers";
|
||||
|
||||
public static final String REASSIGN_PARTITIONS_ROOT_NODE = "/admin/reassign_partitions";
|
||||
|
||||
/**
|
||||
* config
|
||||
*/
|
||||
@@ -27,11 +29,11 @@ public class ZkPathUtil {
|
||||
|
||||
public static final String CONFIG_CLIENTS_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "clients";
|
||||
|
||||
public static final String CONFIG_ENTITY_CHANGES_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "changes/config_change_";
|
||||
public static final String CONFIG_ENTITY_CHANGES_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "changes/config_change_";
|
||||
|
||||
public static final String REASSIGN_PARTITIONS_ROOT_NODE = "/admin/reassign_partitions";
|
||||
private static final String D_METRICS_CONFIG_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "KafkaExMetrics";
|
||||
|
||||
private static final String D_METRICS_CONFIG_ROOT_NODE = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "KafkaExMetrics";
|
||||
public static final String D_CONTROLLER_CANDIDATES = CONFIG_ROOT_NODE + ZOOKEEPER_SEPARATOR + "extension/candidates";
|
||||
|
||||
public static String getBrokerIdNodePath(Integer brokerId) {
|
||||
return BROKER_IDS_ROOT + ZOOKEEPER_SEPARATOR + String.valueOf(brokerId);
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
"mobx": "^5.9.4",
|
||||
"mobx-react": "^5.4.3",
|
||||
"moment": "^2.24.0",
|
||||
"monaco-editor": "^0.20.0",
|
||||
"monaco-editor-webpack-plugin": "^1.9.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.1",
|
||||
"react": "^16.8.4",
|
||||
"react-hot-loader": "^4.8.4",
|
||||
@@ -45,9 +47,13 @@
|
||||
"tslint": "^5.13.1",
|
||||
"tslint-react": "^3.6.0",
|
||||
"typescript": "^3.3.3333",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^4.29.6",
|
||||
"webpack-cli": "^3.2.3",
|
||||
"webpack-dev-server": "^3.2.1",
|
||||
"xlsx": "^0.16.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"format-to-json": "^1.0.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<artifactId>kafka-manager</artifactId>
|
||||
<groupId>com.xiaojukeji.kafka</groupId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<version>${kafka-manager.revision}</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
@@ -28,9 +28,10 @@
|
||||
<goal>install-node-and-npm</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<nodeVersion>v8.12.0</nodeVersion>
|
||||
<npmVersion>6.4.1</npmVersion>
|
||||
<nodeVersion>v12.20.0</nodeVersion>
|
||||
<npmVersion>6.14.8</npmVersion>
|
||||
<nodeDownloadRoot>http://npm.taobao.org/mirrors/node/</nodeDownloadRoot>
|
||||
<npmDownloadRoot>https://registry.npm.taobao.org/npm/-/</npmDownloadRoot>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
|
||||
@@ -48,6 +48,9 @@ import 'antd/es/notification/style';
|
||||
import Tooltip from 'antd/es/tooltip';
|
||||
import 'antd/es/tooltip/style';
|
||||
|
||||
import Popover from 'antd/es/popover';
|
||||
import 'antd/es/popover/style';
|
||||
|
||||
import Radio from 'antd/es/radio';
|
||||
import 'antd/es/radio';
|
||||
import { RadioChangeEvent } from 'antd/es/radio';
|
||||
@@ -97,6 +100,9 @@ import 'antd/es/time-picker/style';
|
||||
import Badge from 'antd/es/badge';
|
||||
import 'antd/es/badge/style';
|
||||
|
||||
import Progress from 'antd/es/progress';
|
||||
import 'antd/es/progress/style';
|
||||
|
||||
import { RangePickerValue } from 'antd/es/date-picker/interface';
|
||||
|
||||
export {
|
||||
@@ -136,4 +142,5 @@ export {
|
||||
TimePicker,
|
||||
RangePickerValue,
|
||||
Badge,
|
||||
Popover
|
||||
};
|
||||
|
||||
68
kafka-manager-console/src/component/editor/editor.tsx
Normal file
68
kafka-manager-console/src/component/editor/editor.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
// import * as React from 'react';
|
||||
// import CodeMirror from 'codemirror/lib/codemirror';
|
||||
// import 'codemirror/lib/codemirror.css';
|
||||
// import 'codemirror/mode/sql/sql';
|
||||
// import 'codemirror/mode/javascript/javascript';
|
||||
// import 'codemirror/addon/hint/show-hint.js';
|
||||
// import 'codemirror/addon/hint/sql-hint.js';
|
||||
// import 'codemirror/addon/hint/show-hint.css';
|
||||
// import './index.less';
|
||||
// import { indexStore } from 'store/my-index';
|
||||
|
||||
// interface IProps {
|
||||
// value?: string;
|
||||
// placeholder?: string;
|
||||
// readOnly?: boolean;
|
||||
// }
|
||||
// export class CodeMirrorEditor extends React.Component<IProps> {
|
||||
|
||||
// public editor = null as any;
|
||||
|
||||
// public handleCodeFocus = () => {
|
||||
// // tslint:disable-next-line:no-unused-expression
|
||||
// this.editor && this.editor.focus();
|
||||
// }
|
||||
|
||||
// public componentDidMount() {
|
||||
// const { value, placeholder, readOnly } = this.props;
|
||||
// const code = document.querySelector('.codemirror');
|
||||
// code.innerHTML = '';
|
||||
// const editor = CodeMirror(document.querySelector('.codemirror'), {
|
||||
// mode: 'application/json',
|
||||
// indentWithTabs: true,
|
||||
// smartIndent: true,
|
||||
// lineNumbers: true,
|
||||
// matchBrackets: true,
|
||||
// autoCloseBrackets: true,
|
||||
// styleSelectedText: true,
|
||||
// foldGutter: true,
|
||||
// readOnly,
|
||||
// extraKeys: readOnly ? {} : {
|
||||
// 'Ctrl-Enter': 'autocomplete',
|
||||
// 'Tab': (cm) => {
|
||||
// const spaces = Array(cm.getOption('indentUnit') + 1).join(' ');
|
||||
// cm.replaceSelection(spaces);
|
||||
// },
|
||||
// },
|
||||
// placeholder,
|
||||
// });
|
||||
// editor.setValue(value || '');
|
||||
// indexStore.setCodeEditorValue(value || '');
|
||||
// editor.on('changes', (a: any) => {
|
||||
// const data = a.getValue();
|
||||
// indexStore.setCodeEditorValue(data);
|
||||
// });
|
||||
// this.editor = editor;
|
||||
// }
|
||||
|
||||
// public render() {
|
||||
// return (
|
||||
// <div
|
||||
// className="editor-wrap"
|
||||
// onClick={this.handleCodeFocus}
|
||||
// >
|
||||
// <div className="codemirror" />
|
||||
// </div >
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
31
kafka-manager-console/src/component/editor/index.less
Normal file
31
kafka-manager-console/src/component/editor/index.less
Normal file
@@ -0,0 +1,31 @@
|
||||
.editor {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror-placeholder {
|
||||
color:#999;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
font-family: -apple-system,BlinkMacSystemFont,Neue Haas Grotesk Text Pro,Arial Nova,Segoe UI,Helvetica Neue,\.PingFang SC,PingFang SC,Microsoft YaHei,Microsoft JhengHei,Source Han Sans SC,Noto Sans CJK SC,Source Han Sans CN,Noto Sans SC,Source Han Sans TC,Noto Sans CJK TC,Hiragino Sans GB,sans-serif;
|
||||
}
|
||||
.editor-wrap {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.monacoEditor{
|
||||
height: 150px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid #cccccc;
|
||||
border-radius: 4px;
|
||||
.editor{
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: -14%;
|
||||
width: 120%;
|
||||
}
|
||||
}
|
||||
50
kafka-manager-console/src/component/editor/index.tsx
Normal file
50
kafka-manager-console/src/component/editor/index.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as React from 'react';
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
import './index.less';
|
||||
|
||||
export interface IEditorProps {
|
||||
style?: React.CSSProperties;
|
||||
options: monaco.editor.IStandaloneEditorConstructionOptions;
|
||||
uri?: monaco.Uri;
|
||||
autoUnmount?: boolean;
|
||||
customMount?: (editor: monaco.editor.IStandaloneCodeEditor, monaco: any) => any;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export class EditorCom extends React.Component<IEditorProps> {
|
||||
public ref: HTMLElement = null;
|
||||
public editor: monaco.editor.IStandaloneCodeEditor;
|
||||
public state = {
|
||||
placeholder: this.props.placeholder ?? '',
|
||||
};
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (this.props.autoUnmount === false) return;
|
||||
const model = this.editor.getModel();
|
||||
model.dispose();
|
||||
this.editor.dispose();
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
const { customMount, options, uri } = this.props;
|
||||
const { value, language } = options;
|
||||
if (uri) {
|
||||
options.model = monaco.editor.createModel(value, language, uri);
|
||||
}
|
||||
|
||||
this.editor = monaco.editor.create(this.ref,
|
||||
options,
|
||||
);
|
||||
if (customMount) customMount(this.editor, monaco);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { style } = this.props;
|
||||
return (
|
||||
<>
|
||||
<div style={style} className="editor" ref={(id) => { this.ref = id; }} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
77
kafka-manager-console/src/component/editor/monacoEditor.tsx
Normal file
77
kafka-manager-console/src/component/editor/monacoEditor.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import * as React from 'react';
|
||||
import * as monaco from 'monaco-editor';
|
||||
import format2json from 'format-to-json';
|
||||
import { Input } from 'component/antd';
|
||||
import './index.less';
|
||||
|
||||
export interface IEditorProps {
|
||||
style?: React.CSSProperties;
|
||||
options: monaco.editor.IStandaloneEditorConstructionOptions;
|
||||
uri?: monaco.Uri;
|
||||
autoUnmount?: boolean;
|
||||
customMount?: (editor: monaco.editor.IStandaloneCodeEditor, monaco: any) => any;
|
||||
placeholder?: string;
|
||||
value: '';
|
||||
onChange?: any;
|
||||
}
|
||||
|
||||
class Monacoeditor extends React.Component<IEditorProps> {
|
||||
public ref: HTMLElement = null;
|
||||
public editor: monaco.editor.IStandaloneCodeEditor;
|
||||
public state = {
|
||||
placeholder: '',
|
||||
};
|
||||
// public arr = '{"clusterId":95,"startId":37397856,"step":100,"topicName":"kmo_topic_metrics_tempory_zq"}';
|
||||
// public Ars(a: string) {
|
||||
// const obj = JSON.parse(a);
|
||||
// const newobj: any = {};
|
||||
// for (const item in obj) {
|
||||
// if (typeof obj[item] === 'object') {
|
||||
// this.Ars(obj[item]);
|
||||
// } else {
|
||||
// newobj[item] = obj[item];
|
||||
// }
|
||||
// }
|
||||
// return JSON.stringify(newobj);
|
||||
// }
|
||||
public async componentDidMount() {
|
||||
const { value, onChange } = this.props;
|
||||
const format: any = await format2json(value);
|
||||
this.editor = monaco.editor.create(this.ref, {
|
||||
value: format.result,
|
||||
language: 'json',
|
||||
lineNumbers: 'off',
|
||||
scrollBeyondLastLine: false,
|
||||
// selectOnLineNumbers: true,
|
||||
// roundedSelection: false,
|
||||
// readOnly: true,
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
// automaticLayout: true, // 自动布局
|
||||
glyphMargin: true, // 字形边缘 {},[]
|
||||
// useTabStops: false,
|
||||
// formatOnPaste: true,
|
||||
// mode: 'application/json',
|
||||
// indentWithTabs: true,
|
||||
// smartIndent: true,
|
||||
// matchBrackets: 'always',
|
||||
// autoCloseBrackets: true,
|
||||
// styleSelectedText: true,
|
||||
// foldGutter: true,
|
||||
});
|
||||
this.editor.onDidChangeModelContent((e) => {
|
||||
const newValue = this.editor.getValue();
|
||||
onChange(newValue);
|
||||
});
|
||||
}
|
||||
public render() {
|
||||
return (
|
||||
<div className="monacoEditor ant-input" >
|
||||
<Input style={{ display: 'none' }} {...this.props} />
|
||||
<div className="editor" {...this.props} ref={(id) => { this.ref = id; }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Monacoeditor;
|
||||
@@ -2,13 +2,13 @@ import * as React from 'react';
|
||||
import { Drawer, Modal, Button, message } from 'component/antd';
|
||||
import { XFormComponent } from 'component/x-form';
|
||||
import { IXFormWrapper } from 'types/base-type';
|
||||
import { wrapper } from 'store';
|
||||
|
||||
export class XFormWrapper extends React.Component<IXFormWrapper> {
|
||||
|
||||
public state = {
|
||||
confirmLoading: false,
|
||||
formMap: this.props.formMap || [] as any,
|
||||
formData: this.props.formData || {},
|
||||
formData: this.props.formData || {}
|
||||
};
|
||||
|
||||
private $formRef: any;
|
||||
@@ -108,7 +108,7 @@ export class XFormWrapper extends React.Component<IXFormWrapper> {
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
const { onSubmit, isWaitting } = this.props;
|
||||
const { onSubmit, isWaitting, onSubmitFaild } = this.props;
|
||||
|
||||
if (typeof onSubmit === 'function') {
|
||||
if (isWaitting) {
|
||||
@@ -116,12 +116,16 @@ export class XFormWrapper extends React.Component<IXFormWrapper> {
|
||||
confirmLoading: true,
|
||||
});
|
||||
onSubmit(result).then(() => {
|
||||
this.setState({
|
||||
confirmLoading: false,
|
||||
});
|
||||
message.success('操作成功');
|
||||
this.resetForm();
|
||||
this.closeModalWrapper();
|
||||
}).catch((err: any) => {
|
||||
const { formMap, formData } = wrapper.xFormWrapper;
|
||||
onSubmitFaild(err, this.$formRef, formData, formMap);
|
||||
}).finally(() => {
|
||||
this.setState({
|
||||
confirmLoading: false,
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { Select, Input, InputNumber, Form, Switch, Checkbox, DatePicker, Radio, Upload, Button, Icon, Tooltip } from 'component/antd';
|
||||
import Monacoeditor from 'component/editor/monacoEditor';
|
||||
import { searchProps } from 'constants/table';
|
||||
import { version } from 'store/version';
|
||||
import './index.less';
|
||||
|
||||
const TextArea = Input.TextArea;
|
||||
@@ -19,6 +21,7 @@ export enum FormItemType {
|
||||
rangePicker = 'range_picker',
|
||||
radioGroup = 'radio_group',
|
||||
upload = 'upload',
|
||||
monacoEditor = 'monaco_editor',
|
||||
}
|
||||
|
||||
export interface IFormItem {
|
||||
@@ -105,13 +108,11 @@ class XForm extends React.Component<IXFormProps> {
|
||||
<Form layout={layout || 'horizontal'} onSubmit={() => ({})}>
|
||||
{formMap.map(formItem => {
|
||||
const { initialValue, valuePropName } = this.handleFormItem(formItem, formData);
|
||||
|
||||
const getFieldValue = {
|
||||
initialValue,
|
||||
rules: formItem.rules || [{ required: false, message: '' }],
|
||||
valuePropName,
|
||||
};
|
||||
|
||||
if (formItem.type === FormItemType.upload) {
|
||||
Object.assign(getFieldValue, {
|
||||
getValueFromEvent: this.onUploadFileChange,
|
||||
@@ -137,7 +138,6 @@ class XForm extends React.Component<IXFormProps> {
|
||||
}
|
||||
|
||||
public renderFormItem(item: IFormItem) {
|
||||
|
||||
switch (item.type) {
|
||||
default:
|
||||
case FormItemType.input:
|
||||
@@ -148,6 +148,9 @@ class XForm extends React.Component<IXFormProps> {
|
||||
return <InputNumber {...item.attrs} />;
|
||||
case FormItemType.textArea:
|
||||
return <TextArea rows={5} {...item.attrs} />;
|
||||
case FormItemType.monacoEditor:
|
||||
// tslint:disable-next-line: jsx-wrap-multiline
|
||||
return <Monacoeditor {...item.attrs} />;
|
||||
case FormItemType.select:
|
||||
return (
|
||||
<Select
|
||||
@@ -187,7 +190,7 @@ class XForm extends React.Component<IXFormProps> {
|
||||
case FormItemType.upload:
|
||||
return (
|
||||
<Upload beforeUpload={(file: any) => false} {...item.attrs}>
|
||||
<Button><Icon type="upload" />上传</Button>
|
||||
<Button><Icon type="upload" />上传</Button>{version.fileSuffix && <span style={{ color: '#fb3939', padding: '0 0 0 10px' }}>{`请上传${version.fileSuffix}文件`}</span>}
|
||||
</Upload>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,10 @@ export const timeMonthStr = 'YYYY/MM';
|
||||
|
||||
// tslint:disable-next-line:max-line-length
|
||||
|
||||
export const indexUrl = 'https://github.com/didi/kafka-manager';
|
||||
export const indexUrl ={
|
||||
indexUrl:'https://github.com/didi/kafka-manager',
|
||||
cagUrl:'https://github.com/didi/Logi-KafkaManager/blob/master/docs/user_guide/add_cluster/add_cluster.md', // 集群接入指南 Cluster access Guide
|
||||
}
|
||||
|
||||
export const expandRemarks = `请填写不少于5字的申请原因!以便工作人员判断审核`;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export const cellStyle = {
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
cursor: 'pointer',
|
||||
// cursor: 'pointer',
|
||||
};
|
||||
|
||||
export const searchProps = {
|
||||
|
||||
@@ -169,6 +169,8 @@ export class ClusterBroker extends SearchAndFilterContainer {
|
||||
title="确定删除?"
|
||||
onConfirm={() => this.deteleTopic(record)}
|
||||
disabled={record.status === 0}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a style={record.status === 0 ? { cursor: 'not-allowed', color: '#999' } : {}}>
|
||||
删除
|
||||
|
||||
@@ -38,7 +38,7 @@ export class ClusterConsumer extends SearchAndFilterContainer {
|
||||
key: 'operation',
|
||||
width: '10%',
|
||||
render: (t: string, item: IOffset) => {
|
||||
return (<a onClick={() => this.getConsumeDetails(item)}>详情</a>);
|
||||
return (<a onClick={() => this.getConsumeDetails(item)}>消费详情</a>);
|
||||
},
|
||||
}];
|
||||
private xFormModal: IXFormWrapper;
|
||||
@@ -72,7 +72,7 @@ export class ClusterConsumer extends SearchAndFilterContainer {
|
||||
data = searchKey ? origin.filter((item: IOffset) =>
|
||||
(item.consumerGroup !== undefined && item.consumerGroup !== null) && item.consumerGroup.toLowerCase().includes(searchKey as string)
|
||||
|| (item.location !== undefined && item.location !== null) && item.location.toLowerCase().includes(searchKey as string),
|
||||
) : origin ;
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ export class ClusterConsumer extends SearchAndFilterContainer {
|
||||
|
||||
public render() {
|
||||
let details: any[];
|
||||
details = this.consumerDetails ? this.consumerDetails.map((ele, index) => {
|
||||
details = this.consumerDetails ? this.consumerDetails.map((ele, index) => {
|
||||
return {
|
||||
key: index,
|
||||
topicName: ele,
|
||||
@@ -90,41 +90,43 @@ export class ClusterConsumer extends SearchAndFilterContainer {
|
||||
}) : [];
|
||||
|
||||
const consumptionColumns = [{
|
||||
title: 'Topic名称',
|
||||
title: '消费的Topic列表',
|
||||
dataIndex: 'topicName',
|
||||
key: 'topicName',
|
||||
}];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="k-row">
|
||||
<ul className="k-tab">
|
||||
<li>{this.props.tab}</li>
|
||||
{this.renderSearch()}
|
||||
</ul>
|
||||
<Table
|
||||
<div className="k-row">
|
||||
<ul className="k-tab">
|
||||
<li>{this.props.tab}</li>
|
||||
{this.renderSearch()}
|
||||
</ul>
|
||||
<Table
|
||||
columns={this.columns}
|
||||
dataSource={this.getData(admin.consumerData)}
|
||||
pagination={pagination}
|
||||
rowKey="key"
|
||||
/>
|
||||
</div>
|
||||
<Modal
|
||||
title="消费的Topic"
|
||||
visible={this.state.detailsVisible}
|
||||
onOk={() => this.handleDetailsOk()}
|
||||
onCancel={() => this.handleDetailsCancel()}
|
||||
maskClosable={false}
|
||||
footer={null}
|
||||
>
|
||||
<Table
|
||||
columns={consumptionColumns}
|
||||
dataSource={details}
|
||||
pagination={pagination}
|
||||
rowKey="key"
|
||||
scroll={{ y: 260 }}
|
||||
/>
|
||||
</Modal>
|
||||
/>
|
||||
</div>
|
||||
<Modal
|
||||
title="消费详情"
|
||||
visible={this.state.detailsVisible}
|
||||
onOk={() => this.handleDetailsOk()}
|
||||
onCancel={() => this.handleDetailsCancel()}
|
||||
maskClosable={false}
|
||||
footer={null}
|
||||
// centered={true}
|
||||
>
|
||||
<Table
|
||||
columns={consumptionColumns}
|
||||
dataSource={details}
|
||||
// 运维管控-消费组列表-详情
|
||||
pagination={details.length < 10 ? false : pagination}
|
||||
rowKey="key"
|
||||
scroll={{ y: 260 }}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export class ClusterController extends SearchAndFilterContainer {
|
||||
|
||||
data = searchKey ? origin.filter((item: IController) =>
|
||||
(item.host !== undefined && item.host !== null) && item.host.toLowerCase().includes(searchKey as string),
|
||||
) : origin ;
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -46,12 +46,6 @@ export class ClusterController extends SearchAndFilterContainer {
|
||||
key: 'brokerId',
|
||||
width: '30%',
|
||||
sorter: (a: IController, b: IController) => b.brokerId - a.brokerId,
|
||||
},
|
||||
{
|
||||
title: 'BrokerHost',
|
||||
key: 'host',
|
||||
dataIndex: 'host',
|
||||
width: '30%',
|
||||
render: (r: string, t: IController) => {
|
||||
return (
|
||||
<a href={`${this.urlPrefix}/admin/broker-detail?clusterId=${this.clusterId}&brokerId=${t.brokerId}`}>{r}
|
||||
@@ -59,6 +53,18 @@ export class ClusterController extends SearchAndFilterContainer {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'BrokerHost',
|
||||
key: 'host',
|
||||
dataIndex: 'host',
|
||||
width: '30%',
|
||||
// render: (r: string, t: IController) => {
|
||||
// return (
|
||||
// <a href={`${this.urlPrefix}/admin/broker-detail?clusterId=${this.clusterId}&brokerId=${t.brokerId}`}>{r}
|
||||
// </a>
|
||||
// );
|
||||
// },
|
||||
},
|
||||
{
|
||||
title: '变更时间',
|
||||
dataIndex: 'timestamp',
|
||||
|
||||
@@ -32,10 +32,12 @@ export class ClusterOverview extends React.Component<IOverview> {
|
||||
const clusterContent = [{
|
||||
value: content.clusterName,
|
||||
label: '集群名称',
|
||||
}, {
|
||||
value: clusterTypeMap[content.mode],
|
||||
label: '集群类型',
|
||||
}, {
|
||||
},
|
||||
// {
|
||||
// value: clusterTypeMap[content.mode],
|
||||
// label: '集群类型',
|
||||
// },
|
||||
{
|
||||
value: gmtCreate,
|
||||
label: '接入时间',
|
||||
}];
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import Url from 'lib/url-parser';
|
||||
import { region } from 'store';
|
||||
import { admin } from 'store/admin';
|
||||
import { app } from 'store/app';
|
||||
import { Table, notification, Tooltip, Popconfirm } from 'antd';
|
||||
import { pagination, cellStyle } from 'constants/table';
|
||||
import { observer } from 'mobx-react';
|
||||
@@ -15,6 +16,8 @@ import './index.less';
|
||||
|
||||
import moment = require('moment');
|
||||
import { ExpandPartitionFormWrapper } from 'container/modal/admin/expand-partition';
|
||||
import { ConfirmDetailTopicFormWrapper } from 'container/modal/admin/confirm-detail-topic';
|
||||
|
||||
import { showEditClusterTopic } from 'container/modal/admin';
|
||||
import { timeFormat } from 'constants/strategy';
|
||||
|
||||
@@ -26,6 +29,7 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
public state = {
|
||||
searchKey: '',
|
||||
expandVisible: false,
|
||||
detailTopicVisible: false,
|
||||
};
|
||||
|
||||
constructor(props: any) {
|
||||
@@ -44,10 +48,41 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
this.setState({ expandVisible: val });
|
||||
}
|
||||
|
||||
// 运维管控-集群列表-Topic列表修改删除业务逻辑-确认删除topic
|
||||
public handleConfirmVisible(val: boolean) {
|
||||
this.setState({ detailTopicVisible: val });
|
||||
}
|
||||
|
||||
public expandPartition(item: IClusterTopics) {
|
||||
// getTopicBasicInfo
|
||||
admin.getTopicsBasicInfo(item.clusterId, item.topicName).then(data => {
|
||||
this.clusterTopicsFrom = item;
|
||||
this.setState({
|
||||
expandVisible: true,
|
||||
});
|
||||
});
|
||||
// if (item.logicalClusterId) {
|
||||
// topic.getTopicBasicInfo(item.logicalClusterId, item.topicName).then(data => {
|
||||
// item.regionNameList = topic.baseInfo.regionNameList;
|
||||
// this.clusterTopicsFrom = item;
|
||||
// this.setState({
|
||||
// expandVisible: true,
|
||||
// });
|
||||
// });
|
||||
// } else {
|
||||
// this.clusterTopicsFrom = item;
|
||||
// this.setState({
|
||||
// expandVisible: true,
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
// 运维管控-集群列表-Topic列表修改删除业务逻辑-确认删除topic
|
||||
public confirmDetailTopic(item: IClusterTopics) {
|
||||
this.clusterTopicsFrom = item;
|
||||
// console.log(this.clusterTopicsFrom);
|
||||
this.setState({
|
||||
expandVisible: true,
|
||||
detailTopicVisible: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,12 +106,13 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
data = searchKey ? origin.filter((item: IClusterTopics) =>
|
||||
(item.appName !== undefined && item.appName !== null) && item.appName.toLowerCase().includes(searchKey as string)
|
||||
|| (item.topicName !== undefined && item.topicName !== null) && item.topicName.toLowerCase().includes(searchKey as string),
|
||||
) : origin ;
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
admin.getClusterTopics(this.clusterId);
|
||||
app.getAdminAppList()
|
||||
}
|
||||
|
||||
public renderClusterTopicList() {
|
||||
@@ -85,7 +121,7 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
title: 'Topic名称',
|
||||
dataIndex: 'topicName',
|
||||
key: 'topicName',
|
||||
width: '15%',
|
||||
width: '120px',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => a.topicName.charCodeAt(0) - b.topicName.charCodeAt(0),
|
||||
render: (text: string, record: IClusterTopics) => {
|
||||
return (
|
||||
@@ -99,11 +135,18 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
</Tooltip>);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '分区数',
|
||||
dataIndex: 'partitionNum',
|
||||
key: 'partitionNum',
|
||||
width: '90px',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.partitionNum - a.partitionNum,
|
||||
},
|
||||
{
|
||||
title: 'QPS',
|
||||
dataIndex: 'produceRequest',
|
||||
key: 'produceRequest',
|
||||
width: '10%',
|
||||
// width: '10%',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.produceRequest - a.produceRequest,
|
||||
render: (t: number) => t === null ? '' : t.toFixed(2),
|
||||
},
|
||||
@@ -111,15 +154,23 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
title: 'Bytes In(KB/s)',
|
||||
dataIndex: 'byteIn',
|
||||
key: 'byteIn',
|
||||
width: '15%',
|
||||
// width: '15%',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.byteIn - a.byteIn,
|
||||
render: (t: number) => t === null ? '' : (t / 1024).toFixed(2),
|
||||
},
|
||||
{
|
||||
title: 'Bytes Out(KB/s)',
|
||||
dataIndex: 'byteOut',
|
||||
key: 'byteOut',
|
||||
// width: '15%',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.byteOut - a.byteOut,
|
||||
render: (t: number) => t && t === null ? '' : (t / 1024).toFixed(2),
|
||||
},
|
||||
{
|
||||
title: '所属应用',
|
||||
dataIndex: 'appName',
|
||||
key: 'appName',
|
||||
width: '10%',
|
||||
// width: '10%',
|
||||
render: (val: string, record: IClusterTopics) => (
|
||||
<Tooltip placement="bottomLeft" title={record.appId} >
|
||||
{val}
|
||||
@@ -130,22 +181,23 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
title: '保存时间(h)',
|
||||
dataIndex: 'retentionTime',
|
||||
key: 'retentionTime',
|
||||
width: '10%',
|
||||
// width: '10%',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.retentionTime - a.retentionTime,
|
||||
render: (time: any) => transMSecondToHour(time),
|
||||
render: (time: any) => transMSecondToHour(time),
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updateTime',
|
||||
key: 'updateTime',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.updateTime - a.updateTime,
|
||||
render: (t: number) => moment(t).format(timeFormat),
|
||||
width: '10%',
|
||||
// width: '10%',
|
||||
},
|
||||
{
|
||||
title: 'Topic说明',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
width: '15%',
|
||||
// width: '15%',
|
||||
onCell: () => ({
|
||||
style: {
|
||||
maxWidth: 180,
|
||||
@@ -155,14 +207,19 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: '30%',
|
||||
width: '120px',
|
||||
render: (value: string, item: IClusterTopics) => (
|
||||
<>
|
||||
<a onClick={() => this.getBaseInfo(item)} className="action-button">编辑</a>
|
||||
<a onClick={() => this.expandPartition(item)} className="action-button">扩分区</a>
|
||||
{/* <a onClick={() => this.expandPartition(item)} className="action-button">删除</a> */}
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => this.deleteTopic(item)}
|
||||
// 运维管控-集群列表-Topic列表修改删除业务逻辑
|
||||
onConfirm={() => this.confirmDetailTopic(item)}
|
||||
// onConfirm={() => this.deleteTopic(item)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
@@ -190,6 +247,24 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
/>
|
||||
</div>
|
||||
{this.renderExpandModal()}
|
||||
{this.renderConfirmDetailModal()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
// 运维管控-集群列表-Topic列表修改删除业务逻辑-确认删除topic
|
||||
public renderConfirmDetailModal() {
|
||||
let formData = {} as IClusterTopics;
|
||||
formData = this.clusterTopicsFrom ? this.clusterTopicsFrom : formData;
|
||||
// console.log(formData);
|
||||
return (
|
||||
<>
|
||||
{this.state.detailTopicVisible && <ConfirmDetailTopicFormWrapper
|
||||
deleteTopic={(val: IClusterTopics) => this.deleteTopic(val)}
|
||||
handleVisible={(val: boolean) => this.handleConfirmVisible(val)}
|
||||
visible={this.state.detailTopicVisible}
|
||||
formData={formData}
|
||||
clusterId={this.clusterId}
|
||||
/>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Table, notification, Tooltip, Popconfirm } from 'component/antd';
|
||||
import { Table, notification, Tooltip, Popconfirm, Modal, Button } from 'component/antd';
|
||||
import { observer } from 'mobx-react';
|
||||
import { SearchAndFilterContainer } from 'container/search-filter';
|
||||
import { pagination, cellStyle } from 'constants/table';
|
||||
@@ -21,6 +21,8 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
public state = {
|
||||
searchKey: '',
|
||||
filterStatus: false,
|
||||
deteleRegion: false,
|
||||
logicalClusterName: '',
|
||||
};
|
||||
|
||||
private xFormModal: IXFormWrapper;
|
||||
@@ -78,7 +80,7 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
}),
|
||||
render: (value: number[]) => {
|
||||
const num = value ? value.join(',') : '';
|
||||
return(
|
||||
return (
|
||||
<Tooltip placement="bottomLeft" title={num}>
|
||||
{num}
|
||||
</Tooltip>);
|
||||
@@ -143,6 +145,8 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => this.handleDeleteRegion(record)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
@@ -154,10 +158,30 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
}
|
||||
|
||||
public handleDeleteRegion = (record: IBrokersRegions) => {
|
||||
deleteRegions(record.id).then(() => {
|
||||
notification.success({ message: '删除成功' });
|
||||
admin.getBrokersRegions(this.clusterId);
|
||||
});
|
||||
const filterRegion = admin.logicalClusters.filter(item => item.regionIdList.includes(record.id));
|
||||
if (!filterRegion) {
|
||||
return;
|
||||
}
|
||||
if (filterRegion && filterRegion.length < 1) {
|
||||
deleteRegions(record.id).then(() => {
|
||||
notification.success({ message: '删除成功' });
|
||||
admin.getBrokersRegions(this.clusterId);
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setState({ deteleRegion: true, logicalClusterName: filterRegion[0].logicalClusterName });
|
||||
// deleteRegions(record.id).then(() => {
|
||||
// notification.success({ message: '删除成功' });
|
||||
// admin.getBrokersRegions(this.clusterId);
|
||||
// });
|
||||
}
|
||||
|
||||
public handleExpandOk = () => {
|
||||
this.setState({ deteleRegion: false });
|
||||
}
|
||||
|
||||
public handleExpandCancel = () => {
|
||||
this.setState({ deteleCluster: false });
|
||||
}
|
||||
|
||||
public addOrModifyRegion(record?: IBrokersRegions) {
|
||||
@@ -185,9 +209,9 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
key: 'brokerIdList',
|
||||
label: 'Broker列表',
|
||||
defaultValue: record ? record.brokerIdList.join(',') : [],
|
||||
rules: [{ required: true, message: '请输入BrokerIdList' }],
|
||||
rules: [{ required: true, message: '请输入BrokerID,多个BrokerID用半角逗号分隔' }],
|
||||
attrs: {
|
||||
placeholder: '请输入BrokerIdList',
|
||||
placeholder: '请输入BrokerID,多个BrokerID用半角逗号分隔',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -248,6 +272,7 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
|
||||
public componentDidMount() {
|
||||
admin.getBrokersRegions(this.clusterId);
|
||||
admin.getLogicalClusters(this.clusterId);
|
||||
admin.getBrokersMetadata(this.clusterId);
|
||||
}
|
||||
|
||||
@@ -255,10 +280,10 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
let data: T[] = origin;
|
||||
let { searchKey } = this.state;
|
||||
searchKey = (searchKey + '').trim().toLowerCase();
|
||||
|
||||
data = searchKey ? origin.filter((item: IBrokersRegions) =>
|
||||
(item.name !== undefined && item.name !== null) && item.name.toLowerCase().includes(searchKey as string),
|
||||
) : origin ;
|
||||
(item.name !== undefined && item.name !== null) && item.name.toLowerCase().includes(searchKey as string)
|
||||
|| item.brokerIdList && item.brokerIdList.map(item => "" + item).join(',').includes(searchKey as string),
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -272,6 +297,30 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
/>
|
||||
);
|
||||
}
|
||||
// -删除RegionModal
|
||||
public renderDeleteRegionModal() {
|
||||
return (
|
||||
<Modal
|
||||
title="提示"
|
||||
visible={this.state.deteleRegion}
|
||||
// okText="确定"
|
||||
// cancelText="取消"
|
||||
maskClosable={false}
|
||||
// onCancel={() => this.handleExpandCancel()}
|
||||
closable={false}
|
||||
// onOk={() => this.handleExpandOk()}
|
||||
footer={<Button style={{ width: '80px' }} type="primary" onClick={() => this.handleExpandOk()}>确定</Button>}
|
||||
// onCancel={() => this.handleExpandCancel()}
|
||||
>
|
||||
<div className="region-prompt">
|
||||
<span>
|
||||
由于该Region已被逻辑集群【 {this.state.logicalClusterName} 】使用
|
||||
请先解除Region与逻辑集群的关系
|
||||
</span>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
@@ -282,10 +331,11 @@ export class ExclusiveCluster extends SearchAndFilterContainer {
|
||||
<i className="k-icon-xinjian didi-theme" />
|
||||
<span>新增Region</span>
|
||||
</li>
|
||||
{this.renderSearch('', '请输入Region名称')}
|
||||
{this.renderSearch('', '请输入Region名称/broker ID')}
|
||||
</ul>
|
||||
{this.renderRegion()}
|
||||
</div>
|
||||
{this.renderRegion()}
|
||||
{this.renderDeleteRegionModal()}
|
||||
</div >
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,4 +81,17 @@
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.cluster-prompt{
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cluster-explain{
|
||||
color: #838383;
|
||||
// transform: scale(0.95,0.95);
|
||||
// text-align: center;
|
||||
}
|
||||
.region-prompt{
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Table, notification, Popconfirm } from 'component/antd';
|
||||
import { Modal } from 'antd';
|
||||
import { observer } from 'mobx-react';
|
||||
import { SearchAndFilterContainer } from 'container/search-filter';
|
||||
import { pagination } from 'constants/table';
|
||||
@@ -21,6 +22,8 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
public state = {
|
||||
searchKey: '',
|
||||
filterStatus: false,
|
||||
deteleCluster: false,
|
||||
logicalClusterId: -1,
|
||||
};
|
||||
|
||||
constructor(props: any) {
|
||||
@@ -40,6 +43,13 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
title: '逻辑集群名称',
|
||||
dataIndex: 'logicalClusterName',
|
||||
key: 'logicalClusterName',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '逻辑集群标识',
|
||||
dataIndex: 'logicalClusterIdentification',
|
||||
key: 'logicalClusterIdentification',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '应用ID',
|
||||
@@ -52,7 +62,7 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
key: 'regionIdList',
|
||||
render: (value: number[]) => {
|
||||
const num = value ? `[${value.join(',')}]` : '';
|
||||
return(
|
||||
return (
|
||||
<span>{num}</span>
|
||||
);
|
||||
},
|
||||
@@ -63,12 +73,12 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
key: 'mode',
|
||||
render: (value: number) => {
|
||||
let val = '';
|
||||
cluster.clusterModes.forEach((ele: any) => {
|
||||
cluster.clusterModes && cluster.clusterModes.forEach((ele: any) => {
|
||||
if (value === ele.code) {
|
||||
val = ele.message;
|
||||
}
|
||||
});
|
||||
return(<span>{val}</span>);
|
||||
return (<span>{val}</span>);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -84,16 +94,20 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: '120px',
|
||||
render: (text: string, record: ILogicalCluster) => {
|
||||
return (
|
||||
<span className="table-operation">
|
||||
<a onClick={() => this.editRegion(record)}>编辑</a>
|
||||
<Popconfirm
|
||||
<a onClick={() => this.handleDeleteRegion(record)}>删除</a>
|
||||
{/* <Popconfirm
|
||||
title="确定删除?"
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
onConfirm={() => this.handleDeleteRegion(record)}
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
</Popconfirm> */}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
@@ -102,9 +116,24 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
}
|
||||
|
||||
public handleDeleteRegion = (record: ILogicalCluster) => {
|
||||
admin.deteleLogicalClusters(this.clusterId, record.logicalClusterId).then(() => {
|
||||
this.setState({ deteleCluster: true, logicalClusterId: record.logicalClusterId });
|
||||
// admin.deteleLogicalClusters(this.clusterId, record.logicalClusterId).then(() => {
|
||||
// notification.success({ message: '删除成功' });
|
||||
// });
|
||||
}
|
||||
|
||||
// -删除逻辑集群
|
||||
|
||||
public handleExpandOk = () => {
|
||||
const { logicalClusterId } = this.state;
|
||||
admin.deteleLogicalClusters(this.clusterId, logicalClusterId).then(() => {
|
||||
notification.success({ message: '删除成功' });
|
||||
});
|
||||
this.setState({ deteleCluster: false });
|
||||
}
|
||||
|
||||
public handleExpandCancel = () => {
|
||||
this.setState({ deteleCluster: false });
|
||||
}
|
||||
|
||||
public async editRegion(record: ILogicalCluster) {
|
||||
@@ -131,12 +160,11 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
let data: T[] = origin;
|
||||
let { searchKey } = this.state;
|
||||
searchKey = (searchKey + '').trim().toLowerCase();
|
||||
|
||||
data = searchKey ? origin.filter((item: ILogicalCluster) =>
|
||||
(item.logicalClusterName !== undefined && item.logicalClusterName !== null)
|
||||
&& item.logicalClusterName.toLowerCase().includes(searchKey as string)
|
||||
&& item.logicalClusterName.toLowerCase().includes(searchKey as string)
|
||||
|| (item.appId !== undefined && item.appId !== null) && item.appId.toLowerCase().includes(searchKey as string),
|
||||
) : origin ;
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -151,11 +179,37 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
);
|
||||
}
|
||||
|
||||
// -删除逻辑集群
|
||||
public renderDeleteCluster() {
|
||||
return (
|
||||
<Modal
|
||||
title="提示"
|
||||
visible={this.state.deteleCluster}
|
||||
okText="确认删除"
|
||||
cancelText="取消"
|
||||
maskClosable={false}
|
||||
onOk={() => this.handleExpandOk()}
|
||||
onCancel={() => this.handleExpandCancel()}
|
||||
>
|
||||
<div className="cluster-prompt">
|
||||
<span>
|
||||
若逻辑集群上存在Topic,则删除逻辑集群后,用户将无法在Topic管理页查看到该Topic
|
||||
</span>
|
||||
</div>
|
||||
<div className="cluster-explain">
|
||||
<span>
|
||||
说明:删除逻辑集群不会真实删除该逻辑集群上创建的topic
|
||||
</span>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div className="k-row">
|
||||
<ul className="k-tab">
|
||||
<li>{this.props.tab}</li>
|
||||
<li>{this.props.tab}</li>
|
||||
<li className="k-add" onClick={() => this.addOrEditLogicalCluster()}>
|
||||
<i className="k-icon-xinjian didi-theme" />
|
||||
<span>新增逻辑集群</span>
|
||||
@@ -163,6 +217,7 @@ export class LogicalCluster extends SearchAndFilterContainer {
|
||||
{this.renderSearch('', '请输入逻辑集群名称或AppId')}
|
||||
</ul>
|
||||
{this.renderLogicalCluster()}
|
||||
{this.renderDeleteCluster()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Modal, Table, Button, notification, message, Tooltip, Icon, Popconfirm } from 'component/antd';
|
||||
import { Modal, Table, Button, notification, message, Tooltip, Icon, Popconfirm, Alert, Popover } from 'component/antd';
|
||||
import { wrapper } from 'store';
|
||||
import { observer } from 'mobx-react';
|
||||
import { IXFormWrapper, IMetaData, IRegister } from 'types/base-type';
|
||||
@@ -9,6 +9,7 @@ import { SearchAndFilterContainer } from 'container/search-filter';
|
||||
import { cluster } from 'store/cluster';
|
||||
import { customPagination } from 'constants/table';
|
||||
import { urlPrefix } from 'constants/left-menu';
|
||||
import { indexUrl } from 'constants/strategy'
|
||||
import { region } from 'store';
|
||||
import './index.less';
|
||||
import { getAdminClusterColumns } from '../config';
|
||||
@@ -57,7 +58,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
message: '请输入zookeeper地址',
|
||||
}],
|
||||
attrs: {
|
||||
placeholder: '请输入zookeeper地址',
|
||||
placeholder: '请输入zookeeper地址,例如:192.168.0.1:2181,192.168.0.2:2181/logi-kafka',
|
||||
rows: 2,
|
||||
disabled: item ? true : false,
|
||||
},
|
||||
@@ -71,7 +72,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
message: '请输入bootstrapServers',
|
||||
}],
|
||||
attrs: {
|
||||
placeholder: '请输入bootstrapServers',
|
||||
placeholder: '请输入bootstrapServers,例如:192.168.1.1:9092,192.168.1.2:9092',
|
||||
rows: 2,
|
||||
disabled: item ? true : false,
|
||||
},
|
||||
@@ -126,8 +127,13 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
message: '请输入安全协议',
|
||||
}],
|
||||
attrs: {
|
||||
placeholder: '请输入安全协议',
|
||||
rows: 6,
|
||||
placeholder: `请输入安全协议,例如:
|
||||
{
|
||||
"security.protocol": "SASL_PLAINTEXT",
|
||||
"sasl.mechanism": "PLAIN",
|
||||
"sasl.jaas.config": "org.apache.kafka.common.security.plain.PlainLoginModule required username=\\"xxxxxx\\" password=\\"xxxxxx\\";"
|
||||
}`,
|
||||
rows: 8,
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -172,7 +178,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
<span className="offline_span">
|
||||
删除集群
|
||||
<a>
|
||||
<Tooltip placement="right" title={'当前集群存在逻辑集群,无法申请下线'} >
|
||||
<Tooltip placement="right" title={'若当前集群存在逻辑集群,则无法删除'} >
|
||||
<Icon type="question-circle" />
|
||||
</Tooltip>
|
||||
</a>
|
||||
@@ -185,7 +191,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
cancelText: '取消',
|
||||
onOk() {
|
||||
if (data.length) {
|
||||
return message.warning('存在逻辑集群,无法申请下线!');
|
||||
return message.warning('存在逻辑集群,无法删除!');
|
||||
}
|
||||
admin.deleteCluster(record.clusterId).then(data => {
|
||||
notification.success({ message: '删除成功' });
|
||||
@@ -204,7 +210,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
};
|
||||
const monitorColumns = [
|
||||
{
|
||||
title: '集群名称',
|
||||
title: '逻辑集群列表',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
onCell: () => ({
|
||||
@@ -231,6 +237,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
pagination={false}
|
||||
bordered={true}
|
||||
/>
|
||||
<Alert message="若当前集群存在逻辑集群,则无法删除" type="error" showIcon={true} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
@@ -243,7 +250,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
|
||||
data = searchKey ? origin.filter((item: IMetaData) =>
|
||||
(item.clusterName !== undefined && item.clusterName !== null) && item.clusterName.toLowerCase().includes(searchKey as string),
|
||||
) : origin ;
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -261,12 +268,16 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
<Popconfirm
|
||||
title={`确定${item.status === 1 ? '暂停' : '开始'}${item.clusterName}监控?`}
|
||||
onConfirm={() => this.pauseMonitor(item)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a
|
||||
className="action-button"
|
||||
>
|
||||
{item.status === 1 ? '暂停监控' : '开始监控'}
|
||||
</a>
|
||||
<Tooltip title="暂停监控将无法正常监控指标信息,建议开启监控">
|
||||
<a
|
||||
className="action-button"
|
||||
>
|
||||
{item.status === 1 ? '暂停监控' : '开始监控'}
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Popconfirm>
|
||||
<a onClick={this.showMonitor.bind(this, item)}>
|
||||
删除
|
||||
@@ -286,6 +297,7 @@ export class ClusterList extends SearchAndFilterContainer {
|
||||
<ul>
|
||||
{this.renderSearch('', '请输入集群名称')}
|
||||
<li className="right-btn-1">
|
||||
<a style={{ display: 'inline-block', marginRight: '20px' }} href={indexUrl.cagUrl} target="_blank">集群接入指南</a>
|
||||
<Button type="primary" onClick={this.createOrRegisterCluster.bind(this, null)}>接入集群</Button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -30,6 +30,8 @@ export const getUserColumns = () => {
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => users.deleteUser(record.username)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
@@ -54,7 +56,7 @@ export const getVersionColumns = () => {
|
||||
render: (text: string, record: IUploadFile) => {
|
||||
return (
|
||||
<Tooltip placement="topLeft" title={text} >
|
||||
<a href={`${urlPrefix}/info?fileId=${record.id}`} target="_blank">{text}</a>
|
||||
<a href={`${window.origin}/api/v1/rd/kafka-files/${record.id}/config-files?dataCenter=cn`} target="_blank">{text}</a>
|
||||
</Tooltip>);
|
||||
},
|
||||
}, {
|
||||
@@ -70,7 +72,7 @@ export const getVersionColumns = () => {
|
||||
render: (text: string) => {
|
||||
return (
|
||||
<Tooltip placement="bottomLeft" title={text} >
|
||||
{text.substring(0, 8)}
|
||||
{text.substring(0, 8)}
|
||||
</Tooltip>);
|
||||
},
|
||||
}, {
|
||||
@@ -95,26 +97,28 @@ export const getVersionColumns = () => {
|
||||
render: (text: string) => {
|
||||
return (
|
||||
<Tooltip placement="topLeft" title={text} >
|
||||
{text}
|
||||
{text}
|
||||
</Tooltip>);
|
||||
},
|
||||
}, {
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
key: 'operation',
|
||||
render: (text: string, record: IUploadFile) => {
|
||||
return (
|
||||
<span className="table-operation">
|
||||
<a onClick={() => showModifyModal(record)}>编辑</a>
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => version.deleteFile(record.id)}
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
</span>);
|
||||
},
|
||||
dataIndex: 'operation',
|
||||
key: 'operation',
|
||||
render: (text: string, record: IUploadFile) => {
|
||||
return (
|
||||
<span className="table-operation">
|
||||
<a onClick={() => showModifyModal(record)}>编辑</a>
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => version.deleteFile(record.id)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
</span>);
|
||||
},
|
||||
},
|
||||
];
|
||||
return columns;
|
||||
};
|
||||
@@ -168,6 +172,8 @@ export const getConfigureColumns = () => {
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => admin.deleteConfigure(record.configKey)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
@@ -178,11 +184,11 @@ export const getConfigureColumns = () => {
|
||||
return columns;
|
||||
};
|
||||
|
||||
const renderClusterHref = (value: number | string, item: IMetaData, key: number) => {
|
||||
const renderClusterHref = (value: number | string, item: IMetaData, key: number) => {
|
||||
return ( // 0 暂停监控--不可点击 1 监控中---可正常点击
|
||||
<>
|
||||
{item.status === 1 ? <a href={`${urlPrefix}/admin/cluster-detail?clusterId=${item.clusterId}#${key}`}>{value}</a>
|
||||
: <a style={{ cursor: 'not-allowed', color: '#999' }}>{value}</a>}
|
||||
{item.status === 1 ? <a href={`${urlPrefix}/admin/cluster-detail?clusterId=${item.clusterId}#${key}`}>{value}</a>
|
||||
: <a style={{ cursor: 'not-allowed', color: '#999' }}>{value}</a>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -190,13 +196,13 @@ const renderClusterHref = (value: number | string, item: IMetaData, key: number
|
||||
export const getAdminClusterColumns = () => {
|
||||
return [
|
||||
{
|
||||
title: '集群ID',
|
||||
title: '物理集群ID',
|
||||
dataIndex: 'clusterId',
|
||||
key: 'clusterId',
|
||||
sorter: (a: IMetaData, b: IMetaData) => b.clusterId - a.clusterId,
|
||||
},
|
||||
{
|
||||
title: '集群名称',
|
||||
title: '物理集群名称',
|
||||
dataIndex: 'clusterName',
|
||||
key: 'clusterName',
|
||||
sorter: (a: IMetaData, b: IMetaData) => a.clusterName.charCodeAt(0) - b.clusterName.charCodeAt(0),
|
||||
|
||||
@@ -26,11 +26,11 @@ export class ConfigureManagement extends SearchAndFilterContainer {
|
||||
searchKey = (searchKey + '').trim().toLowerCase();
|
||||
|
||||
data = searchKey ? origin.filter((item: IConfigure) =>
|
||||
((item.configKey !== undefined && item.configKey !== null) && item.configKey.toLowerCase().includes(searchKey as string))
|
||||
|| ((item.configValue !== undefined && item.configValue !== null) && item.configValue.toLowerCase().includes(searchKey as string))
|
||||
|| ((item.configDescription !== undefined && item.configDescription !== null) &&
|
||||
((item.configKey !== undefined && item.configKey !== null) && item.configKey.toLowerCase().includes(searchKey as string))
|
||||
|| ((item.configValue !== undefined && item.configValue !== null) && item.configValue.toLowerCase().includes(searchKey as string))
|
||||
|| ((item.configDescription !== undefined && item.configDescription !== null) &&
|
||||
item.configDescription.toLowerCase().includes(searchKey as string)),
|
||||
) : origin ;
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ export class IndividualBill extends React.Component {
|
||||
}
|
||||
|
||||
public renderTableList() {
|
||||
const adminUrl=`${urlPrefix}/admin/bill-detail`
|
||||
const adminUrl = `${urlPrefix}/admin/bill-detail`
|
||||
return (
|
||||
<Table
|
||||
rowKey="key"
|
||||
@@ -89,11 +89,11 @@ export class IndividualBill extends React.Component {
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public renderChart() {
|
||||
return (
|
||||
<div className="chart-box">
|
||||
<BarChartComponet ref={(ref) => this.chart = ref } getChartData={this.getData.bind(this, null)} />
|
||||
<BarChartComponet ref={(ref) => this.chart = ref} getChartData={this.getData.bind(this, null)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ export class IndividualBill extends React.Component {
|
||||
<>
|
||||
<div className="container">
|
||||
<Tabs defaultActiveKey="1" type="card">
|
||||
<TabPane
|
||||
<TabPane
|
||||
tab={<>
|
||||
<span>账单趋势</span>
|
||||
<a
|
||||
@@ -142,7 +142,7 @@ export class IndividualBill extends React.Component {
|
||||
>
|
||||
<Icon type="question-circle" />
|
||||
</a>
|
||||
</>}
|
||||
</>}
|
||||
key="1"
|
||||
>
|
||||
{this.renderDatePick()}
|
||||
|
||||
@@ -55,7 +55,9 @@ export class EassentialInfo extends React.Component<IEassProps> {
|
||||
<Descriptions.Item key={item.label || index} label={item.label}>{item.value}</Descriptions.Item>
|
||||
))}
|
||||
<Descriptions.Item key="server" label="server配置名">
|
||||
<a href={`${urlPrefix}/info?fileId=${tasks.serverPropertiesFileId || ''}`} target="_blank">{tasks.serverPropertiesName}</a>
|
||||
{/* /api/v1/rd/kafka-files/66/config-files?dataCenter=cn */}
|
||||
|
||||
<a href={`${window.origin}/api/v1/rd/kafka-files/${tasks.serverPropertiesFileId}/config-files?dataCenter=cn`} target="_blank">{tasks.serverPropertiesName}</a>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="server" label="server配置 MD5">{tasks.serverPropertiesMd5}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
@@ -82,6 +82,8 @@ export class OperationDetail extends React.Component {
|
||||
<Popconfirm
|
||||
title={`确定${showContinue ? '开始' : '暂停'}?`}
|
||||
onConfirm={() => this.bindClick()}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>{showContinue ? '开始' : '暂停'}</a>
|
||||
</Popconfirm>
|
||||
@@ -94,6 +96,8 @@ export class OperationDetail extends React.Component {
|
||||
<Popconfirm
|
||||
title={`确定回滚?`}
|
||||
onConfirm={() => this.callBackOrCancel('rollback')}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>回滚</a>
|
||||
</Popconfirm>
|
||||
@@ -106,6 +110,8 @@ export class OperationDetail extends React.Component {
|
||||
<Popconfirm
|
||||
title={`确定回滚?`}
|
||||
onConfirm={() => this.callBackOrCancel('cancel')}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>取消</a>
|
||||
</Popconfirm>
|
||||
|
||||
@@ -87,6 +87,8 @@ export class TaskStatusDetails extends SearchAndFilterContainer {
|
||||
<Popconfirm
|
||||
title={`确定忽略?`}
|
||||
onConfirm={() => this.bindClick(record, 'ignore')}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>忽略</a>
|
||||
</Popconfirm>
|
||||
@@ -130,7 +132,7 @@ export class TaskStatusDetails extends SearchAndFilterContainer {
|
||||
return (
|
||||
<>
|
||||
<div className="config-info">
|
||||
{admin.clusterTaskLog}
|
||||
{admin.clusterTaskLog ? admin.clusterTaskLog : '暂无数据'}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -78,10 +78,10 @@ export class ClusterTask extends SearchAndFilterContainer {
|
||||
cluster,
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'gmtCreate',
|
||||
key: 'gmtCreate',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
width: '15%',
|
||||
sorter: (a: ITaskManage, b: ITaskManage) => b.gmtCreate - a.gmtCreate,
|
||||
sorter: (a: ITaskManage, b: ITaskManage) => b.createTime - a.createTime,
|
||||
render: (t: number) => moment(t).format(timeFormat),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -41,6 +41,8 @@ export const migrationTaskColumns = (migrationUrl: string) => {
|
||||
<Popconfirm
|
||||
title="确定开始?"
|
||||
onConfirm={() => startMigrationTask(item, 'start')}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a style={{ marginRight: 16 }}>开始</a>
|
||||
</Popconfirm>}
|
||||
@@ -49,6 +51,8 @@ export const migrationTaskColumns = (migrationUrl: string) => {
|
||||
{item.status === 0 &&
|
||||
<Popconfirm
|
||||
title="确定取消?"
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
onConfirm={() => cancelMigrationTask(item, 'cancel')}
|
||||
><a>取消</a>
|
||||
</Popconfirm>}
|
||||
|
||||
@@ -35,7 +35,7 @@ export class MigrationDetail extends SearchAndFilterContainer {
|
||||
const detail = expert.tasksDetail;
|
||||
const gmtCreate = moment(detail.gmtCreate).format(timeFormat);
|
||||
const startTime = moment(detail.beginTime).format(timeFormat);
|
||||
const endTime = moment(detail.endTime).format(timeFormat);
|
||||
const endTime = detail.endTime == null ? '任务运行中' : moment(detail.endTime).format(timeFormat);
|
||||
const options = [{
|
||||
value: detail.taskName,
|
||||
label: '任务名称',
|
||||
|
||||
@@ -20,7 +20,7 @@ export class VersionManagement extends SearchAndFilterContainer {
|
||||
|
||||
public async componentDidMount() {
|
||||
if (!version.fileTypeList.length) {
|
||||
await version.getFileTypeList();
|
||||
await version.getFileTypeList();
|
||||
}
|
||||
|
||||
if (!version.fileList.length) {
|
||||
@@ -58,7 +58,7 @@ export class VersionManagement extends SearchAndFilterContainer {
|
||||
|
||||
if (searchKey) {
|
||||
data = origin.filter((item: IUploadFile) => item.id + '' === searchKey
|
||||
|| ((item.fileName !== undefined && item.fileName !== null) && item.fileName.toLowerCase().includes(searchKey as string)));
|
||||
|| ((item.fileName !== undefined && item.fileName !== null) && item.fileName.toLowerCase().includes(searchKey as string)));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ export const getAlarmColumns = (urlPrefix: string) => {
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => deteleMonitor(item)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
@@ -193,21 +195,21 @@ export const xActionFormMap = [{
|
||||
key: 'acceptGroup',
|
||||
label: '报警接收组',
|
||||
type: 'custom',
|
||||
customFormItem: <AlarmSelect isDisabled={isDetailPage}/>,
|
||||
customFormItem: <AlarmSelect isDisabled={isDetailPage} />,
|
||||
rules: [{ required: true, message: '请输入报警接收组' }],
|
||||
},
|
||||
{
|
||||
key: 'callback',
|
||||
label: '回调地址',
|
||||
rules: [{ required: false, message: '请输入回调地址' }],
|
||||
attrs: {disabled: isDetailPage},
|
||||
attrs: { disabled: isDetailPage },
|
||||
}] as unknown as IFormSelect[]; // as IFormItem[];
|
||||
|
||||
export const xTypeFormMap = [{
|
||||
key: 'alarmName',
|
||||
label: '告警规则',
|
||||
label: '告警规则名称',
|
||||
rules: [{ required: true, message: '请输入告警规则' }],
|
||||
attrs: {placeholder: '请输入', disabled: isDetailPage},
|
||||
attrs: { placeholder: '请输入告警规则名称', disabled: isDetailPage },
|
||||
}, {
|
||||
key: 'app',
|
||||
label: '所属应用',
|
||||
@@ -217,8 +219,8 @@ export const xTypeFormMap = [{
|
||||
optionFilterProp: 'children',
|
||||
showSearch: true,
|
||||
filterOption: (input: any, option: any) => {
|
||||
if ( typeof option.props.children === 'object' ) {
|
||||
const { props } = option.props.children as any;
|
||||
if (typeof option.props.children === 'object') {
|
||||
const { props } = option.props.children as any;
|
||||
return (props.children + '').toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
}
|
||||
return (option.props.children + '').toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
|
||||
@@ -11,6 +11,7 @@ import { filterKeys } from 'constants/strategy';
|
||||
import { VirtualScrollSelect } from 'component/virtual-scroll-select';
|
||||
import { IsNotNaN } from 'lib/utils';
|
||||
import { searchProps } from 'constants/table';
|
||||
import { toJS } from 'mobx';
|
||||
|
||||
interface IDynamicProps {
|
||||
form?: any;
|
||||
@@ -33,6 +34,7 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
public monitorType: string = null;
|
||||
public clusterId: number = null;
|
||||
public clusterName: string = null;
|
||||
public clusterIdentification: string | number = null;
|
||||
public topicName: string = null;
|
||||
public consumerGroup: string = null;
|
||||
public location: string = null;
|
||||
@@ -45,16 +47,18 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
this.props.form.validateFields((err: Error, values: any) => {
|
||||
if (!err) {
|
||||
monitorType = values.monitorType;
|
||||
const index = cluster.clusterData.findIndex(item => item.clusterId === values.cluster);
|
||||
const index = cluster.clusterData.findIndex(item => item.clusterIdentification === values.cluster);
|
||||
if (index > -1) {
|
||||
values.clusterIdentification = cluster.clusterData[index].clusterIdentification;
|
||||
values.clusterName = cluster.clusterData[index].clusterName;
|
||||
}
|
||||
for (const key of Object.keys(values)) {
|
||||
if (filterKeys.indexOf(key) > -1) { // 只有这几种值可以设置
|
||||
filterList.push({
|
||||
tkey: key === 'clusterName' ? 'cluster' : key, // 传参需要将clusterName转成cluster
|
||||
tkey: key === 'clusterName' ? 'cluster' : key, // clusterIdentification
|
||||
topt: '=',
|
||||
tval: [values[key]],
|
||||
clusterIdentification: values.clusterIdentification
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -74,13 +78,13 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
|
||||
public resetFormValue(
|
||||
monitorType: string = null,
|
||||
clusterId: number = null,
|
||||
clusterIdentification: any = null,
|
||||
topicName: string = null,
|
||||
consumerGroup: string = null,
|
||||
location: string = null) {
|
||||
const { setFieldsValue } = this.props.form;
|
||||
setFieldsValue({
|
||||
cluster: clusterId,
|
||||
cluster: clusterIdentification,
|
||||
topic: topicName,
|
||||
consumerGroup,
|
||||
location,
|
||||
@@ -88,18 +92,18 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
});
|
||||
}
|
||||
|
||||
public getClusterId = (clusterName: string) => {
|
||||
public getClusterId = async (clusterIdentification: any) => {
|
||||
let clusterId = null;
|
||||
const index = cluster.clusterData.findIndex(item => item.clusterName === clusterName);
|
||||
const index = cluster.clusterData.findIndex(item => item.clusterIdentification === clusterIdentification);
|
||||
if (index > -1) {
|
||||
clusterId = cluster.clusterData[index].clusterId;
|
||||
}
|
||||
if (clusterId) {
|
||||
cluster.getClusterMetaTopics(clusterId);
|
||||
await cluster.getClusterMetaTopics(clusterId);
|
||||
this.clusterId = clusterId;
|
||||
return this.clusterId;
|
||||
}
|
||||
return this.clusterId = clusterName as any;
|
||||
};
|
||||
return this.clusterId = clusterId as any;
|
||||
}
|
||||
|
||||
public async initFormValue(monitorRule: IRequestParams) {
|
||||
@@ -108,17 +112,19 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
const topicFilter = strategyFilterList.filter(item => item.tkey === 'topic')[0];
|
||||
const consumerFilter = strategyFilterList.filter(item => item.tkey === 'consumerGroup')[0];
|
||||
|
||||
const clusterName = clusterFilter ? clusterFilter.tval[0] : null;
|
||||
const clusterIdentification = clusterFilter ? clusterFilter.tval[0] : null;
|
||||
const topic = topicFilter ? topicFilter.tval[0] : null;
|
||||
const consumerGroup = consumerFilter ? consumerFilter.tval[0] : null;
|
||||
const location: string = null;
|
||||
const monitorType = monitorRule.strategyExpressionList[0].metric;
|
||||
alarm.changeMonitorStrategyType(monitorType);
|
||||
|
||||
await this.getClusterId(clusterName);
|
||||
//增加clusterIdentification替代原来的clusterName
|
||||
this.clusterIdentification = clusterIdentification;
|
||||
await this.getClusterId(this.clusterIdentification);
|
||||
//
|
||||
await this.handleSelectChange(topic, 'topic');
|
||||
await this.handleSelectChange(consumerGroup, 'consumerGroup');
|
||||
this.resetFormValue(monitorType, this.clusterId, topic, consumerGroup, location);
|
||||
this.resetFormValue(monitorType, this.clusterIdentification, topic, consumerGroup, location);
|
||||
}
|
||||
|
||||
public clearFormData() {
|
||||
@@ -130,11 +136,12 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
this.resetFormValue();
|
||||
}
|
||||
|
||||
public async handleClusterChange(e: number) {
|
||||
this.clusterId = e;
|
||||
public async handleClusterChange(e: any) {
|
||||
this.clusterIdentification = e;
|
||||
this.topicName = null;
|
||||
topic.setLoading(true);
|
||||
await cluster.getClusterMetaTopics(e);
|
||||
const clusterId = await this.getClusterId(e);
|
||||
await cluster.getClusterMetaTopics(clusterId);
|
||||
this.resetFormValue(this.monitorType, e, null, this.consumerGroup, this.location);
|
||||
topic.setLoading(false);
|
||||
}
|
||||
@@ -170,7 +177,7 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
}
|
||||
this.consumerGroup = null;
|
||||
this.location = null;
|
||||
this.resetFormValue(this.monitorType, this.clusterId, this.topicName);
|
||||
this.resetFormValue(this.monitorType, this.clusterIdentification, this.topicName);
|
||||
topic.setLoading(false);
|
||||
}
|
||||
|
||||
@@ -213,17 +220,24 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
},
|
||||
rules: [{ required: true, message: '请选择监控指标' }],
|
||||
} as IVritualScrollSelect;
|
||||
const clusterData = toJS(cluster.clusterData);
|
||||
const options = clusterData?.length ? clusterData.map(item => {
|
||||
return {
|
||||
label: `${item.clusterName}${item.description ? '(' + item.description + ')' : ''}`,
|
||||
value: item.clusterIdentification
|
||||
}
|
||||
}) : null;
|
||||
|
||||
const clusterItem = {
|
||||
label: '集群',
|
||||
options: cluster.clusterData,
|
||||
defaultValue: this.clusterId,
|
||||
options,
|
||||
defaultValue: this.clusterIdentification,
|
||||
rules: [{ required: true, message: '请选择集群' }],
|
||||
attrs: {
|
||||
placeholder: '请选择集群',
|
||||
className: 'middle-size',
|
||||
className: 'large-size',
|
||||
disabled: this.isDetailPage,
|
||||
onChange: (e: number) => this.handleClusterChange(e),
|
||||
onChange: (e: any) => this.handleClusterChange(e),
|
||||
},
|
||||
key: 'cluster',
|
||||
} as unknown as IVritualScrollSelect;
|
||||
@@ -241,7 +255,7 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
}),
|
||||
attrs: {
|
||||
placeholder: '请选择Topic',
|
||||
className: 'middle-size',
|
||||
className: 'large-size',
|
||||
disabled: this.isDetailPage,
|
||||
onChange: (e: string) => this.handleSelectChange(e, 'topic'),
|
||||
},
|
||||
@@ -260,7 +274,7 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
rules: [{ required: showMore, message: '请选择消费组' }],
|
||||
attrs: {
|
||||
placeholder: '请选择消费组',
|
||||
className: 'middle-size',
|
||||
className: 'large-size',
|
||||
disabled: this.isDetailPage,
|
||||
onChange: (e: string) => this.handleSelectChange(e, 'consumerGroup'),
|
||||
},
|
||||
@@ -329,7 +343,7 @@ export class DynamicSetFilter extends React.Component<IDynamicProps> {
|
||||
key={v.value || v.key || index}
|
||||
value={v.value}
|
||||
>
|
||||
{v.label.length > 25 ? <Tooltip placement="bottomLeft" title={v.label}>
|
||||
{v.label?.length > 25 ? <Tooltip placement="bottomLeft" title={v.label}>
|
||||
{v.label}
|
||||
</Tooltip> : v.label}
|
||||
</Select.Option>
|
||||
|
||||
@@ -43,18 +43,23 @@
|
||||
Icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.ant-form-item-label {
|
||||
// padding-left: 10px;
|
||||
width: 118px;
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
&.type-form {
|
||||
padding-top: 10px;
|
||||
|
||||
.ant-form-item {
|
||||
width: 30%
|
||||
.ant-form{
|
||||
min-width: 755px;
|
||||
}
|
||||
.ant-form-item-label {
|
||||
padding-left: 10px;
|
||||
.ant-form-item {
|
||||
width: 45%;
|
||||
min-width: 360px;
|
||||
}
|
||||
.ant-form-item-control {
|
||||
width: 220px;
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +166,7 @@
|
||||
}
|
||||
|
||||
.dynamic-set {
|
||||
padding: 15px 10px;
|
||||
padding: 15px 0;
|
||||
|
||||
ul{
|
||||
li{
|
||||
@@ -176,7 +181,7 @@
|
||||
|
||||
.ant-form-item {
|
||||
display: inline-block;
|
||||
margin: 0px 5px 10px 5px;
|
||||
margin: 0px 5px 10px 0;
|
||||
|
||||
.ant-select {
|
||||
width: 150px;
|
||||
|
||||
@@ -12,7 +12,6 @@ import { alarm } from 'store/alarm';
|
||||
import { app } from 'store/app';
|
||||
import Url from 'lib/url-parser';
|
||||
import { IStrategyExpression, IRequestParams } from 'types/alarm';
|
||||
|
||||
@observer
|
||||
export class AddAlarm extends SearchAndFilterContainer {
|
||||
public isDetailPage = window.location.pathname.includes('/alarm-detail'); // 判断是否为详情
|
||||
@@ -90,8 +89,8 @@ export class AddAlarm extends SearchAndFilterContainer {
|
||||
const filterObj = this.typeForm.getFormData().filterObj;
|
||||
// tslint:disable-next-line:max-line-length
|
||||
if (!actionValue || !timeValue || !typeValue || !strategyList.length || !filterObj || !filterObj.filterList.length) {
|
||||
message.error('请正确填写必填项');
|
||||
return null;
|
||||
message.error('请正确填写必填项');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (filterObj.monitorType === 'online-kafka-topic-throttled') {
|
||||
@@ -101,13 +100,17 @@ export class AddAlarm extends SearchAndFilterContainer {
|
||||
tval: [typeValue.app],
|
||||
});
|
||||
}
|
||||
this.id && filterObj.filterList.forEach((item: any) => {
|
||||
if (item.tkey === 'cluster') {
|
||||
item.tval = [item.clusterIdentification]
|
||||
}
|
||||
})
|
||||
strategyList = strategyList.map((row: IStrategyExpression) => {
|
||||
return {
|
||||
...row,
|
||||
metric: filterObj.monitorType,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
appId: typeValue.app,
|
||||
name: typeValue.alarmName,
|
||||
@@ -129,7 +132,7 @@ export class AddAlarm extends SearchAndFilterContainer {
|
||||
public renderAlarmStrategy() {
|
||||
return (
|
||||
<div className="config-wrapper">
|
||||
<span className="span-tag">报警策略</span>
|
||||
<span className="span-tag" data-set={alarm.monitorType}>报警策略</span>
|
||||
<div className="info-wrapper">
|
||||
<WrappedDynamicSetStrategy wrappedComponentRef={(form: any) => this.strategyForm = form} />
|
||||
</div>
|
||||
@@ -139,9 +142,9 @@ export class AddAlarm extends SearchAndFilterContainer {
|
||||
|
||||
public renderTimeForm() {
|
||||
return (
|
||||
<>
|
||||
<WrappedTimeForm wrappedComponentRef={(form: any) => this.timeForm = form} />
|
||||
</>
|
||||
<>
|
||||
<WrappedTimeForm wrappedComponentRef={(form: any) => this.timeForm = form} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -164,7 +167,7 @@ export class AddAlarm extends SearchAndFilterContainer {
|
||||
{this.renderAlarmStrategy()}
|
||||
{this.renderTimeForm()}
|
||||
<ActionForm ref={(actionForm) => this.actionForm = actionForm} />
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { IStringMap } from 'types/base-type';
|
||||
import { IRequestParams } from 'types/alarm';
|
||||
import { IFormSelect, IFormItem, FormItemType } from 'component/x-form';
|
||||
import { searchProps } from 'constants/table';
|
||||
import { alarm } from 'store/alarm';
|
||||
|
||||
interface IDynamicProps {
|
||||
form: any;
|
||||
@@ -27,6 +28,7 @@ class DynamicSetStrategy extends React.Component<IDynamicProps> {
|
||||
public crudList = [] as ICRUDItem[];
|
||||
public state = {
|
||||
shouldUpdate: false,
|
||||
monitorType: alarm.monitorType
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
@@ -130,7 +132,7 @@ class DynamicSetStrategy extends React.Component<IDynamicProps> {
|
||||
|
||||
if (lineValue.func === 'happen' && paramsArray.length > 1 && paramsArray[0] < paramsArray[1]) {
|
||||
strategyList = []; // 清空赋值
|
||||
return message.error('周期值应大于次数') ;
|
||||
return message.error('周期值应大于次数');
|
||||
}
|
||||
|
||||
lineValue.params = paramsArray.join(',');
|
||||
@@ -292,8 +294,39 @@ class DynamicSetStrategy extends React.Component<IDynamicProps> {
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
public renderFormList(row: ICRUDItem) {
|
||||
public unit(monitorType: string) {
|
||||
let element = null;
|
||||
switch (monitorType) {
|
||||
case 'online-kafka-topic-msgIn':
|
||||
element = "条/秒"
|
||||
break;
|
||||
case 'online-kafka-topic-bytesIn':
|
||||
element = "字节/秒"
|
||||
break;
|
||||
case 'online-kafka-topic-bytesRejected':
|
||||
element = "字节/秒"
|
||||
break;
|
||||
case 'online-kafka-topic-produce-throttled':
|
||||
element = "1表示被限流"
|
||||
break;
|
||||
case 'online-kafka-topic-fetch-throttled':
|
||||
element = "1表示被限流"
|
||||
break;
|
||||
case 'online-kafka-consumer-maxLag':
|
||||
element = "条"
|
||||
break;
|
||||
case 'online-kafka-consumer-lag':
|
||||
element = "条"
|
||||
break;
|
||||
case 'online-kafka-consumer-maxDelayTime':
|
||||
element = "秒"
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<span>{element}</span>
|
||||
)
|
||||
}
|
||||
public renderFormList(row: ICRUDItem, monitorType: string) {
|
||||
const key = row.id;
|
||||
const funcType = row.func;
|
||||
|
||||
@@ -309,6 +342,7 @@ class DynamicSetStrategy extends React.Component<IDynamicProps> {
|
||||
key: key + '-func',
|
||||
} as IFormSelect)}
|
||||
{this.getFuncItem(row)}
|
||||
{row.func !== 'c_avg_rate_abs' && row.func !== 'pdiff' ? this.unit(monitorType) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -340,8 +374,8 @@ class DynamicSetStrategy extends React.Component<IDynamicProps> {
|
||||
<Form>
|
||||
{crudList.map((row, index) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
{this.renderFormList(row)}
|
||||
<div key={`${index}-${this.state.monitorType}`}>
|
||||
{this.renderFormList(row, alarm.monitorType)}
|
||||
{
|
||||
crudList.length > 1 ? (
|
||||
<Icon
|
||||
|
||||
@@ -50,23 +50,23 @@ export class TypeForm extends React.Component {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="config-wrapper">
|
||||
<span className="span-tag">基本信息</span>
|
||||
<div className="alarm-x-form type-form">
|
||||
<XFormComponent
|
||||
ref={form => this.$form = form}
|
||||
formData={formData}
|
||||
formMap={xTypeFormMap}
|
||||
layout="inline"
|
||||
/>
|
||||
</div>
|
||||
</div >
|
||||
<div className="config-wrapper">
|
||||
<span className="span-tag">选择指标</span>
|
||||
<div className="alarm-x-form type-form">
|
||||
<WrappedDynamicSetFilter wrappedComponentRef={(form: any) => this.filterForm = form} />
|
||||
</div>
|
||||
</div >
|
||||
<div className="config-wrapper">
|
||||
<span className="span-tag">基本信息</span>
|
||||
<div className="alarm-x-form type-form">
|
||||
<XFormComponent
|
||||
ref={form => this.$form = form}
|
||||
formData={formData}
|
||||
formMap={xTypeFormMap}
|
||||
layout="inline"
|
||||
/>
|
||||
</div>
|
||||
</div >
|
||||
<div className="config-wrapper">
|
||||
<span className="span-tag">选择指标</span>
|
||||
<div className="alarm-x-form type-form">
|
||||
<WrappedDynamicSetFilter wrappedComponentRef={(form: any) => this.filterForm = form} />
|
||||
</div>
|
||||
</div >
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -163,6 +163,8 @@ export class ShieldHistory extends React.Component {
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
onConfirm={() => this.deleteSilences(record)}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
>
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
|
||||
@@ -7,7 +7,7 @@ const Option = Select.Option;
|
||||
|
||||
interface IStaffSelectProps {
|
||||
selectData?: any[];
|
||||
onChange?: (result: string []) => any;
|
||||
onChange?: (result: string[]) => any;
|
||||
value?: string[];
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export class AppSelect extends React.Component<IStaffSelectProps> {
|
||||
<Select
|
||||
placeholder="请选择"
|
||||
value={value || []}
|
||||
onChange={(e: string []) => this.handleChange(e)}
|
||||
onChange={(e: string[]) => this.handleChange(e)}
|
||||
{...searchProps}
|
||||
>
|
||||
{selectData.map((d: any) =>
|
||||
@@ -29,16 +29,18 @@ export class AppSelect extends React.Component<IStaffSelectProps> {
|
||||
{d.name.length > 25 ? <Tooltip placement="bottomLeft" title={d.name}>{d.name}</Tooltip> : d.name}
|
||||
</Option>)}
|
||||
</Select>
|
||||
{
|
||||
selectData.length ? null : <i>
|
||||
没有应用?
|
||||
{/* {
|
||||
selectData.length ? null : */}
|
||||
<i>
|
||||
没有应用?
|
||||
<a href={`${urlPrefix}/topic/app-list?${query}`}>立刻创建</a>
|
||||
</i>}
|
||||
</i>
|
||||
{/* } */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
public handleChange(params: string []) {
|
||||
public handleChange(params: string[]) {
|
||||
const { onChange } = this.props;
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
onChange && onChange(params);
|
||||
|
||||
@@ -61,6 +61,7 @@ export class AppDetail extends SearchAndFilterContainer {
|
||||
title: '申请时间',
|
||||
dataIndex: 'gmtCreate',
|
||||
key: 'gmtCreate',
|
||||
sorter: (a: any, b: any) => a.gmtCreate - b.gmtCreate,
|
||||
render: (t: number) => moment(t).format(timeFormat),
|
||||
},
|
||||
statusColumn,
|
||||
@@ -101,11 +102,11 @@ export class AppDetail extends SearchAndFilterContainer {
|
||||
value: baseInfo.principals,
|
||||
}];
|
||||
const infoCopy: ILabelValue[] = [{
|
||||
label: 'AppID',
|
||||
value: baseInfo.appId,
|
||||
}, {
|
||||
label: '密钥',
|
||||
value: baseInfo.password,
|
||||
label: 'AppID',
|
||||
value: baseInfo.appId,
|
||||
}, {
|
||||
label: '密钥',
|
||||
value: baseInfo.password,
|
||||
}];
|
||||
return (
|
||||
<PageHeader
|
||||
@@ -118,7 +119,7 @@ export class AppDetail extends SearchAndFilterContainer {
|
||||
<Descriptions.Item key={key} label={item.label}>
|
||||
<Tooltip placement="bottomLeft" title={item.value}>
|
||||
<span className="overview-bootstrap">
|
||||
<i className="overview-boot">{item.value}</i>
|
||||
<i className="overview-boot">{item.value}</i>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Descriptions.Item>
|
||||
@@ -136,14 +137,14 @@ export class AppDetail extends SearchAndFilterContainer {
|
||||
))}
|
||||
</Descriptions>
|
||||
<Descriptions size="small" column={1}>
|
||||
<Descriptions.Item label="应用描述">
|
||||
<Tooltip placement="bottomLeft" title={baseInfo.description}>
|
||||
<span className="overview-bootstrap" style={{width: '600px'}}>
|
||||
<i className="overview-boot"> {baseInfo.description} </i>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<Descriptions.Item label="应用描述">
|
||||
<Tooltip placement="bottomLeft" title={baseInfo.description}>
|
||||
<span className="overview-bootstrap" style={{ width: '600px' }}>
|
||||
<i className="overview-boot"> {baseInfo.description} </i>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</PageHeader>
|
||||
);
|
||||
}
|
||||
@@ -156,7 +157,7 @@ export class AppDetail extends SearchAndFilterContainer {
|
||||
data = searchKey ? origin.filter((item: ITopic) =>
|
||||
(item.topicName !== undefined && item.topicName !== null) && item.topicName.toLowerCase().includes(searchKey as string)
|
||||
|| (item.clusterName !== undefined && item.clusterName !== null) && item.clusterName.toLowerCase().includes(searchKey as string),
|
||||
) : origin ;
|
||||
) : origin;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -183,22 +184,22 @@ export class AppDetail extends SearchAndFilterContainer {
|
||||
const { currentTab } = app;
|
||||
return (
|
||||
<>
|
||||
<div className="app-container">
|
||||
<div className="base-info">
|
||||
{this.renderBaseInfo(app.baseInfo)}
|
||||
<div className="app-container">
|
||||
<div className="base-info">
|
||||
{this.renderBaseInfo(app.baseInfo)}
|
||||
</div>
|
||||
<div className="k-row">
|
||||
<Tabs defaultActiveKey="1" type="card" onChange={(e) => this.onChangeTab(e)}>
|
||||
<TabPane tab="创建的Topic" key="1" />
|
||||
<TabPane tab="有权限Topic" key="2" />
|
||||
</Tabs>
|
||||
<ul className="k-tab">
|
||||
<li>{currentTab === '1' ? '创建的Topic' : '有权限Topic'}</li>
|
||||
{this.renderSearch('', '请输入Topic名称/集群名称')}
|
||||
</ul>
|
||||
{this.renderTable()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="k-row">
|
||||
<Tabs defaultActiveKey="1" type="card" onChange={(e) => this.onChangeTab(e)}>
|
||||
<TabPane tab="创建的Topic" key="1" />
|
||||
<TabPane tab="有权限Topic" key="2" />
|
||||
</Tabs>
|
||||
<ul className="k-tab">
|
||||
<li>{currentTab === '1' ? '创建的Topic' : '有权限Topic'}</li>
|
||||
{this.renderSearch('', '请输入Topic名称/集群名称')}
|
||||
</ul>
|
||||
{this.renderTable()}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,15 +32,20 @@ export class ClusterOverview extends React.Component<IOverview> {
|
||||
const clusterContent = [{
|
||||
value: content.clusterName,
|
||||
label: '集群名称',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
value: content.clusterIdentification,
|
||||
label: '集群标识',
|
||||
},
|
||||
{
|
||||
value: clusterTypeMap[content.mode],
|
||||
label: '集群类型',
|
||||
}, {
|
||||
value: moment(content.gmtCreate).format(timeFormat),
|
||||
label: '接入时间',
|
||||
}, {
|
||||
value: content.physicalClusterId,
|
||||
label: '物理集群ID',
|
||||
value: content.clusterId,
|
||||
label: '集群ID',
|
||||
}];
|
||||
const clusterInfo = [{
|
||||
value: content.clusterVersion,
|
||||
@@ -55,23 +60,23 @@ export class ClusterOverview extends React.Component<IOverview> {
|
||||
<PageHeader className="detail" title="">
|
||||
<Descriptions size="small" column={3}>
|
||||
{clusterContent.map((item: ILabelValue, index: number) => (
|
||||
<Descriptions.Item key={index} label={item.label} >
|
||||
{item.value}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key={index} label={item.label} >
|
||||
{item.value}
|
||||
</Descriptions.Item>
|
||||
))}
|
||||
{clusterInfo.map((item: ILabelValue, index: number) => (
|
||||
<Descriptions.Item key={index} label={item.label}>
|
||||
<Tooltip placement="bottomLeft" title={item.value}>
|
||||
<span className="overview-bootstrap">
|
||||
<Icon
|
||||
onClick={() => copyString(item.value)}
|
||||
type="copy"
|
||||
className="didi-theme overview-theme"
|
||||
/>
|
||||
<i className="overview-boot">{item.value}</i>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key={index} label={item.label}>
|
||||
<Tooltip placement="bottomLeft" title={item.value}>
|
||||
<span className="overview-bootstrap">
|
||||
<Icon
|
||||
onClick={() => copyString(item.value)}
|
||||
type="copy"
|
||||
className="didi-theme overview-theme"
|
||||
/>
|
||||
<i className="overview-boot">{item.value}</i>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Descriptions.Item>
|
||||
))}
|
||||
</Descriptions>
|
||||
</PageHeader>
|
||||
|
||||
@@ -101,6 +101,7 @@ export class ClusterTopic extends SearchAndFilterContainer {
|
||||
dataIndex: 'updateTime',
|
||||
key: 'updateTime',
|
||||
width: '20%',
|
||||
sorter: (a: IClusterTopics, b: IClusterTopics) => b.updateTime - a.updateTime,
|
||||
render: (t: number) => moment(t).format(timeFormat),
|
||||
},
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user