mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-11 03:49:06 +08:00
Compare commits
90 Commits
init
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
|
d4ba61ef65 | ||
|
0d87486d7a | ||
|
94d7a4e418 | ||
|
3fbaa3ab92 | ||
|
e6d454301f | ||
|
f5c09ac287 | ||
|
e97072a3b1 | ||
|
6d360509c0 | ||
|
464f57adf8 | ||
|
5d08d3b122 | ||
|
d9fc76d3a3 | ||
|
2bc59db340 | ||
|
d58e13da95 | ||
|
e7cb315050 | ||
|
21dc2acfdc | ||
|
823bce2b8b | ||
|
2fb0fce0b1 | ||
|
6456630324 | ||
|
a25ccd6337 | ||
|
538d1c1c45 | ||
|
86bdb06364 | ||
|
7a54427d9c | ||
|
fc9781e6fc | ||
|
ea8834bacd | ||
|
63d9da7429 | ||
|
daa181ccfd | ||
|
f5b9bbb9a7 | ||
|
6de5d51661 | ||
|
4269879d93 | ||
|
0fc7ca904d | ||
|
636ba51bc3 | ||
|
8c5d8747a7 | ||
|
3f02992e13 | ||
|
78b85ebdb6 | ||
|
653332d488 | ||
|
d2da9ca41f | ||
|
6da21f480e | ||
|
e281b74456 | ||
|
529501c007 | ||
|
560b56e9dc | ||
|
8acd94c89a | ||
|
2d8bf001b3 | ||
|
1caeb4ce31 | ||
|
749e6f15f7 | ||
|
2524ca668a | ||
|
6054c057c8 | ||
|
e660c7d874 | ||
|
a5a3659c04 | ||
|
2160e23b91 | ||
|
ef7b97e96a | ||
|
d73d9b2793 | ||
|
a2234f8517 | ||
|
4b2b61e394 | ||
|
d5fed12773 | ||
|
cc30bb2373 | ||
|
d0583b73c3 | ||
|
193a66e5c2 | ||
|
9e9762ef44 | ||
|
8b12e8e7d7 | ||
|
f6d4e18b89 | ||
|
a5d7cce483 | ||
|
58336d951a | ||
|
dc67c660ff | ||
|
f4b759dba6 | ||
|
ef09ceb736 | ||
|
91794b5a9c | ||
|
d120610686 | ||
|
ef3a27d642 | ||
|
0614bc499e | ||
|
b0a2c8ff41 | ||
|
d5588b1fd0 | ||
|
3fd2223cb5 | ||
|
975449e268 | ||
|
5b2a027cd8 | ||
|
25129169d5 | ||
|
a1490d8377 | ||
|
38e97a4c53 | ||
|
818cd8d5d1 | ||
|
c9d4cd1b72 | ||
|
635e0ce4d0 | ||
|
ef25e37ca6 | ||
|
b1752d6dd6 | ||
|
0f5a5e1dda | ||
|
417f34130e | ||
|
a977542a0f | ||
|
51ed6117c2 | ||
|
bcfd10b65a | ||
|
1a751091b3 | ||
|
62a4cafea0 | ||
|
39d9db8a48 |
11
.asf.yaml
11
.asf.yaml
@@ -5,3 +5,14 @@ github:
|
||||
issues: true
|
||||
# Enable wiki
|
||||
wiki: true
|
||||
enabled_merge_buttons:
|
||||
squash: true
|
||||
merge: false
|
||||
rebase: false
|
||||
|
||||
notifications:
|
||||
commits: commits@rocketmq.apache.org
|
||||
issues: commits@rocketmq.apache.org
|
||||
pullrequests: commits@rocketmq.apache.org
|
||||
jobs: commits@rocketmq.apache.org
|
||||
discussions: dev@rocketmq.apache.org
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,8 @@
|
||||
/.idea/
|
||||
/target/
|
||||
*.iml
|
||||
.classpath
|
||||
.project
|
||||
.factorypath
|
||||
.settings/
|
||||
.vscode
|
@@ -14,9 +14,11 @@ jdk:
|
||||
- oraclejdk11
|
||||
|
||||
script:
|
||||
- travis_retry mvn -B clean
|
||||
- travis_retry mvn -B clean apache-rat:check
|
||||
- travis_retry mvn -B package findbugs:findbugs jacoco:report coveralls:report
|
||||
|
||||
# - travis_retry mvn -B package findbugs:findbugs coveralls:report
|
||||
#after_success:
|
||||
# - mvn sonar:sonar
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash) -t 996e4d8e-8a00-49f2-b649-38c03716d690 || echo 'Codecov failed to upload'
|
||||
|
60
LICENSE
60
LICENSE
@@ -15,7 +15,7 @@
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (properties) the power, direct or indirect, to cause the
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
@@ -357,38 +357,16 @@ SOFTWARE.
|
||||
|
||||
echarts
|
||||
----------------------------------
|
||||
https://github.com/ecomfe/echarts
|
||||
https://github.com/apache/echarts
|
||||
|
||||
Copyright (c) 2017, Baidu Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
html5-boilerplate
|
||||
------------------------------------------
|
||||
https://github.com/h5bp/html5-boilerplate
|
||||
h5bp/html5-boilerplate is licensed under the MIT License
|
||||
Copyright (c) HTML5 Boilerplate
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
@@ -409,23 +387,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Font-Awesome
|
||||
----------------------
|
||||
https://github.com/FortAwesome/Font-Awesome
|
||||
|
||||
License
|
||||
|
||||
The Font Awesome font is licensed under the SIL OFL 1.1:
|
||||
http://scripts.sil.org/OFL
|
||||
Font Awesome CSS, LESS, and Sass files are licensed under the MIT License:
|
||||
https://opensource.org/licenses/mit-license.html
|
||||
The Font Awesome documentation is licensed under the CC BY 3.0 License:
|
||||
http://creativecommons.org/licenses/by/3.0/
|
||||
Attribution is no longer required as of Font Awesome 3.0, but much appreciated:
|
||||
Font Awesome by Dave Gandy - http://fontawesome.io
|
||||
Full details: http://fontawesome.io/license/
|
||||
|
||||
|
||||
jquery
|
||||
---------------------
|
||||
Copyright JS Foundation and other contributors, https://js.foundation/
|
||||
@@ -551,6 +512,15 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
pagination
|
||||
---------------------
|
||||
https://github.com/317482454/tm.pagination
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
|
||||
bootstrap-validator
|
||||
---------------------------
|
||||
|
4
NOTICE
4
NOTICE
@@ -1,5 +1,5 @@
|
||||
Apache RocketMQ Dashboard
|
||||
Copyright 2016-2017 The Apache Software Foundation
|
||||
Apache RocketMQ
|
||||
Copyright 2016-2022 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
59
README.md
59
README.md
@@ -1,52 +1,50 @@
|
||||
## RocketMQ Dashboard [](https://travis-ci.com/github/apache/rocketmq-dashboard)[](https://coveralls.io/github/apache/rocketmq-dashboard?branch=master)
|
||||
## [Apache RocketMQ](https://github.com/apache/rocketmq) Dashboard
|
||||
[](https://travis-ci.com/github/apache/rocketmq-dashboard) [](https://coveralls.io/github/apache/rocketmq-dashboard?branch=master)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://codecov.io/gh/apache/rocketmq-dashboard)
|
||||
[](http://isitmaintained.com/project/apache/rocketmq-dashboard "Average time to resolve an issue")
|
||||
[](http://isitmaintained.com/project/apache/rocketmq-dashboard "Percentage of issues still open")
|
||||
[](https://twitter.com/intent/follow?screen_name=ApacheRocketMQ)
|
||||
## How To Install
|
||||
## Quick Start
|
||||
|
||||
### With Docker
|
||||
### Run with docker
|
||||
|
||||
* get docker image
|
||||
#### Pull from [docker hub(rocketmq-dashboard)](https://hub.docker.com/r/apacherocketmq/rocketmq-dashboard/tags)
|
||||
|
||||
```
|
||||
mvn clean package -Dmaven.test.skip=true docker:build
|
||||
```shell
|
||||
docker pull apacherocketmq/rocketmq-dashboard:latest
|
||||
```
|
||||
|
||||
or
|
||||
#### Run it (use your own `rocketmq.namesrv.addr` and `port`)
|
||||
|
||||
```
|
||||
docker pull apacherocketmq/rocketmq-console
|
||||
```shell
|
||||
docker run -d --name rocketmq-dashboard -e "JAVA_OPTS=-Drocketmq.namesrv.addr=127.0.0.1:9876" -p 8080:8080 -t apacherocketmq/rocketmq-dashboard:latest
|
||||
```
|
||||
|
||||
> currently the newest available docker image is apacherocketmq/rocketmq-console:2.0.0
|
||||
### Run with source code
|
||||
|
||||
|
||||
* run it (change namesvrAddr and port yourself)
|
||||
#### Prerequisite
|
||||
1. 64bit OS, Linux/Unix/Mac is recommended;
|
||||
2. 64bit JDK 1.8+;
|
||||
3. Maven 3.2.x;
|
||||
|
||||
```
|
||||
docker run -e "JAVA_OPTS=-Drocketmq.namesrv.addr=127.0.0.1:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" -p 8080:8080 -t apacherocketmq/rocketmq-console-ng
|
||||
```
|
||||
#### Maven spring-boot run
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
docker run -e "JAVA_OPTS=-Drocketmq.namesrv.addr=127.0.0.1:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" -p 8080:8080 -t apacherocketmq/rocketmq-console-ng:2.0.0
|
||||
```
|
||||
|
||||
### Without Docker
|
||||
require java 1.8+
|
||||
```
|
||||
```shell
|
||||
mvn spring-boot:run
|
||||
```
|
||||
or
|
||||
```
|
||||
|
||||
#### Maven build and run
|
||||
|
||||
```shell
|
||||
mvn clean package -Dmaven.test.skip=true
|
||||
java -jar target/rocketmq-dashboard-2.0.0.jar
|
||||
java -jar target/rocketmq-dashboard-1.0.1-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
#### Tips
|
||||
* if you download package slow,you can change maven's mirror(maven's settings.xml)
|
||||
* If you download the package slowly, you can change maven's mirror(maven's settings.xml)
|
||||
|
||||
```
|
||||
<mirrors>
|
||||
@@ -59,18 +57,17 @@ java -jar target/rocketmq-dashboard-2.0.0.jar
|
||||
</mirrors>
|
||||
```
|
||||
|
||||
* if you use the rocketmq < 3.5.8,please add -Dcom.rocketmq.sendMessageWithVIPChannel=false when you start rocketmq-dashboard(or you can change it in ops page)
|
||||
* change the rocketmq.config.namesrvAddr in resource/application.properties.(or you can change it in ops page)
|
||||
* Change the rocketmq.config.namesrvAddr in resource/application.properties.(or you can change it in ops page)
|
||||
|
||||
## UserGuide
|
||||
|
||||
[English](https://github.com/apache/rocketmq-dashboard/blob/master/doc/1_0_0/UserGuide_EN.md)
|
||||
[English](https://github.com/apache/rocketmq-dashboard/blob/master/docs/1_0_0/UserGuide_EN.md)
|
||||
|
||||
[中文](https://github.com/apache/rocketmq-dashboard/blob/master/doc/1_0_0/UserGuide_CN.md)
|
||||
[中文](https://github.com/apache/rocketmq-dashboard/blob/master/docs/1_0_0/UserGuide_CN.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
We are always very happy to have contributions, whether for trivial cleanups or big new features. Please see the RocketMQ main website to read [details](http://rocketmq.apache.org/docs/how-to-contribute/).
|
||||
We are always very happy to have contributions, whether for trivial cleanups or big new features. Please see the RocketMQ main website to read the [details](http://rocketmq.apache.org/docs/how-to-contribute/).
|
||||
|
||||
## License
|
||||
[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) Copyright (C) Apache Software Foundation
|
||||
|
@@ -63,6 +63,18 @@
|
||||
* 根据消息主题和消息Id进行消息的查询
|
||||
* 消息详情可以展示这条消息的详细信息,查看消息对应到具体消费组的消费情况(如果异常,可以查看具体的异常信息)。可以向指定的消费组重发消息。
|
||||
|
||||
## RocketMQ-V5.0 仪表盘
|
||||
* 版本切换
|
||||
* RocketMQ右上角可切换不同版本,用户可以自主选择 RocketMQ-5.x 或 RocketMQ-4.x 版本
|
||||
* 主题页面
|
||||
* 支持延迟/顺序/事务消息的筛选
|
||||
* 支持延迟/顺序/事物/普通等多种消息类型主题的新增与更新
|
||||
* 消费页面
|
||||
* 支持顺序消费类型订阅组的过滤
|
||||
* 提供顺序消费类型订阅组的新增与更新,如果需要开启顺序消费,FIFO类型的订阅组一定需要打开consumeOrderlyEnable选项
|
||||
* 代理页面(RocketMQ 5.0新增)
|
||||
* 支持代理节点的新增与查询
|
||||
* 支持代理节点地址配置:在application.yml中可对proxyAddr和proxyAddrs属性进行预配置
|
||||
|
||||
## HTTPS 方式访问Dashboard
|
||||
* HTTPS功能实际上是使用SpringBoot提供的配置功能即可完成,首先,需要有一个SSL KeyStore来存放服务端证书,可以使用本工程所提供的测试密钥库:
|
||||
@@ -91,7 +103,7 @@ server.port=8443
|
||||
## 登录访问Dashboard
|
||||
在访问Dashboard时支持按用户名和密码登录控制台,在操作完成后登出。需要做如下的设置:
|
||||
|
||||
* 1.在Spring配置文件resources/application.properties中修改 开启登录功能
|
||||
* 1.在Spring配置文件resources/application.properties中修改rocketmq.config.loginRequired=true开启登录功能
|
||||
```$xslt
|
||||
# 开启登录功能
|
||||
rocketmq.config.loginRequired=true
|
||||
@@ -113,3 +125,40 @@ user1=user1
|
||||
user2=user2
|
||||
```
|
||||
* 3.启动控制台则开启了登录功能
|
||||
|
||||
## 权限检验
|
||||
如果用户访问console时开启了登录功能,会按照登录的角色对访问的接口进行权限控制。
|
||||
* 1.在Spring配置文件resources/application.properties中修改rocketmq.config.loginRequired=true开启登录功能
|
||||
```$xslt
|
||||
# 开启登录功能
|
||||
rocketmq.config.loginRequired=true
|
||||
|
||||
# Dashboard文件目录,登录用户配置文件所在目录
|
||||
rocketmq.config.dataPath=/tmp/rocketmq-console/data
|
||||
```
|
||||
* 2.确保${rocketmq.config.dataPath}定义的目录存在,并且该目录下创建访问权限配置文件"role-permission.yml",
|
||||
如果该目录下不存在此文件,则默认使用resources/role-permission.yml文件。该文件保存了普通用户角色所有能访问的接口地址。
|
||||
role-permission.yml文件格式为:
|
||||
```$xslt
|
||||
# 该文件支持热修改,即添加和修改用户时,不需要重新启动console
|
||||
# 格式,如果增加和删除接口权限,直接在列表中增加和删除接口地址即可。
|
||||
# 接口路径配置支持通配符
|
||||
# * 表示匹配0或多个不是/的字符
|
||||
# ** 表示匹配0或多个任意字符
|
||||
# ? 表示匹配1个任意字符
|
||||
|
||||
rolePerms:
|
||||
# 普通用户
|
||||
ordinary:
|
||||
- /rocketmq/nsaddr
|
||||
- /ops/*
|
||||
- /dashboard/**
|
||||
- /topic/*.query
|
||||
- /topic/sendTopicMessage.do
|
||||
- /producer/*.query
|
||||
- /message/*
|
||||
- /messageTrace/*
|
||||
- /monitor/*
|
||||
....
|
||||
```
|
||||
* 3.前端页面显示上,为了更好区分普通用户和admin用户权限,关于资源的删除、更新等操作按钮不对普通用户角色显示,如果要执行资源相关操作,需要退出使用admin角色登录。
|
@@ -64,6 +64,18 @@
|
||||
* look over this message's detail info.you can see the message's consume state(each group has one line),show the exception message if has exception.
|
||||
you can send this message to the group you selected
|
||||
|
||||
## RocketMQ-V5.0 dashboard
|
||||
* Version switching
|
||||
* RocketMQ can switch between different versions in the upper right corner, and users can freely choose between RocketMQ-5.X or RocketMQ-4.X versions
|
||||
* Theme page
|
||||
* Support filtering of delayed/sequential/transaction messages
|
||||
* Support the addition and update of multiple message types such as delay, sequence, object, and ordinary themes
|
||||
* Consumption page
|
||||
* Support filtering of subscription groups for fifo consumption types
|
||||
* Provide the addition and update of subscription groups for sequential consumption types. If fifo consumption needs to be enabled, FIFO type subscription groups must have the consumeOrderlyEnable option enabled
|
||||
* Proxy page (Added in RocketMQ 5.0)
|
||||
* Support for adding and querying proxy nodes
|
||||
* Support proxy node address configuration: ProxyAddr and proxyAddrs properties can be pre configured in application.yml
|
||||
|
||||
## Access Dashboard with HTTPS
|
||||
* SpringBoot itself has provided the SSL configuration. You can use the project test Keystore:resources/rmqcngkeystore.jks. The store is generated with the following unix keytool commands:
|
||||
@@ -115,4 +127,44 @@ admin=admin,1
|
||||
user1=user1
|
||||
user2=user2
|
||||
```
|
||||
* 3. Restart Dashboard Application after above configuration setting well.
|
||||
* 3.Restart Console Application after above configuration setting well.
|
||||
|
||||
|
||||
## Permission Control
|
||||
If the login function is enabled when a user accesses the Console, the user controls the access permission of the interface based on the login role.
|
||||
|
||||
* 1.Turn on the property in resources/application.properties.
|
||||
```$xslt
|
||||
# open the login func
|
||||
rocketmq.config.loginRequired=true
|
||||
|
||||
# Directory of ashboard & login user configure file
|
||||
rocketmq.config.dataPath=/tmp/rocketmq-console/data
|
||||
```
|
||||
* 2.Make sure the directory defined in property ${rocketmq.config.dataPath} exists and the permission control file "role-permission.yml" is created under it.
|
||||
The console system will use the resources/role-permission.yml by default if a customized file is not found。
|
||||
|
||||
The format in the content of role-permission.yml:
|
||||
```$xslt
|
||||
# This file supports hot change, any change will be auto-reloaded without Console restarting.
|
||||
# Format: To add or delete interface permissions, add or delete interface addresses from the list.
|
||||
# the interface paths can be configured with wildcard characters.
|
||||
# ?: Matches 1 characters.
|
||||
# *: Matches 0 or more characters that are not /.
|
||||
# **: Matches 0 or more characters.
|
||||
|
||||
rolePerms:
|
||||
# ordinary user
|
||||
ordinary:
|
||||
- /rocketmq/nsaddr
|
||||
- /ops/*
|
||||
- /dashboard/**
|
||||
- /topic/*.query
|
||||
- /topic/sendTopicMessage.do
|
||||
- /producer/*.query
|
||||
- /message/*
|
||||
- /messageTrace/*
|
||||
- /monitor/*
|
||||
....
|
||||
```
|
||||
* 3.On the front page, operation buttons such as deleting and updating resources are not displayed for common users in order to better distinguish the rights of common users and admin users. If need to operate related resources, log out and use the admin role to log in
|
23
frontend/.gitignore
vendored
Normal file
23
frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
16650
frontend/package-lock.json
generated
Normal file
16650
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
frontend/package.json
Normal file
40
frontend/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-scripts": "4.0.3",
|
||||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
"proxy": "http://localhost:8080",
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
BIN
frontend/public/favicon.ico
Normal file
BIN
frontend/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
59
frontend/public/index.html
Normal file
59
frontend/public/index.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
BIN
frontend/public/logo192.png
Normal file
BIN
frontend/public/logo192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
frontend/public/logo512.png
Normal file
BIN
frontend/public/logo512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
25
frontend/public/manifest.json
Normal file
25
frontend/public/manifest.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
54
frontend/src/App.css
Normal file
54
frontend/src/App.css
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 40vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
49
frontend/src/App.js
Normal file
49
frontend/src/App.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
|
||||
function App() {
|
||||
const [message, setMessage] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
fetch('cluster/list.query')
|
||||
.then(response => response.text())
|
||||
.then(message => {
|
||||
setMessage(message);
|
||||
});
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" height="60"/>
|
||||
<p>
|
||||
Edit <code>src/App.js</code> and save to reload.
|
||||
</p>
|
||||
</header>
|
||||
<h1>ClusterInfo</h1>
|
||||
<p>
|
||||
{message}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
24
frontend/src/App.test.js
Normal file
24
frontend/src/App.test.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
29
frontend/src/index.css
Normal file
29
frontend/src/index.css
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
33
frontend/src/index.js
Normal file
33
frontend/src/index.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
17
frontend/src/logo.svg
Normal file
17
frontend/src/logo.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
After Width: | Height: | Size: 3.4 KiB |
29
frontend/src/reportWebVitals.js
Normal file
29
frontend/src/reportWebVitals.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
21
frontend/src/setupTests.js
Normal file
21
frontend/src/setupTests.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
11595
frontend/yarn.lock
Normal file
11595
frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "rocketmq-dashboard",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
181
pom.xml
181
pom.xml
@@ -1,7 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache</groupId>
|
||||
@@ -10,12 +25,19 @@
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.apache</groupId>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-dashboard</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>2.0.0</version>
|
||||
<version>2.0.1-SNAPSHOT</version>
|
||||
<name>rocketmq-dashboard</name>
|
||||
|
||||
<scm>
|
||||
<url>git@github.com:apache/rocketmq-dashboard.git</url>
|
||||
<connection>scm:git:git@github.com:apache/rocketmq-dashboard.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:apache/rocketmq-dashboard.git</developerConnection>
|
||||
<tag>1.0.0</tag>
|
||||
</scm>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>Development List</name>
|
||||
@@ -45,6 +67,11 @@
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<organization>
|
||||
<name>Apache Software Foundation</name>
|
||||
<url>http://www.apache.org</url>
|
||||
</organization>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
@@ -63,15 +90,24 @@
|
||||
<commons-lang.version>2.6</commons-lang.version>
|
||||
<commons-io.version>2.4</commons-io.version>
|
||||
<commons-cli.version>1.2</commons-cli.version>
|
||||
<rocketmq.version>4.9.0</rocketmq.version>
|
||||
<commons-collections.version>3.2.2</commons-collections.version>
|
||||
<rocketmq.version>5.1.0</rocketmq.version>
|
||||
<surefire.version>2.19.1</surefire.version>
|
||||
<aspectj.version>1.9.6</aspectj.version>
|
||||
<lombok.version>1.18.12</lombok.version>
|
||||
<lombok.version>1.18.22</lombok.version>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<docker.image.prefix>apacherocketmq</docker.image.prefix>
|
||||
<spring.boot.version>2.2.2.RELEASE</spring.boot.version>
|
||||
<spring.boot.version>2.6.0</spring.boot.version>
|
||||
<mockito-inline.version>3.3.3</mockito-inline.version>
|
||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||
<commons-pool2.version>2.4.3</commons-pool2.version>
|
||||
<easyexcel.version>2.2.10</easyexcel.version>
|
||||
<asm.version>4.2</asm.version>
|
||||
<junit.version>4.12</junit.version>
|
||||
<snakeyaml.version>1.32</snakeyaml.version>
|
||||
<cglib.version>2.2.2</cglib.version>
|
||||
<joor.version>0.9.6</joor.version>
|
||||
<bcpkix-jdk15on.version>1.68</bcpkix-jdk15on.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -95,11 +131,22 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<version>${commons-collections.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
@@ -139,6 +186,7 @@
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-broker</artifactId>
|
||||
<version>${rocketmq.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
@@ -173,17 +221,17 @@
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<version>${cglib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jooq</groupId>
|
||||
<artifactId>joor</artifactId>
|
||||
<version>0.9.6</version>
|
||||
<version>${joor.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.68</version>
|
||||
<version>${bcpkix-jdk15on.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
@@ -201,6 +249,33 @@
|
||||
<version>${mockito-inline.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
<version>${commons-pool2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>${easyexcel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>${asm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -314,7 +389,87 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.rat</groupId>
|
||||
<artifactId>apache-rat-plugin</artifactId>
|
||||
<version>0.12</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>.gitignore</exclude>
|
||||
<exclude>.travis.yml</exclude>
|
||||
<exclude>.asf.yaml</exclude>
|
||||
<exclude>README.md</exclude>
|
||||
<exclude>.github/**</exclude>
|
||||
<exclude>docs/**</exclude>
|
||||
<exclude>src/main/resources/static/vendor/**</exclude>
|
||||
<exclude>src/main/resources/static/src/data/**</exclude>
|
||||
<exclude>frontend/node_modules/**</exclude>
|
||||
<exclude>frontend/build/**</exclude>
|
||||
<exclude>frontend/**.json</exclude>
|
||||
<exclude>frontend/**.lock</exclude>
|
||||
<exclude>frontend/public/manifest.json</exclude>
|
||||
<exclude>package-lock.json</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>1.11.3</version>
|
||||
<configuration>
|
||||
<workingDirectory>frontend</workingDirectory>
|
||||
<installDirectory>target</installDirectory>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>install node and yarn</id>
|
||||
<goals>
|
||||
<goal>install-node-and-yarn</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<nodeVersion>v16.2.0</nodeVersion>
|
||||
<yarnVersion>v1.22.10</yarnVersion>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>yarn install</id>
|
||||
<goals>
|
||||
<goal>yarn</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<arguments>install</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>yarn build</id>
|
||||
<goals>
|
||||
<goal>yarn</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<arguments>build</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<copy todir="${project.build.directory}/classes/public">
|
||||
<fileset dir="${project.basedir}/frontend/build" />
|
||||
</copy>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
@@ -1,3 +1,20 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
FROM java:8
|
||||
VOLUME /tmp
|
||||
ADD rocketmq-dashboard-*.jar rocketmq-dashboard.jar
|
||||
|
@@ -19,11 +19,14 @@ package org.apache.rocketmq.dashboard;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||
import org.springframework.context.annotation.EnableMBeanExport;
|
||||
import org.springframework.jmx.support.RegistrationPolicy;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@ServletComponentScan
|
||||
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
|
||||
public class App {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.admin;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
||||
import org.apache.rocketmq.acl.common.SessionCredentials;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.remoting.RPCHook;
|
||||
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
|
||||
@Slf4j
|
||||
public class MQAdminFactory {
|
||||
private RMQConfigure rmqConfigure;
|
||||
|
||||
public MQAdminFactory(RMQConfigure rmqConfigure) {
|
||||
this.rmqConfigure = rmqConfigure;
|
||||
}
|
||||
|
||||
private final AtomicLong adminIndex = new AtomicLong(0);
|
||||
|
||||
public MQAdminExt getInstance() throws Exception {
|
||||
RPCHook rpcHook = null;
|
||||
final String accessKey = rmqConfigure.getAccessKey();
|
||||
final String secretKey = rmqConfigure.getSecretKey();
|
||||
boolean isEnableAcl = StringUtils.isNotEmpty(accessKey) && StringUtils.isNotEmpty(secretKey);
|
||||
if (isEnableAcl) {
|
||||
rpcHook = new AclClientRPCHook(new SessionCredentials(accessKey, secretKey));
|
||||
}
|
||||
DefaultMQAdminExt mqAdminExt = null;
|
||||
if (rmqConfigure.getTimeoutMillis() == null) {
|
||||
mqAdminExt = new DefaultMQAdminExt(rpcHook);
|
||||
} else {
|
||||
mqAdminExt = new DefaultMQAdminExt(rpcHook, rmqConfigure.getTimeoutMillis());
|
||||
}
|
||||
mqAdminExt.setAdminExtGroup(mqAdminExt.getAdminExtGroup() + "_" + adminIndex.getAndIncrement());
|
||||
mqAdminExt.setVipChannelEnabled(Boolean.parseBoolean(rmqConfigure.getIsVIPChannel()));
|
||||
mqAdminExt.setUseTLS(rmqConfigure.isUseTLS());
|
||||
mqAdminExt.setInstanceName(Long.toString(System.currentTimeMillis()));
|
||||
mqAdminExt.start();
|
||||
log.info("create MQAdmin instance {} success.", mqAdminExt);
|
||||
return mqAdminExt;
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.admin;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.PooledObjectFactory;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
|
||||
@Slf4j
|
||||
public class MQAdminPooledObjectFactory implements PooledObjectFactory<MQAdminExt> {
|
||||
|
||||
private MQAdminFactory mqAdminFactory;
|
||||
|
||||
@Override
|
||||
public PooledObject<MQAdminExt> makeObject() throws Exception {
|
||||
DefaultPooledObject<MQAdminExt> pooledObject = new DefaultPooledObject<>(
|
||||
mqAdminFactory.getInstance());
|
||||
return pooledObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject<MQAdminExt> p) {
|
||||
MQAdminExt mqAdmin = p.getObject();
|
||||
if (mqAdmin != null) {
|
||||
try {
|
||||
mqAdmin.shutdown();
|
||||
} catch (Exception e) {
|
||||
log.warn("MQAdminExt shutdown err", e);
|
||||
}
|
||||
}
|
||||
log.info("destroy object {}", p.getObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(PooledObject<MQAdminExt> p) {
|
||||
MQAdminExt mqAdmin = p.getObject();
|
||||
ClusterInfo clusterInfo = null;
|
||||
try {
|
||||
clusterInfo = mqAdmin.examineBrokerClusterInfo();
|
||||
} catch (Exception e) {
|
||||
log.warn("validate object {} err", p.getObject(), e);
|
||||
}
|
||||
if (clusterInfo == null || MapUtils.isEmpty(clusterInfo.getBrokerAddrTable())) {
|
||||
log.warn("validateObject failed, clusterInfo = {}", clusterInfo);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(PooledObject<MQAdminExt> p) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(PooledObject<MQAdminExt> p) {
|
||||
}
|
||||
|
||||
public void setMqAdminFactory(MQAdminFactory mqAdminFactory) {
|
||||
this.mqAdminFactory = mqAdminFactory;
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.admin;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class MqAdminExtObjectPool {
|
||||
|
||||
@Autowired
|
||||
private RMQConfigure rmqConfigure;
|
||||
|
||||
@Bean
|
||||
public GenericObjectPool<MQAdminExt> mqAdminExtPool() {
|
||||
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
|
||||
genericObjectPoolConfig.setTestWhileIdle(true);
|
||||
genericObjectPoolConfig.setMaxWaitMillis(10000);
|
||||
genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis(20000);
|
||||
MQAdminPooledObjectFactory mqAdminPooledObjectFactory = new MQAdminPooledObjectFactory();
|
||||
MQAdminFactory mqAdminFactory = new MQAdminFactory(rmqConfigure);
|
||||
mqAdminPooledObjectFactory.setMqAdminFactory(mqAdminFactory);
|
||||
GenericObjectPool<MQAdminExt> genericObjectPool = new GenericObjectPool<MQAdminExt>(
|
||||
mqAdminPooledObjectFactory,
|
||||
genericObjectPoolConfig);
|
||||
return genericObjectPool;
|
||||
}
|
||||
}
|
@@ -16,28 +16,24 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.aspect.admin;
|
||||
|
||||
import org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.rocketmq.dashboard.service.client.MQAdminInstance;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Aspect
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MQAdminAspect {
|
||||
private Logger logger = LoggerFactory.getLogger(MQAdminAspect.class);
|
||||
|
||||
@Autowired
|
||||
private RMQConfigure rmqConfigure;
|
||||
private GenericObjectPool<MQAdminExt> mqAdminExtPool;
|
||||
|
||||
public MQAdminAspect() {
|
||||
}
|
||||
@@ -47,30 +43,16 @@ public class MQAdminAspect {
|
||||
|
||||
}
|
||||
|
||||
@Pointcut("@annotation(org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod)")
|
||||
public void multiMQAdminMethodPointCut() {
|
||||
|
||||
}
|
||||
|
||||
@Around(value = "mQAdminMethodPointCut() || multiMQAdminMethodPointCut()")
|
||||
@Around(value = "mQAdminMethodPointCut()")
|
||||
public Object aroundMQAdminMethod(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
long start = System.currentTimeMillis();
|
||||
Object obj = null;
|
||||
try {
|
||||
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
MultiMQAdminCmdMethod multiMQAdminCmdMethod = method.getAnnotation(MultiMQAdminCmdMethod.class);
|
||||
if (multiMQAdminCmdMethod != null && multiMQAdminCmdMethod.timeoutMillis() > 0) {
|
||||
MQAdminInstance.initMQAdminInstance(multiMQAdminCmdMethod.timeoutMillis(),rmqConfigure.getAccessKey(),rmqConfigure.getSecretKey(), rmqConfigure.isUseTLS());
|
||||
}
|
||||
else {
|
||||
MQAdminInstance.initMQAdminInstance(0,rmqConfigure.getAccessKey(),rmqConfigure.getSecretKey(), rmqConfigure.isUseTLS());
|
||||
}
|
||||
MQAdminInstance.createMQAdmin(mqAdminExtPool);
|
||||
obj = joinPoint.proceed();
|
||||
}
|
||||
finally {
|
||||
MQAdminInstance.destroyMQAdminInstance();
|
||||
logger.debug("op=look method={} cost={}", joinPoint.getSignature().getName(), System.currentTimeMillis() - start);
|
||||
} finally {
|
||||
MQAdminInstance.returnMQAdmin(mqAdminExtPool);
|
||||
log.debug("op=look method={} cost={}", joinPoint.getSignature().getName(), System.currentTimeMillis() - start);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -52,6 +53,7 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
"/cluster/**",
|
||||
"/consumer/**",
|
||||
"/dashboard/**",
|
||||
"/dlqMessage/**",
|
||||
"/message/**",
|
||||
"/messageTrace/**",
|
||||
"/monitor/**",
|
||||
@@ -59,7 +61,8 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
"/ops/**",
|
||||
"/producer/**",
|
||||
"/test/**",
|
||||
"/topic/**");
|
||||
"/topic/**",
|
||||
"/acl/**");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +89,9 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
|
||||
super.addArgumentResolvers(argumentResolvers); //REVIEW ME
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("*.htm").setViewName("forward:/app.html");
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.config;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "threadpool.config")
|
||||
@Data
|
||||
public class CollectExecutorConfig {
|
||||
private int coreSize = 20;
|
||||
private int maxSize = 20;
|
||||
private long keepAliveTime = 3000L;
|
||||
private int queueSize = 1000;
|
||||
|
||||
@Bean(name = "collectExecutor")
|
||||
public ExecutorService collectExecutor(CollectExecutorConfig collectExecutorConfig) {
|
||||
ExecutorService collectExecutor = new ThreadPoolExecutor(
|
||||
collectExecutorConfig.getCoreSize(),
|
||||
collectExecutorConfig.getMaxSize(),
|
||||
collectExecutorConfig.getKeepAliveTime(),
|
||||
TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingDeque<>(collectExecutorConfig.getQueueSize()),
|
||||
new ThreadFactory() {
|
||||
private final AtomicLong threadIndex = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "collectTopicThread_" + this.threadIndex.incrementAndGet());
|
||||
}
|
||||
},
|
||||
new ThreadPoolExecutor.DiscardOldestPolicy()
|
||||
);
|
||||
return collectExecutor;
|
||||
}
|
||||
}
|
@@ -16,9 +16,10 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@@ -30,6 +31,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.rocketmq.client.ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY;
|
||||
|
||||
@@ -41,6 +43,8 @@ public class RMQConfigure {
|
||||
//use rocketmq.namesrv.addr first,if it is empty,than use system proerty or system env
|
||||
private volatile String namesrvAddr = System.getProperty(MixAll.NAMESRV_ADDR_PROPERTY, System.getenv(MixAll.NAMESRV_ADDR_ENV));
|
||||
|
||||
private volatile String proxyAddr;
|
||||
|
||||
private volatile String isVIPChannel = System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "true");
|
||||
|
||||
|
||||
@@ -48,8 +52,6 @@ public class RMQConfigure {
|
||||
|
||||
private boolean enableDashBoardCollect;
|
||||
|
||||
private String msgTrackTopicName;
|
||||
|
||||
private boolean loginRequired = false;
|
||||
|
||||
private String accessKey;
|
||||
@@ -58,6 +60,12 @@ public class RMQConfigure {
|
||||
|
||||
private boolean useTLS = false;
|
||||
|
||||
private Long timeoutMillis;
|
||||
|
||||
private List<String> namesrvAddrs = new ArrayList<>();
|
||||
|
||||
private List<String> proxyAddrs = new ArrayList<>();
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
@@ -78,6 +86,36 @@ public class RMQConfigure {
|
||||
return namesrvAddr;
|
||||
}
|
||||
|
||||
public List<String> getNamesrvAddrs() {
|
||||
return namesrvAddrs;
|
||||
}
|
||||
|
||||
public List<String> getProxyAddrs() {
|
||||
return this.proxyAddrs;
|
||||
}
|
||||
|
||||
public void setProxyAddrs(List<String> proxyAddrs) {
|
||||
this.proxyAddrs = proxyAddrs;
|
||||
if (CollectionUtils.isNotEmpty(proxyAddrs)) {
|
||||
this.setProxyAddr(proxyAddrs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
public String getProxyAddr() {
|
||||
return proxyAddr;
|
||||
}
|
||||
|
||||
public void setProxyAddr(String proxyAddr) {
|
||||
this.proxyAddr = proxyAddr;
|
||||
}
|
||||
|
||||
public void setNamesrvAddrs(List<String> namesrvAddrs) {
|
||||
this.namesrvAddrs = namesrvAddrs;
|
||||
if (CollectionUtils.isNotEmpty(namesrvAddrs)) {
|
||||
this.setNamesrvAddr(namesrvAddrs.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void setNamesrvAddr(String namesrvAddr) {
|
||||
if (StringUtils.isNotBlank(namesrvAddr)) {
|
||||
this.namesrvAddr = namesrvAddr;
|
||||
@@ -121,17 +159,6 @@ public class RMQConfigure {
|
||||
this.enableDashBoardCollect = Boolean.valueOf(enableDashBoardCollect);
|
||||
}
|
||||
|
||||
public String getMsgTrackTopicNameOrDefault() {
|
||||
if (StringUtils.isEmpty(msgTrackTopicName)) {
|
||||
return TopicValidator.RMQ_SYS_TRACE_TOPIC;
|
||||
}
|
||||
return msgTrackTopicName;
|
||||
}
|
||||
|
||||
public void setMsgTrackTopicName(String msgTrackTopicName) {
|
||||
this.msgTrackTopicName = msgTrackTopicName;
|
||||
}
|
||||
|
||||
public boolean isLoginRequired() {
|
||||
return loginRequired;
|
||||
}
|
||||
@@ -148,6 +175,14 @@ public class RMQConfigure {
|
||||
this.useTLS = useTLS;
|
||||
}
|
||||
|
||||
public Long getTimeoutMillis() {
|
||||
return timeoutMillis;
|
||||
}
|
||||
|
||||
public void setTimeoutMillis(Long timeoutMillis) {
|
||||
this.timeoutMillis = timeoutMillis;
|
||||
}
|
||||
|
||||
// Error Page process logic, move to a central configure later
|
||||
@Bean
|
||||
public ErrorPageRegistrar errorPageRegistrar() {
|
||||
|
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.User;
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.AclService;
|
||||
import org.apache.rocketmq.dashboard.support.JsonResult;
|
||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/acl")
|
||||
@Permission
|
||||
public class AclController {
|
||||
|
||||
@Resource
|
||||
private AclService aclService;
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@GetMapping("/enable.query")
|
||||
public Object isEnableAcl() {
|
||||
return new JsonResult<>(configure.isACLEnabled());
|
||||
}
|
||||
|
||||
@GetMapping("/config.query")
|
||||
public AclConfig getAclConfig(HttpServletRequest request) {
|
||||
if (!configure.isLoginRequired()) {
|
||||
return aclService.getAclConfig(false);
|
||||
}
|
||||
UserInfo userInfo = (UserInfo) WebUtil.getValueFromSession(request, WebUtil.USER_INFO);
|
||||
// if user info is null but reach here, must exclude secret key for safety.
|
||||
return aclService.getAclConfig(userInfo == null || userInfo.getUser().getType() != User.ADMIN);
|
||||
}
|
||||
|
||||
@PostMapping("/add.do")
|
||||
public Object addAclConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getSecretKey()), "secretKey is null");
|
||||
aclService.addAclConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/delete.do")
|
||||
public Object deleteAclConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getAccessKey()), "accessKey is null");
|
||||
aclService.deleteAclConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/update.do")
|
||||
public Object updateAclConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getSecretKey()), "secretKey is null");
|
||||
aclService.updateAclConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/topic/add.do")
|
||||
public Object addAclTopicConfig(@RequestBody AclRequest request) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getSecretKey()), "secretKey is null");
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(request.getConfig().getTopicPerms()), "topic perms is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getTopicPerm()), "topic perm is null");
|
||||
aclService.addOrUpdateAclTopicConfig(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/group/add.do")
|
||||
public Object addAclGroupConfig(@RequestBody AclRequest request) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getSecretKey()), "secretKey is null");
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(request.getConfig().getGroupPerms()), "group perms is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getGroupPerm()), "group perm is null");
|
||||
aclService.addOrUpdateAclGroupConfig(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/perm/delete.do")
|
||||
public Object deletePermConfig(@RequestBody AclRequest request) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(request.getConfig().getSecretKey()), "secretKey is null");
|
||||
aclService.deletePermConfig(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/sync.do")
|
||||
public Object syncConfig(@RequestBody PlainAccessConfig config) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getAccessKey()), "accessKey is null");
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(config.getSecretKey()), "secretKey is null");
|
||||
aclService.syncData(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/white/list/add.do")
|
||||
public Object addWhiteList(@RequestBody List<String> whiteList) {
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(whiteList), "white list is null");
|
||||
aclService.addWhiteList(whiteList);
|
||||
return true;
|
||||
}
|
||||
|
||||
@DeleteMapping("/white/list/delete.do")
|
||||
public Object deleteWhiteAddr(@RequestParam String request) {
|
||||
aclService.deleteWhiteAddr(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/white/list/sync.do")
|
||||
public Object synchronizeWhiteList(@RequestBody List<String> whiteList) {
|
||||
Preconditions.checkArgument(CollectionUtils.isNotEmpty(whiteList), "white list is null");
|
||||
aclService.synchronizeWhiteList(whiteList);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ClusterService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/cluster")
|
||||
@Permission
|
||||
public class ClusterController {
|
||||
|
||||
@Resource
|
||||
|
@@ -19,11 +19,12 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
import com.google.common.base.Preconditions;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.dashboard.model.ConnectionInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ConsumerService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.slf4j.Logger;
|
||||
@@ -37,6 +38,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/consumer")
|
||||
@Permission
|
||||
public class ConsumerController {
|
||||
private Logger logger = LoggerFactory.getLogger(ConsumerController.class);
|
||||
|
||||
@@ -45,14 +47,14 @@ public class ConsumerController {
|
||||
|
||||
@RequestMapping(value = "/groupList.query")
|
||||
@ResponseBody
|
||||
public Object list() {
|
||||
return consumerService.queryGroupList();
|
||||
public Object list(@RequestParam(value = "skipSysGroup", required = false) boolean skipSysGroup, String address) {
|
||||
return consumerService.queryGroupList(skipSysGroup, address);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/group.query")
|
||||
@ResponseBody
|
||||
public Object groupQuery(@RequestParam String consumerGroup) {
|
||||
return consumerService.queryGroup(consumerGroup);
|
||||
public Object groupQuery(@RequestParam String consumerGroup, String address) {
|
||||
return consumerService.queryGroup(consumerGroup, address);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/resetOffset.do", method = {RequestMethod.POST})
|
||||
@@ -97,14 +99,14 @@ public class ConsumerController {
|
||||
|
||||
@RequestMapping(value = "/queryTopicByConsumer.query")
|
||||
@ResponseBody
|
||||
public Object queryConsumerByTopic(@RequestParam String consumerGroup) {
|
||||
return consumerService.queryConsumeStatsListByGroupName(consumerGroup);
|
||||
public Object queryConsumerByTopic(@RequestParam String consumerGroup, String address) {
|
||||
return consumerService.queryConsumeStatsListByGroupName(consumerGroup, address);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/consumerConnection.query")
|
||||
@ResponseBody
|
||||
public Object consumerConnection(@RequestParam(required = false) String consumerGroup) {
|
||||
ConsumerConnection consumerConnection = consumerService.getConsumerConnection(consumerGroup);
|
||||
public Object consumerConnection(@RequestParam(required = false) String consumerGroup, String address) {
|
||||
ConsumerConnection consumerConnection = consumerService.getConsumerConnection(consumerGroup, address);
|
||||
consumerConnection.setConnectionSet(ConnectionInfo.buildConnectionInfoHashSet(consumerConnection.getConnectionSet()));
|
||||
return consumerConnection;
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.DashboardService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -29,6 +30,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/dashboard")
|
||||
@Permission
|
||||
public class DashboardController {
|
||||
|
||||
@Resource
|
||||
@@ -49,7 +51,7 @@ public class DashboardController {
|
||||
return dashboardService.queryTopicData(date,topicName);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/topicCurrent", method = RequestMethod.GET)
|
||||
@RequestMapping(value = "/topicCurrent.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object topicCurrent() {
|
||||
return dashboardService.queryTopicCurrentData();
|
||||
|
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageExcelModel;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.DlqMessageService;
|
||||
import org.apache.rocketmq.dashboard.util.ExcelUtil;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/dlqMessage")
|
||||
@Permission
|
||||
@Slf4j
|
||||
public class DlqMessageController {
|
||||
|
||||
@Resource
|
||||
private DlqMessageService dlqMessageService;
|
||||
|
||||
@Resource
|
||||
private MQAdminExt mqAdminExt;
|
||||
|
||||
@RequestMapping(value = "/queryDlqMessageByConsumerGroup.query", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object queryDlqMessageByConsumerGroup(@RequestBody MessageQuery query) {
|
||||
return dlqMessageService.queryDlqMessageByPage(query);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/exportDlqMessage.do")
|
||||
public void exportDlqMessage(HttpServletResponse response, @RequestParam String consumerGroup,
|
||||
@RequestParam String msgId) {
|
||||
MessageExt messageExt = null;
|
||||
try {
|
||||
String topic = MixAll.DLQ_GROUP_TOPIC_PREFIX + consumerGroup;
|
||||
messageExt = mqAdminExt.viewMessage(topic, msgId);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(-1, String.format("Failed to query message by Id: %s", msgId));
|
||||
}
|
||||
DlqMessageExcelModel excelModel = new DlqMessageExcelModel(messageExt);
|
||||
try {
|
||||
ExcelUtil.writeExcel(response, Lists.newArrayList(excelModel), "dlq", "dlq", DlqMessageExcelModel.class);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(-1, String.format("export dlq message failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/batchResendDlqMessage.do")
|
||||
@ResponseBody
|
||||
public Object batchResendDlqMessage(@RequestBody List<DlqMessageRequest> dlqMessages) {
|
||||
return dlqMessageService.batchResendDlqMessage(dlqMessages);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/batchExportDlqMessage.do")
|
||||
public void batchExportDlqMessage(HttpServletResponse response, @RequestBody List<DlqMessageRequest> dlqMessages) {
|
||||
List<DlqMessageExcelModel> dlqMessageExcelModelList = new ArrayList<>(dlqMessages.size());
|
||||
for (DlqMessageRequest dlqMessage : dlqMessages) {
|
||||
DlqMessageExcelModel excelModel = new DlqMessageExcelModel();
|
||||
try {
|
||||
String topic = MixAll.DLQ_GROUP_TOPIC_PREFIX + dlqMessage.getConsumerGroup();
|
||||
MessageExt messageExt = mqAdminExt.viewMessage(topic, dlqMessage.getMsgId());
|
||||
excelModel = new DlqMessageExcelModel(messageExt);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to query message by Id:{}", dlqMessage.getMsgId(), e);
|
||||
excelModel.setMsgId(dlqMessage.getMsgId());
|
||||
excelModel.setException(e.getMessage());
|
||||
}
|
||||
dlqMessageExcelModelList.add(excelModel);
|
||||
}
|
||||
try {
|
||||
ExcelUtil.writeExcel(response, dlqMessageExcelModelList, "dlqs", "dlqs", DlqMessageExcelModel.class);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(-1, String.format("export dlq message failed!"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.LoginInfo;
|
||||
import org.apache.rocketmq.dashboard.model.LoginResult;
|
||||
import org.apache.rocketmq.dashboard.model.User;
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
import org.apache.rocketmq.dashboard.service.UserService;
|
||||
@@ -65,7 +66,7 @@ public class LoginController {
|
||||
|
||||
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public JsonResult<String> login(@RequestParam("username") String username,
|
||||
public Object login(@RequestParam("username") String username,
|
||||
@RequestParam(value = "password") String password,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) throws Exception {
|
||||
@@ -80,7 +81,8 @@ public class LoginController {
|
||||
WebUtil.setSessionValue(request, WebUtil.USER_INFO, userInfo);
|
||||
WebUtil.setSessionValue(request, WebUtil.USER_NAME, username);
|
||||
userInfo.setSessionId(WebUtil.getSessionId(request));
|
||||
return new JsonResult<>(contextPath);
|
||||
LoginResult result = new LoginResult(username, user.getType(), contextPath);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,10 +18,11 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.MessageService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
@@ -41,6 +42,7 @@ import java.util.Map;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/message")
|
||||
@Permission
|
||||
public class MessageController {
|
||||
private Logger logger = LoggerFactory.getLogger(MessageController.class);
|
||||
@Resource
|
||||
|
@@ -26,6 +26,7 @@ import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||
import org.apache.rocketmq.dashboard.model.trace.MessageTraceGraph;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.MessageService;
|
||||
import org.apache.rocketmq.dashboard.service.MessageTraceService;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
@@ -37,6 +38,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/messageTrace")
|
||||
@Permission
|
||||
public class MessageTraceController {
|
||||
|
||||
@Resource
|
||||
@@ -62,7 +64,8 @@ public class MessageTraceController {
|
||||
|
||||
@RequestMapping(value = "/viewMessageTraceGraph.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public MessageTraceGraph viewMessageTraceGraph(@RequestParam String msgId) {
|
||||
return messageTraceService.queryMessageTraceGraph(msgId);
|
||||
public MessageTraceGraph viewMessageTraceGraph(@RequestParam String msgId,
|
||||
@RequestParam(required = false) String traceTopic) {
|
||||
return messageTraceService.queryMessageTraceGraph(msgId, traceTopic);
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.MonitorService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -29,6 +30,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/monitor")
|
||||
@Permission
|
||||
public class MonitorController {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(MonitorController.class);
|
||||
|
@@ -18,6 +18,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.dashboard.aspect.admin.annotation.OriginalControllerReturnValue;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.OpsService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -26,11 +27,12 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/rocketmq")
|
||||
@Permission
|
||||
public class NamesvrController {
|
||||
@Resource
|
||||
private OpsService opsService;
|
||||
|
||||
@RequestMapping(value = "/nsaddr", method = RequestMethod.GET)
|
||||
@RequestMapping(value = "/nsaddr.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
@OriginalControllerReturnValue
|
||||
public Object nsaddr() {
|
||||
|
@@ -16,7 +16,10 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.OpsService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -26,6 +29,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/ops")
|
||||
@Permission
|
||||
public class OpsController {
|
||||
|
||||
@Resource
|
||||
@@ -44,6 +48,15 @@ public class OpsController {
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/addNameSvrAddr.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object addNameSvrAddr(@RequestParam String newNamesrvAddr) {
|
||||
Preconditions.checkArgument(StringUtils.isNotEmpty(newNamesrvAddr),
|
||||
"namesrvAddr can not be blank");
|
||||
opsService.addNameSvrAddr(newNamesrvAddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/updateIsVIPChannel.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object updateIsVIPChannel(@RequestParam String useVIPChannel) {
|
||||
@@ -51,14 +64,12 @@ public class OpsController {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/rocketMqStatus.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object clusterStatus() {
|
||||
return opsService.rocketMqStatusCheck();
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/updateUseTLS.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object updateUseTLS(@RequestParam String useTLS) {
|
||||
|
@@ -17,8 +17,9 @@
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.dashboard.model.ConnectionInfo;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ProducerService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/producer")
|
||||
@Permission
|
||||
public class ProducerController {
|
||||
|
||||
@Resource
|
||||
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ProxyService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/proxy")
|
||||
@Permission
|
||||
public class ProxyController {
|
||||
@Resource
|
||||
private ProxyService proxyService;
|
||||
@RequestMapping(value = "/homePage.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object homePage() {
|
||||
return proxyService.getProxyHomePage();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/addProxyAddr.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object addProxyAddr(@RequestParam String newProxyAddr) {
|
||||
proxyService.addProxyAddrList(newProxyAddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/updateProxyAddr.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object updateProxyAddr(@RequestParam String proxyAddr) {
|
||||
proxyService.updateProxyAddrList(proxyAddr);
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -17,6 +17,7 @@
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingException;
|
||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||
@@ -38,6 +39,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/topic")
|
||||
@Permission
|
||||
public class TopicController {
|
||||
private Logger logger = LoggerFactory.getLogger(TopicController.class);
|
||||
|
||||
@@ -49,13 +51,15 @@ public class TopicController {
|
||||
|
||||
@RequestMapping(value = "/list.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object list(@RequestParam(value = "skipSysProcess", required = false) String skipSysProcess)
|
||||
throws MQClientException, RemotingException, InterruptedException {
|
||||
boolean flag = false;
|
||||
if ("true".equals(skipSysProcess)) {
|
||||
flag = true;
|
||||
public Object list(@RequestParam(value = "skipSysProcess", required = false) boolean skipSysProcess,
|
||||
@RequestParam(value = "skipRetryAndDlq", required = false) boolean skipRetryAndDlq) {
|
||||
return topicService.fetchAllTopicList(skipSysProcess, skipRetryAndDlq);
|
||||
}
|
||||
return topicService.fetchAllTopicList(flag);
|
||||
|
||||
@RequestMapping(value = "/list.queryTopicType", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object listTopicType() {
|
||||
return topicService.examineAllTopicType();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/stats.query", method = RequestMethod.GET)
|
||||
|
@@ -20,7 +20,7 @@ import com.google.common.collect.Sets;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import org.apache.rocketmq.common.MQVersion;
|
||||
import org.apache.rocketmq.common.protocol.body.Connection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||
|
||||
public class ConnectionInfo extends Connection {
|
||||
private String versionDesc;
|
||||
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.alibaba.excel.metadata.BaseRowModel;
|
||||
import com.alibaba.excel.util.DateUtils;
|
||||
import com.google.common.base.Charsets;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class DlqMessageExcelModel extends BaseRowModel implements Serializable {
|
||||
|
||||
@ExcelProperty(value = "topic", index = 0)
|
||||
@ColumnWidth(value = 15)
|
||||
private String topic;
|
||||
|
||||
@ExcelProperty(value = "msgId", index = 1)
|
||||
@ColumnWidth(value = 15)
|
||||
private String msgId;
|
||||
|
||||
@ExcelProperty(value = "bornHost", index = 2)
|
||||
@ColumnWidth(value = 15)
|
||||
private String bornHost;
|
||||
|
||||
@ExcelProperty(value = "bornTimestamp", index = 3)
|
||||
@ColumnWidth(value = 25)
|
||||
private String bornTimestamp;
|
||||
|
||||
@ExcelProperty(value = "storeTimestamp", index = 4)
|
||||
@ColumnWidth(value = 25)
|
||||
private String storeTimestamp;
|
||||
|
||||
@ExcelProperty(value = "reconsumeTimes", index = 5)
|
||||
@ColumnWidth(value = 25)
|
||||
private int reconsumeTimes;
|
||||
|
||||
@ExcelProperty(value = "properties", index = 6)
|
||||
@ColumnWidth(value = 20)
|
||||
private String properties;
|
||||
|
||||
@ExcelProperty(value = "messageBody", index = 7)
|
||||
@ColumnWidth(value = 20)
|
||||
private String messageBody;
|
||||
|
||||
@ExcelProperty(value = "bodyCRC", index = 8)
|
||||
@ColumnWidth(value = 15)
|
||||
private int bodyCRC;
|
||||
|
||||
@ExcelProperty(value = "exception", index = 9)
|
||||
@ColumnWidth(value = 30)
|
||||
private String exception;
|
||||
|
||||
public DlqMessageExcelModel(MessageExt messageExt) {
|
||||
this.topic = messageExt.getTopic();
|
||||
this.msgId = messageExt.getMsgId();
|
||||
this.bornHost = messageExt.getBornHostString();
|
||||
this.bornTimestamp = DateUtils.format(new Date(messageExt.getBornTimestamp()), DateUtils.DATE_FORMAT_19);
|
||||
this.storeTimestamp = DateUtils.format(new Date(messageExt.getStoreTimestamp()), DateUtils.DATE_FORMAT_19);
|
||||
this.reconsumeTimes = messageExt.getReconsumeTimes();
|
||||
this.properties = messageExt.getProperties().toString();
|
||||
this.messageBody = new String(messageExt.getBody(), Charsets.UTF_8);
|
||||
this.bodyCRC = messageExt.getBodyCRC();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DlqMessageRequest {
|
||||
|
||||
private String topicName;
|
||||
|
||||
private String consumerGroup;
|
||||
|
||||
private String msgId;
|
||||
|
||||
private String clientId;
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.rocketmq.remoting.protocol.body.CMResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
|
||||
@Data
|
||||
public class DlqMessageResendResult {
|
||||
private CMResult consumeResult;
|
||||
private String remark;
|
||||
private String msgId;
|
||||
|
||||
public DlqMessageResendResult(ConsumeMessageDirectlyResult consumeMessageDirectlyResult, String msgId) {
|
||||
this.consumeResult = consumeMessageDirectlyResult.getConsumeResult();
|
||||
this.remark = consumeMessageDirectlyResult.getRemark();
|
||||
this.msgId = msgId;
|
||||
}
|
||||
}
|
@@ -16,8 +16,10 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
|
||||
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GroupConsumeInfo implements Comparable<GroupConsumeInfo> {
|
||||
private String group;
|
||||
@@ -25,8 +27,11 @@ public class GroupConsumeInfo implements Comparable<GroupConsumeInfo> {
|
||||
private int count;
|
||||
private ConsumeType consumeType;
|
||||
private MessageModel messageModel;
|
||||
private List<String> address;
|
||||
private int consumeTps;
|
||||
private long diffTotal = -1;
|
||||
private String subGroupType = "NORMAL";
|
||||
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
@@ -68,6 +73,22 @@ public class GroupConsumeInfo implements Comparable<GroupConsumeInfo> {
|
||||
this.diffTotal = diffTotal;
|
||||
}
|
||||
|
||||
public List<String> getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(List<String> address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getSubGroupType() {
|
||||
return subGroupType;
|
||||
}
|
||||
|
||||
public void setSubGroupType(String subGroupType) {
|
||||
this.subGroupType = subGroupType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(GroupConsumeInfo o) {
|
||||
if (this.count != o.count) {
|
||||
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class LoginResult {
|
||||
|
||||
private String loginUserName;
|
||||
|
||||
/**
|
||||
* 0: normal 1: admin
|
||||
*/
|
||||
private int loginUserRole;
|
||||
|
||||
private String contextPath;
|
||||
}
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model;
|
||||
|
||||
import org.apache.rocketmq.common.admin.OffsetWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
|
||||
@Data
|
||||
public class AclRequest {
|
||||
|
||||
private PlainAccessConfig config;
|
||||
|
||||
private String topicPerm;
|
||||
|
||||
private String groupPerm;
|
||||
}
|
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import java.util.List;
|
||||
@@ -32,6 +31,7 @@ public class TopicConfigInfo {
|
||||
private int perm;
|
||||
private boolean order;
|
||||
|
||||
private String messageType;
|
||||
public List<String> getClusterNameList() {
|
||||
return clusterNameList;
|
||||
}
|
||||
@@ -92,6 +92,18 @@ public class TopicConfigInfo {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
|
||||
public String getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public void setMessageType(String messageType) {
|
||||
this.messageType = messageType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
@@ -103,12 +115,13 @@ public class TopicConfigInfo {
|
||||
readQueueNums == that.readQueueNums &&
|
||||
perm == that.perm &&
|
||||
order == that.order &&
|
||||
Objects.equal(topicName, that.topicName);
|
||||
Objects.equal(topicName, that.topicName) &&
|
||||
Objects.equal(messageType, that.messageType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order);
|
||||
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order,messageType);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TopicTypeList {
|
||||
private List<String> topicNameList;
|
||||
private List<String> messageTypeList;
|
||||
|
||||
public List<String> getTopicNameList() {
|
||||
return topicNameList;
|
||||
}
|
||||
|
||||
public void setTopicNameList(List<String> topicNameList) {
|
||||
this.topicNameList = topicNameList;
|
||||
}
|
||||
|
||||
public List<String> getMessageTypeList() {
|
||||
return messageTypeList;
|
||||
}
|
||||
|
||||
public void setMessageTypeList(List<String> messageTypeList) {
|
||||
this.messageTypeList = messageTypeList;
|
||||
}
|
||||
|
||||
public TopicTypeList(List<String> topicNameList, List<String> messageTypeList) {
|
||||
this.topicNameList = topicNameList;
|
||||
this.messageTypeList = messageTypeList;
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
public class TopicTypeMeta {
|
||||
private String topicName;
|
||||
private String messageType;
|
||||
|
||||
public String getTopicName() {
|
||||
return topicName;
|
||||
}
|
||||
|
||||
public void setTopicName(String topicName) {
|
||||
this.topicName = topicName;
|
||||
}
|
||||
|
||||
public String getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public void setMessageType(String messageType) {
|
||||
this.messageType = messageType;
|
||||
}
|
||||
}
|
@@ -14,18 +14,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.permisssion;
|
||||
|
||||
package org.apache.rocketmq.dashboard.aspect.admin.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.METHOD})
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface MultiMQAdminCmdMethod {
|
||||
long timeoutMillis() default 0;
|
||||
public @interface Permission {
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.permisssion;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
import org.apache.rocketmq.dashboard.service.PermissionService;
|
||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class PermissionAspect {
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
|
||||
/**
|
||||
* @Permission can be applied to the Controller class to implement Permission verification on all methods in the class
|
||||
* can also be applied to methods in a class for fine control
|
||||
*/
|
||||
@Pointcut("@annotation(org.apache.rocketmq.dashboard.permisssion.Permission) || @within(org.apache.rocketmq.dashboard.permisssion.Permission)")
|
||||
private void permission() {
|
||||
|
||||
}
|
||||
|
||||
@Around("permission()")
|
||||
public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
if (configure.isLoginRequired()) {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
String url = request.getRequestURI();
|
||||
UserInfo userInfo = (UserInfo) request.getSession().getAttribute(WebUtil.USER_INFO);
|
||||
if (userInfo == null || userInfo.getUser() == null) {
|
||||
throw new ServiceException(-1, "user not login");
|
||||
}
|
||||
boolean checkResult = permissionService.checkUrlAvailable(userInfo, url);
|
||||
if (!checkResult) {
|
||||
throw new ServiceException(-1, "no permission");
|
||||
}
|
||||
}
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.permisssion;
|
||||
|
||||
public enum UserRoleEnum {
|
||||
ADMIN(1, "admin"),
|
||||
ORDINARY(0, "ordinary");
|
||||
|
||||
private int roleType;
|
||||
private String roleName;
|
||||
|
||||
UserRoleEnum(int roleType, String roleName) {
|
||||
this.roleType = roleType;
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public int getRoleType() {
|
||||
return roleType;
|
||||
}
|
||||
|
||||
public String getRoleName() {
|
||||
return roleName;
|
||||
}
|
||||
}
|
@@ -19,8 +19,8 @@ package org.apache.rocketmq.dashboard.service;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
@@ -28,7 +28,7 @@ import org.apache.commons.collections.CollectionUtils;
|
||||
public abstract class AbstractCommonService {
|
||||
@Resource
|
||||
protected MQAdminExt mqAdminExt;
|
||||
protected final Set<String> changeToBrokerNameSet(HashMap<String, Set<String>> clusterAddrTable,
|
||||
protected final Set<String> changeToBrokerNameSet(Map<String, Set<String>> clusterAddrTable,
|
||||
List<String> clusterNameList, List<String> brokerNameList) {
|
||||
Set<String> finalBrokerNameList = Sets.newHashSet();
|
||||
if (CollectionUtils.isNotEmpty(clusterNameList)) {
|
||||
@@ -38,7 +38,8 @@ public abstract class AbstractCommonService {
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(brokerNameList)) {
|
||||
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
|
||||
public interface AclService {
|
||||
|
||||
AclConfig getAclConfig(boolean excludeSecretKey);
|
||||
|
||||
void addAclConfig(PlainAccessConfig config);
|
||||
|
||||
void deleteAclConfig(PlainAccessConfig config);
|
||||
|
||||
void updateAclConfig(PlainAccessConfig config);
|
||||
|
||||
void addOrUpdateAclTopicConfig(AclRequest request);
|
||||
|
||||
void addOrUpdateAclGroupConfig(AclRequest request);
|
||||
|
||||
void deletePermConfig(AclRequest request);
|
||||
|
||||
void syncData(PlainAccessConfig config);
|
||||
|
||||
void addWhiteList(List<String> whiteList);
|
||||
|
||||
void deleteWhiteAddr(String addr);
|
||||
|
||||
void synchronizeWhiteList(List<String> whiteList);
|
||||
}
|
@@ -17,8 +17,8 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.dashboard.model.ConsumerGroupRollBackStat;
|
||||
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
|
||||
import org.apache.rocketmq.dashboard.model.TopicConsumerInfo;
|
||||
@@ -31,12 +31,12 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ConsumerService {
|
||||
List<GroupConsumeInfo> queryGroupList();
|
||||
List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup,String address);
|
||||
|
||||
GroupConsumeInfo queryGroup(String consumerGroup);
|
||||
GroupConsumeInfo queryGroup(String consumerGroup, String address);
|
||||
|
||||
|
||||
List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName);
|
||||
List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName, String address);
|
||||
|
||||
List<TopicConsumerInfo> queryConsumeStatsList(String topic, String groupName);
|
||||
|
||||
@@ -52,7 +52,7 @@ public interface ConsumerService {
|
||||
|
||||
Set<String> fetchBrokerNameSetBySubscriptionGroup(String group);
|
||||
|
||||
ConsumerConnection getConsumerConnection(String consumerGroup);
|
||||
ConsumerConnection getConsumerConnection(String consumerGroup, String address);
|
||||
|
||||
ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack);
|
||||
}
|
||||
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageResendResult;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
|
||||
public interface DlqMessageService {
|
||||
|
||||
MessagePage queryDlqMessageByPage(MessageQuery query);
|
||||
|
||||
List<DlqMessageResendResult> batchResendDlqMessage(List<DlqMessageRequest> dlqMessages);
|
||||
}
|
@@ -19,7 +19,7 @@ package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
|
@@ -27,5 +27,5 @@ public interface MessageTraceService {
|
||||
|
||||
List<MessageTraceView> queryMessageTraceByTopicAndKey(final String topic, final String key);
|
||||
|
||||
MessageTraceGraph queryMessageTraceGraph(final String key);
|
||||
MessageTraceGraph queryMessageTraceGraph(final String key, final String traceTopic);
|
||||
}
|
||||
|
@@ -31,4 +31,6 @@ public interface OpsService {
|
||||
boolean updateIsVIPChannel(String useVIPChannel);
|
||||
|
||||
boolean updateUseTLS(boolean useTLS);
|
||||
|
||||
void addNameSvrAddr(String namesrvAddr);
|
||||
}
|
||||
|
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
|
||||
public interface PermissionService {
|
||||
|
||||
boolean checkUrlAvailable(UserInfo userInfo, String url);
|
||||
}
|
@@ -17,7 +17,7 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
|
||||
public interface ProducerService {
|
||||
ProducerConnection getProducerConnection(String producerGroup, String topic);
|
||||
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ProxyService {
|
||||
|
||||
void addProxyAddrList(String proxyAddr);
|
||||
|
||||
void updateProxyAddrList(String proxyAddr);
|
||||
|
||||
Map<String, Object> getProxyHomePage();
|
||||
}
|
@@ -19,17 +19,20 @@ package org.apache.rocketmq.dashboard.service;
|
||||
|
||||
import org.apache.rocketmq.client.producer.SendResult;
|
||||
import org.apache.rocketmq.common.TopicConfig;
|
||||
import org.apache.rocketmq.common.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TopicService {
|
||||
TopicList fetchAllTopicList(boolean skipSysProcess);
|
||||
TopicList fetchAllTopicList(boolean skipSysProcess, boolean skipRetryAndDlq);
|
||||
|
||||
TopicTypeList examineAllTopicType();
|
||||
|
||||
TopicStatsTable stats(String topic);
|
||||
|
||||
|
@@ -17,43 +17,16 @@
|
||||
package org.apache.rocketmq.dashboard.service.client;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import org.apache.rocketmq.client.QueryResult;
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.client.impl.MQAdminImpl;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.common.TopicConfig;
|
||||
import org.apache.rocketmq.common.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.common.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.RequestCode;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterAclVersionInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeStatsList;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
|
||||
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
|
||||
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.common.message.MessageRequestMode;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.apache.rocketmq.remoting.RemotingClient;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
|
||||
@@ -62,13 +35,51 @@ import org.apache.rocketmq.remoting.exception.RemotingException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
|
||||
import org.apache.rocketmq.remoting.protocol.RequestCode;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.BrokerReplicasInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterAclVersionInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeStatsList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.EpochEntryCache;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.HARuntimeInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerTableInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.QueryConsumeQueueResponseBody;
|
||||
import org.apache.rocketmq.remoting.protocol.body.QueueTimeSpan;
|
||||
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
|
||||
import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader;
|
||||
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingDetail;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.GroupForbidden;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.tools.admin.api.BrokerOperatorResult;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
import org.joor.Reflect;
|
||||
import org.apache.rocketmq.tools.admin.common.AdminToolResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.rocketmq.remoting.protocol.RemotingSerializable.decode;
|
||||
|
||||
@Service
|
||||
@@ -81,7 +92,7 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
@Override
|
||||
public void updateBrokerConfig(String brokerAddr, Properties properties)
|
||||
throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
|
||||
UnsupportedEncodingException, InterruptedException, MQBrokerException {
|
||||
UnsupportedEncodingException, InterruptedException, MQBrokerException, MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().updateBrokerConfig(brokerAddr, properties);
|
||||
}
|
||||
|
||||
@@ -91,29 +102,34 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createAndUpdateTopicConfig(addr, config);
|
||||
}
|
||||
|
||||
@Override public void createAndUpdatePlainAccessConfig(String addr,
|
||||
@Override
|
||||
public void createAndUpdatePlainAccessConfig(String addr,
|
||||
PlainAccessConfig plainAccessConfig) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
|
||||
MQAdminInstance.threadLocalMQAdminExt().createAndUpdatePlainAccessConfig(addr, plainAccessConfig);
|
||||
}
|
||||
|
||||
@Override public void deletePlainAccessConfig(String addr,
|
||||
@Override
|
||||
public void deletePlainAccessConfig(String addr,
|
||||
String accessKey) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
|
||||
MQAdminInstance.threadLocalMQAdminExt().deletePlainAccessConfig(addr, accessKey);
|
||||
}
|
||||
|
||||
@Override public void updateGlobalWhiteAddrConfig(String addr,
|
||||
@Override
|
||||
public void updateGlobalWhiteAddrConfig(String addr,
|
||||
String globalWhiteAddrs) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
|
||||
MQAdminInstance.threadLocalMQAdminExt().updateGlobalWhiteAddrConfig(addr, globalWhiteAddrs);
|
||||
}
|
||||
|
||||
@Override public ClusterAclVersionInfo examineBrokerClusterAclVersionInfo(
|
||||
@Override
|
||||
public ClusterAclVersionInfo examineBrokerClusterAclVersionInfo(
|
||||
String addr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public AclConfig examineBrokerClusterAclConfig(
|
||||
@Override
|
||||
public AclConfig examineBrokerClusterAclConfig(
|
||||
String addr) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
return null;
|
||||
return MQAdminInstance.threadLocalMQAdminExt().examineBrokerClusterAclConfig(addr);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,7 +139,7 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionGroupConfig examineSubscriptionGroupConfig(String addr, String group) {
|
||||
public SubscriptionGroupConfig examineSubscriptionGroupConfig(String addr, String group) throws MQBrokerException {
|
||||
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
|
||||
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_SUBSCRIPTIONGROUP_CONFIG, null);
|
||||
RemotingCommand response = null;
|
||||
@@ -131,7 +147,8 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
response = remotingClient.invokeSync(addr, request, 3000);
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
assert response != null;
|
||||
switch (response.getCode()) {
|
||||
@@ -140,12 +157,12 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
return subscriptionGroupWrapper.getSubscriptionGroupTable().get(group);
|
||||
}
|
||||
default:
|
||||
throw Throwables.propagate(new MQBrokerException(response.getCode(), response.getRemark()));
|
||||
throw new MQBrokerException(response.getCode(), response.getRemark());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfig examineTopicConfig(String addr, String topic) {
|
||||
public TopicConfig examineTopicConfig(String addr, String topic) throws MQBrokerException {
|
||||
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
|
||||
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_TOPIC_CONFIG, null);
|
||||
RemotingCommand response = null;
|
||||
@@ -153,7 +170,8 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
response = remotingClient.invokeSync(addr, request, 3000);
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
switch (response.getCode()) {
|
||||
case ResponseCode.SUCCESS: {
|
||||
@@ -161,7 +179,7 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
return topicConfigSerializeWrapper.getTopicConfigTable().get(topic);
|
||||
}
|
||||
default:
|
||||
throw Throwables.propagate(new MQBrokerException(response.getCode(), response.getRemark()));
|
||||
throw new MQBrokerException(response.getCode(), response.getRemark());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +253,12 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().wipeWritePermOfBroker(namesrvAddr, brokerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addWritePermOfBroker(String namesrvAddr,
|
||||
String brokerName) throws RemotingCommandException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQClientException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().addWritePermOfBroker(namesrvAddr, brokerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putKVConfig(String namespace, String key, String value) {
|
||||
MQAdminInstance.threadLocalMQAdminExt().putKVConfig(namespace, key, value);
|
||||
@@ -272,8 +296,9 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSubscriptionGroup(String addr, String groupName, boolean removeOffset) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
throw new UnsupportedOperationException();
|
||||
public void deleteSubscriptionGroup(String addr, String groupName, boolean removeOffset)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().deleteSubscriptionGroup(addr, groupName, removeOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -364,14 +389,14 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTopic(String key, String newTopic, int queueNum) throws MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum);
|
||||
public void createTopic(String key, String newTopic, int queueNum, Map<String, String> attributes) throws MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag)
|
||||
public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag, Map<String, String> attributes)
|
||||
throws MQClientException {
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, topicSysFlag);
|
||||
MQAdminInstance.threadLocalMQAdminExt().createTopic(key, newTopic, queueNum, topicSysFlag, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -439,16 +464,19 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
MQAdminImpl mqAdminImpl = MQAdminInstance.threadLocalMqClientInstance().getMQAdminImpl();
|
||||
QueryResult qr = Reflect.on(mqAdminImpl).call("queryMessage", topic, msgId, 32,
|
||||
MessageClientIDSetter.getNearlyTimeFromID(msgId).getTime() - 1000 * 60 * 60 * 13L, Long.MAX_VALUE, true).get();
|
||||
if (qr != null && qr.getMessageList() != null && qr.getMessageList().size() > 0) {
|
||||
return qr.getMessageList().get(0);
|
||||
|
||||
Set<String> clusterList = MQAdminInstance.threadLocalMQAdminExt().getTopicClusterList(topic);
|
||||
if (clusterList == null || clusterList.isEmpty()) {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().queryMessage("", topic, msgId);
|
||||
}
|
||||
for (String name : clusterList) {
|
||||
MessageExt messageExt = MQAdminInstance.threadLocalMQAdminExt().queryMessage(name, topic, msgId);
|
||||
if (messageExt != null) {
|
||||
return messageExt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumeMessageDirectlyResult consumeMessageDirectly(String consumerGroup, String clientId, String topic,
|
||||
@@ -511,9 +539,21 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfigSerializeWrapper getAllTopicGroup(String brokerAddr,
|
||||
public SubscriptionGroupWrapper getUserSubscriptionGroup(String brokerAddr,
|
||||
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getAllTopicGroup(brokerAddr, timeoutMillis);
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getUserSubscriptionGroup(brokerAddr, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfigSerializeWrapper getAllTopicConfig(String brokerAddr,
|
||||
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQBrokerException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getAllTopicConfig(brokerAddr, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicConfigSerializeWrapper getUserTopicConfig(String brokerAddr, boolean specialTopic,
|
||||
long timeoutMillis) throws InterruptedException, RemotingException, MQBrokerException, MQClientException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().getUserTopicConfig(brokerAddr, specialTopic, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -548,4 +588,256 @@ public class MQAdminExtImpl implements MQAdminExt {
|
||||
String msgId) throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBrokerToContainer(String brokerContainerAddr, String brokerConfig) throws InterruptedException,
|
||||
MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'addBrokerToContainer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBrokerFromContainer(String brokerContainerAddr, String clusterName, String brokerName,
|
||||
long brokerId) throws InterruptedException, MQBrokerException, RemotingTimeoutException,
|
||||
RemotingSendRequestException, RemotingConnectException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'removeBrokerFromContainer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateGlobalWhiteAddrConfig(String addr, String globalWhiteAddrs, String aclFileFullPath)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'updateGlobalWhiteAddrConfig'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicStatsTable examineTopicStats(String brokerAddr, String topic)
|
||||
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'examineTopicStats'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<TopicStatsTable> examineTopicStatsConcurrent(String topic) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'examineTopicStatsConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumeStats examineConsumeStats(String brokerAddr, String consumerGroup, String topicName,
|
||||
long timeoutMillis) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
|
||||
RemotingConnectException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
return MQAdminInstance.threadLocalMQAdminExt().examineConsumeStats(brokerAddr, consumerGroup, topicName, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<ConsumeStats> examineConsumeStatsConcurrent(String consumerGroup, String topic) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'examineConsumeStatsConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumerConnection examineConsumerConnectionInfo(String consumerGroup, String brokerAddr)
|
||||
throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
|
||||
return MQAdminInstance.threadLocalMQAdminExt().examineConsumerConnectionInfo(consumerGroup, brokerAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProducerTableInfo getAllProducerInfo(String brokerAddr)
|
||||
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getAllProducerInfo'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTopic(String topicName, String clusterName)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteTopic'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<BrokerOperatorResult> deleteTopicInBrokerConcurrent(Set<String> addrs, String topic) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteTopicInBrokerConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTopicInNameServer(Set<String> addrs, String clusterName, String topic)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteTopicInNameServer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<BrokerOperatorResult> resetOffsetNewConcurrent(String group, String topic, long timestamp) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'resetOffsetNewConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicList queryTopicsByConsumer(String group)
|
||||
throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryTopicsByConsumer'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<TopicList> queryTopicsByConsumerConcurrent(String group) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryTopicsByConsumerConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionData querySubscription(String group, String topic)
|
||||
throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'querySubscription'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdminToolResult<List<QueueTimeSpan>> queryConsumeTimeSpanConcurrent(String topic, String group) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryConsumeTimeSpanConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteExpiredCommitLog(String cluster) throws RemotingConnectException, RemotingSendRequestException,
|
||||
RemotingTimeoutException, MQClientException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteExpiredCommitLog'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteExpiredCommitLogByAddr(String addr) throws RemotingConnectException,
|
||||
RemotingSendRequestException, RemotingTimeoutException, MQClientException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'deleteExpiredCommitLogByAddr'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumerRunningInfo getConsumerRunningInfo(String consumerGroup, String clientId, boolean jstack,
|
||||
boolean metrics) throws RemotingException, MQClientException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getConsumerRunningInfo'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MessageTrack> messageTrackDetailConcurrent(MessageExt msg)
|
||||
throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'messageTrackDetailConcurrent'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageRequestMode(String brokerAddr, String topic, String consumerGroup, MessageRequestMode mode,
|
||||
int popWorkGroupSize, long timeoutMillis) throws InterruptedException, RemotingTimeoutException,
|
||||
RemotingSendRequestException, RemotingConnectException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'setMessageRequestMode'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long searchOffset(String brokerAddr, String topicName, int queueId, long timestamp, long timeoutMillis)
|
||||
throws RemotingException, MQBrokerException, InterruptedException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'searchOffset'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetOffsetByQueueId(String brokerAddr, String consumerGroup, String topicName, int queueId,
|
||||
long resetOffset) throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'resetOffsetByQueueId'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createStaticTopic(String addr, String defaultTopic, TopicConfig topicConfig,
|
||||
TopicQueueMappingDetail mappingDetail, boolean force)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'createStaticTopic'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupForbidden updateAndGetGroupReadForbidden(String brokerAddr, String groupName, String topicName,
|
||||
Boolean readable) throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'updateAndGetGroupReadForbidden'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageExt queryMessage(String clusterName, String topic, String msgId)
|
||||
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'queryMessage'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public HARuntimeInfo getBrokerHAStatus(String brokerAddr) throws RemotingConnectException,
|
||||
RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getBrokerHAStatus'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrokerReplicasInfo getInSyncStateData(String controllerAddress, List<String> brokers)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getInSyncStateData'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EpochEntryCache getBrokerEpochCache(String brokerAddr)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getBrokerEpochCache'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetMetaDataResponseHeader getControllerMetaData(String controllerAddr)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getControllerMetaData'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMasterFlushOffset(String brokerAddr, long masterFlushOffset) throws InterruptedException,
|
||||
MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'resetMasterFlushOffset'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Properties> getControllerConfig(List<String> controllerServers)
|
||||
throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
|
||||
RemotingConnectException, MQClientException, UnsupportedEncodingException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getControllerConfig'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateControllerConfig(Properties properties, List<String> controllers)
|
||||
throws InterruptedException, RemotingConnectException, UnsupportedEncodingException,
|
||||
RemotingSendRequestException, RemotingTimeoutException, MQClientException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'updateControllerConfig'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElectMasterResponseHeader electMaster(String controllerAddr, String clusterName, String brokerName,
|
||||
String brokerAddr) throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'electMaster'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanControllerBrokerData(String controllerAddr, String clusterName, String brokerName,
|
||||
String brokerAddr, boolean isCleanLivingBroker)
|
||||
throws RemotingException, InterruptedException, MQBrokerException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'cleanControllerBrokerData'");
|
||||
}
|
||||
}
|
||||
|
@@ -16,29 +16,27 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.client;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
||||
import org.apache.rocketmq.acl.common.SessionCredentials;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.rocketmq.client.impl.MQClientAPIImpl;
|
||||
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
|
||||
import org.apache.rocketmq.remoting.RPCHook;
|
||||
import org.apache.rocketmq.remoting.RemotingClient;
|
||||
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
|
||||
import org.apache.rocketmq.tools.admin.DefaultMQAdminExtImpl;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.joor.Reflect;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class MQAdminInstance {
|
||||
private static final ThreadLocal<DefaultMQAdminExt> MQ_ADMIN_EXT_THREAD_LOCAL = new ThreadLocal<DefaultMQAdminExt>();
|
||||
private static final ThreadLocal<Integer> INIT_COUNTER = new ThreadLocal<Integer>();
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MQAdminInstance.class);
|
||||
private static final ThreadLocal<MQAdminExt> MQ_ADMIN_EXT_THREAD_LOCAL = new ThreadLocal<>();
|
||||
|
||||
public static MQAdminExt threadLocalMQAdminExt() {
|
||||
DefaultMQAdminExt defaultMQAdminExt = MQ_ADMIN_EXT_THREAD_LOCAL.get();
|
||||
if (defaultMQAdminExt == null) {
|
||||
MQAdminExt mqAdminExt = MQ_ADMIN_EXT_THREAD_LOCAL.get();
|
||||
if (mqAdminExt == null) {
|
||||
throw new IllegalStateException("defaultMQAdminExt should be init before you get this");
|
||||
}
|
||||
return defaultMQAdminExt;
|
||||
return mqAdminExt;
|
||||
}
|
||||
|
||||
public static RemotingClient threadLocalRemotingClient() {
|
||||
@@ -51,44 +49,27 @@ public class MQAdminInstance {
|
||||
DefaultMQAdminExtImpl defaultMQAdminExtImpl = Reflect.on(MQAdminInstance.threadLocalMQAdminExt()).get("defaultMQAdminExtImpl");
|
||||
return Reflect.on(defaultMQAdminExtImpl).get("mqClientInstance");
|
||||
}
|
||||
public static void initMQAdminInstance(long timeoutMillis,String accessKey,String secretKey, boolean useTLS) throws MQClientException {
|
||||
Integer nowCount = INIT_COUNTER.get();
|
||||
if (nowCount == null) {
|
||||
RPCHook rpcHook = null;
|
||||
boolean isEnableAcl = !StringUtils.isEmpty(accessKey) && !StringUtils.isEmpty(secretKey);
|
||||
if (isEnableAcl) {
|
||||
rpcHook = new AclClientRPCHook(new SessionCredentials(accessKey, secretKey));
|
||||
|
||||
public static void createMQAdmin(GenericObjectPool<MQAdminExt> mqAdminExtPool) {
|
||||
try {
|
||||
// Get the mqAdmin instance from the object pool
|
||||
MQAdminExt mqAdminExt = mqAdminExtPool.borrowObject();
|
||||
MQ_ADMIN_EXT_THREAD_LOCAL.set(mqAdminExt);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("get mqAdmin from pool error", e);
|
||||
}
|
||||
DefaultMQAdminExt defaultMQAdminExt;
|
||||
if (timeoutMillis > 0) {
|
||||
defaultMQAdminExt = new DefaultMQAdminExt(rpcHook,timeoutMillis);
|
||||
}
|
||||
else {
|
||||
defaultMQAdminExt = new DefaultMQAdminExt(rpcHook);
|
||||
}
|
||||
defaultMQAdminExt.setUseTLS(useTLS);
|
||||
defaultMQAdminExt.setInstanceName(Long.toString(System.currentTimeMillis()));
|
||||
defaultMQAdminExt.start();
|
||||
MQ_ADMIN_EXT_THREAD_LOCAL.set(defaultMQAdminExt);
|
||||
INIT_COUNTER.set(1);
|
||||
}
|
||||
else {
|
||||
INIT_COUNTER.set(nowCount + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void destroyMQAdminInstance() {
|
||||
Integer nowCount = INIT_COUNTER.get() - 1;
|
||||
if (nowCount > 0) {
|
||||
INIT_COUNTER.set(nowCount);
|
||||
return;
|
||||
}
|
||||
public static void returnMQAdmin(GenericObjectPool<MQAdminExt> mqAdminExtPool) {
|
||||
MQAdminExt mqAdminExt = MQ_ADMIN_EXT_THREAD_LOCAL.get();
|
||||
if (mqAdminExt != null) {
|
||||
mqAdminExt.shutdown();
|
||||
try {
|
||||
// After execution, return the mqAdmin instance to the object pool
|
||||
mqAdminExtPool.returnObject(mqAdminExt);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("return mqAdmin to pool error", e);
|
||||
}
|
||||
}
|
||||
MQ_ADMIN_EXT_THREAD_LOCAL.remove();
|
||||
INIT_COUNTER.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.client;
|
||||
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingConnectException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
|
||||
public interface ProxyAdmin {
|
||||
|
||||
ConsumerConnection examineConsumerConnectionInfo(String addr, String consumerGroup) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQBrokerException;
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.client;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.remoting.RemotingClient;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingConnectException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.header.GetConsumerConnectionListRequestHeader;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static org.apache.rocketmq.remoting.protocol.RequestCode.GET_CONSUMER_CONNECTION_LIST;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ProxyAdminImpl implements ProxyAdmin {
|
||||
@Autowired
|
||||
private GenericObjectPool<MQAdminExt> mqAdminExtPool;
|
||||
|
||||
@Override
|
||||
public ConsumerConnection examineConsumerConnectionInfo(String addr, String consumerGroup) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQBrokerException {
|
||||
try {
|
||||
MQAdminInstance.createMQAdmin(mqAdminExtPool);
|
||||
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
|
||||
GetConsumerConnectionListRequestHeader requestHeader = new GetConsumerConnectionListRequestHeader();
|
||||
requestHeader.setConsumerGroup(consumerGroup);
|
||||
RemotingCommand request = RemotingCommand.createRequestCommand(GET_CONSUMER_CONNECTION_LIST, requestHeader);
|
||||
RemotingCommand response = remotingClient.invokeSync(addr, request, 3000);
|
||||
switch (response.getCode()) {
|
||||
case 0:
|
||||
return ConsumerConnection.decode(response.getBody(), ConsumerConnection.class);
|
||||
default:
|
||||
throw new MQBrokerException(response.getCode(), response.getRemark(), addr);
|
||||
}
|
||||
} finally {
|
||||
MQAdminInstance.returnMQAdmin(mqAdminExtPool);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.srvutil.FileWatchService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class AbstractFileStore {
|
||||
public final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public String filePath;
|
||||
|
||||
public AbstractFileStore(RMQConfigure configure, String fileName) {
|
||||
filePath = configure.getRocketMqDashboardDataPath() + File.separator + fileName;
|
||||
if (!new File(filePath).exists()) {
|
||||
// Use the default path
|
||||
InputStream inputStream = getClass().getResourceAsStream("/" + fileName);
|
||||
if (inputStream == null) {
|
||||
log.error(String.format("Can not found the file %s in Spring Boot jar", fileName));
|
||||
System.exit(1);
|
||||
} else {
|
||||
try {
|
||||
load(inputStream);
|
||||
} catch (Exception e) {
|
||||
log.error("fail to load file {}", filePath, e);
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
log.error("inputStream close exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info(String.format("configure file is %s", filePath));
|
||||
load();
|
||||
watch();
|
||||
}
|
||||
}
|
||||
|
||||
abstract void load(InputStream inputStream);
|
||||
|
||||
private void load() {
|
||||
load(null);
|
||||
}
|
||||
|
||||
private boolean watch() {
|
||||
try {
|
||||
FileWatchService fileWatchService = new FileWatchService(new String[] {filePath}, new FileWatchService.Listener() {
|
||||
@Override
|
||||
public void onChanged(String path) {
|
||||
log.info("The file changed, reload the context");
|
||||
load();
|
||||
}
|
||||
});
|
||||
fileWatchService.start();
|
||||
log.info("Succeed to start FileWatcherService");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to start FileWatcherService", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.client.exception.MQBrokerException;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
|
||||
import org.apache.rocketmq.dashboard.service.AclService;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingConnectException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AclServiceImpl extends AbstractCommonService implements AclService {
|
||||
|
||||
@Override
|
||||
public AclConfig getAclConfig(boolean excludeSecretKey) {
|
||||
try {
|
||||
Optional<String> addr = getMasterSet().stream().findFirst();
|
||||
if (addr.isPresent()) {
|
||||
if (!excludeSecretKey) {
|
||||
return mqAdminExt.examineBrokerClusterAclConfig(addr.get());
|
||||
} else {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr.get());
|
||||
if (CollectionUtils.isNotEmpty(aclConfig.getPlainAccessConfigs())) {
|
||||
aclConfig.getPlainAccessConfigs().forEach(pac -> pac.setSecretKey(null));
|
||||
}
|
||||
return aclConfig;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("getAclConfig error.", e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
AclConfig aclConfig = new AclConfig();
|
||||
aclConfig.setGlobalWhiteAddrs(Collections.emptyList());
|
||||
aclConfig.setPlainAccessConfigs(Collections.emptyList());
|
||||
return aclConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAclConfig(PlainAccessConfig config) {
|
||||
try {
|
||||
Set<String> masterSet = getMasterSet();
|
||||
|
||||
if (masterSet.isEmpty()) {
|
||||
throw new IllegalStateException("broker addr list is empty");
|
||||
}
|
||||
// check to see if account is exists
|
||||
for (String addr : masterSet) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
List<PlainAccessConfig> plainAccessConfigs = aclConfig.getPlainAccessConfigs();
|
||||
for (PlainAccessConfig pac : plainAccessConfigs) {
|
||||
if (pac.getAccessKey().equals(config.getAccessKey())) {
|
||||
throw new IllegalArgumentException(String.format("broker: %s, exist accessKey: %s", addr, config.getAccessKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all broker
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, config);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAclConfig(PlainAccessConfig config) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
log.info("Start to delete acl [{}] from broker [{}]", config.getAccessKey(), addr);
|
||||
if (isExistAccessKey(config.getAccessKey(), addr)) {
|
||||
mqAdminExt.deletePlainAccessConfig(addr, config.getAccessKey());
|
||||
}
|
||||
log.info("Delete acl [{}] from broker [{}] complete", config.getAccessKey(), addr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAclConfig(PlainAccessConfig config) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
for (PlainAccessConfig pac : aclConfig.getPlainAccessConfigs()) {
|
||||
if (pac.getAccessKey().equals(config.getAccessKey())) {
|
||||
remoteConfig = pac;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remoteConfig != null) {
|
||||
remoteConfig.setSecretKey(config.getSecretKey());
|
||||
remoteConfig.setAdmin(config.isAdmin());
|
||||
config = remoteConfig;
|
||||
}
|
||||
}
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, config);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOrUpdateAclTopicConfig(AclRequest request) {
|
||||
try {
|
||||
PlainAccessConfig addConfig = request.getConfig();
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
for (PlainAccessConfig config : aclConfig.getPlainAccessConfigs()) {
|
||||
if (config.getAccessKey().equals(addConfig.getAccessKey())) {
|
||||
remoteConfig = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remoteConfig == null) {
|
||||
// Maybe the broker no acl config of the access key, therefore add it;
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, addConfig);
|
||||
} else {
|
||||
if (remoteConfig.getTopicPerms() == null) {
|
||||
remoteConfig.setTopicPerms(new ArrayList<>());
|
||||
}
|
||||
removeExist(remoteConfig.getTopicPerms(), request.getTopicPerm().split("=")[0]);
|
||||
remoteConfig.getTopicPerms().add(request.getTopicPerm());
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, remoteConfig);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOrUpdateAclGroupConfig(AclRequest request) {
|
||||
try {
|
||||
PlainAccessConfig addConfig = request.getConfig();
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
for (PlainAccessConfig config : aclConfig.getPlainAccessConfigs()) {
|
||||
if (config.getAccessKey().equals(addConfig.getAccessKey())) {
|
||||
remoteConfig = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remoteConfig == null) {
|
||||
// May be the broker no acl config of the access key, therefore add it;
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, addConfig);
|
||||
} else {
|
||||
if (remoteConfig.getGroupPerms() == null) {
|
||||
remoteConfig.setGroupPerms(new ArrayList<>());
|
||||
}
|
||||
removeExist(remoteConfig.getGroupPerms(), request.getGroupPerm().split("=")[0]);
|
||||
remoteConfig.getGroupPerms().add(request.getGroupPerm());
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, remoteConfig);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePermConfig(AclRequest request) {
|
||||
try {
|
||||
PlainAccessConfig deleteConfig = request.getConfig();
|
||||
|
||||
String topic = StringUtils.isNotEmpty(request.getTopicPerm()) ? request.getTopicPerm().split("=")[0] : null;
|
||||
String group = StringUtils.isNotEmpty(request.getGroupPerm()) ? request.getGroupPerm().split("=")[0] : null;
|
||||
if (deleteConfig.getTopicPerms() != null && topic != null) {
|
||||
removeExist(deleteConfig.getTopicPerms(), topic);
|
||||
}
|
||||
if (deleteConfig.getGroupPerms() != null && group != null) {
|
||||
removeExist(deleteConfig.getGroupPerms(), group);
|
||||
}
|
||||
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
PlainAccessConfig remoteConfig = null;
|
||||
if (aclConfig.getPlainAccessConfigs() != null) {
|
||||
for (PlainAccessConfig config : aclConfig.getPlainAccessConfigs()) {
|
||||
if (config.getAccessKey().equals(deleteConfig.getAccessKey())) {
|
||||
remoteConfig = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remoteConfig == null) {
|
||||
// Maybe the broker no acl config of the access key, therefore add it;
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, deleteConfig);
|
||||
} else {
|
||||
if (remoteConfig.getTopicPerms() != null && topic != null) {
|
||||
removeExist(remoteConfig.getTopicPerms(), topic);
|
||||
}
|
||||
if (remoteConfig.getGroupPerms() != null && group != null) {
|
||||
removeExist(remoteConfig.getGroupPerms(), group);
|
||||
}
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, remoteConfig);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncData(PlainAccessConfig config) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, config);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWhiteList(List<String> whiteList) {
|
||||
if (whiteList == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
if (aclConfig.getGlobalWhiteAddrs() != null) {
|
||||
aclConfig.setGlobalWhiteAddrs(Stream.of(whiteList, aclConfig.getGlobalWhiteAddrs()).flatMap(Collection::stream).distinct().collect(Collectors.toList()));
|
||||
} else {
|
||||
aclConfig.setGlobalWhiteAddrs(whiteList);
|
||||
}
|
||||
mqAdminExt.updateGlobalWhiteAddrConfig(addr, StringUtils.join(aclConfig.getGlobalWhiteAddrs(), ","));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteWhiteAddr(String deleteAddr) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
if (aclConfig.getGlobalWhiteAddrs() == null || aclConfig.getGlobalWhiteAddrs().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
aclConfig.getGlobalWhiteAddrs().remove(deleteAddr);
|
||||
mqAdminExt.updateGlobalWhiteAddrConfig(addr, StringUtils.join(aclConfig.getGlobalWhiteAddrs(), ","));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void synchronizeWhiteList(List<String> whiteList) {
|
||||
if (whiteList == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
mqAdminExt.updateGlobalWhiteAddrConfig(addr, StringUtils.join(whiteList, ","));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeExist(List<String> list, String name) {
|
||||
Iterator<String> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String v = iterator.next();
|
||||
String cmp = v.split("=")[0];
|
||||
if (cmp.equals(name)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExistAccessKey(String accessKey,
|
||||
String addr) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
|
||||
AclConfig aclConfig = mqAdminExt.examineBrokerClusterAclConfig(addr);
|
||||
List<PlainAccessConfig> plainAccessConfigs = aclConfig.getPlainAccessConfigs();
|
||||
if (plainAccessConfigs == null || plainAccessConfigs.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (PlainAccessConfig config : plainAccessConfigs) {
|
||||
if (accessKey.equals(config.getAccessKey())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<BrokerData> getBrokerDataSet() throws InterruptedException, RemotingConnectException, RemotingTimeoutException, RemotingSendRequestException, MQBrokerException {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
Map<String, BrokerData> brokerDataMap = clusterInfo.getBrokerAddrTable();
|
||||
return new HashSet<>(brokerDataMap.values());
|
||||
}
|
||||
|
||||
private Set<String> getMasterSet() throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
return getBrokerDataSet().stream().map(data -> data.getBrokerAddrs().get(MixAll.MASTER_ID)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<String> getBrokerAddrs() throws InterruptedException, MQBrokerException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
|
||||
Set<String> brokerAddrs = new HashSet<>();
|
||||
getBrokerDataSet().forEach(data -> brokerAddrs.addAll(data.getBrokerAddrs().values()));
|
||||
return brokerAddrs;
|
||||
}
|
||||
}
|
@@ -17,9 +17,10 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.attribute.TopicMessageType;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.dashboard.service.ClusterService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
@@ -30,8 +31,10 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class ClusterServiceImpl implements ClusterService {
|
||||
@@ -56,10 +59,14 @@ public class ClusterServiceImpl implements ClusterService {
|
||||
}
|
||||
resultMap.put("clusterInfo", clusterInfo);
|
||||
resultMap.put("brokerServer", brokerServer);
|
||||
// add messageType
|
||||
resultMap.put("messageTypes", Arrays.stream(TopicMessageType.values()).sorted()
|
||||
.collect(Collectors.toMap(TopicMessageType::getValue, messageType ->String.format("MESSAGE_TYPE_%s",messageType.getValue()))));
|
||||
return resultMap;
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +77,8 @@ public class ClusterServiceImpl implements ClusterService {
|
||||
return mqAdminExt.getBrokerConfig(brokerAddr);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,27 +23,44 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.MQVersion;
|
||||
import org.apache.rocketmq.common.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.common.admin.RollbackStats;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.dashboard.service.client.ProxyAdmin;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.Connection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerRunningInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.common.utils.ThreadUtils;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.ConsumerGroupRollBackStat;
|
||||
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
|
||||
import org.apache.rocketmq.dashboard.model.QueueStatInfo;
|
||||
@@ -55,39 +72,113 @@ import org.apache.rocketmq.dashboard.service.AbstractCommonService;
|
||||
import org.apache.rocketmq.dashboard.service.ConsumerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
@Service
|
||||
public class ConsumerServiceImpl extends AbstractCommonService implements ConsumerService {
|
||||
public class ConsumerServiceImpl extends AbstractCommonService implements ConsumerService, InitializingBean, DisposableBean {
|
||||
private Logger logger = LoggerFactory.getLogger(ConsumerServiceImpl.class);
|
||||
|
||||
@Resource
|
||||
protected ProxyAdmin proxyAdmin;
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
private static final Set<String> SYSTEM_GROUP_SET = new HashSet<>();
|
||||
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public List<GroupConsumeInfo> queryGroupList() {
|
||||
Set<String> consumerGroupSet = Sets.newHashSet();
|
||||
public void afterPropertiesSet() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
int corePoolSize = Math.max(10, runtime.availableProcessors() * 2);
|
||||
int maximumPoolSize = Math.max(20, runtime.availableProcessors() * 2);
|
||||
ThreadFactory threadFactory = new ThreadFactory() {
|
||||
private final AtomicLong threadIndex = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, "QueryGroup_" + this.threadIndex.incrementAndGet());
|
||||
}
|
||||
};
|
||||
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
|
||||
this.executorService = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 60L, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(5000), threadFactory, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
ThreadUtils.shutdownGracefully(executorService, 10L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
static {
|
||||
SYSTEM_GROUP_SET.add(MixAll.TOOLS_CONSUMER_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.FILTERSRV_CONSUMER_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.SELF_TEST_CONSUMER_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.ONS_HTTP_PROXY_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.CID_ONSAPI_PULL_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.CID_ONSAPI_PERMISSION_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.CID_ONSAPI_OWNER_GROUP);
|
||||
SYSTEM_GROUP_SET.add(MixAll.CID_SYS_RMQ_TRANS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupConsumeInfo> queryGroupList(boolean skipSysGroup, String address) {
|
||||
HashMap<String, List<String>> consumerGroupMap = Maps.newHashMap();
|
||||
try {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
for (BrokerData brokerData : clusterInfo.getBrokerAddrTable().values()) {
|
||||
SubscriptionGroupWrapper subscriptionGroupWrapper = mqAdminExt.getAllSubscriptionGroup(brokerData.selectBrokerAddr(), 3000L);
|
||||
consumerGroupSet.addAll(subscriptionGroupWrapper.getSubscriptionGroupTable().keySet());
|
||||
for (String groupName : subscriptionGroupWrapper.getSubscriptionGroupTable().keySet()) {
|
||||
if (!consumerGroupMap.containsKey(groupName)) {
|
||||
consumerGroupMap.putIfAbsent(groupName, new ArrayList<>());
|
||||
}
|
||||
List<String> addresses = consumerGroupMap.get(groupName);
|
||||
addresses.add(brokerData.selectBrokerAddr());
|
||||
consumerGroupMap.put(groupName, addresses);
|
||||
}
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
} catch (Exception err) {
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
List<GroupConsumeInfo> groupConsumeInfoList = Lists.newArrayList();
|
||||
for (String consumerGroup : consumerGroupSet) {
|
||||
groupConsumeInfoList.add(queryGroup(consumerGroup));
|
||||
List<GroupConsumeInfo> groupConsumeInfoList = Collections.synchronizedList(Lists.newArrayList());
|
||||
CountDownLatch countDownLatch = new CountDownLatch(consumerGroupMap.size());
|
||||
for (Map.Entry<String, List<String>> entry : consumerGroupMap.entrySet()) {
|
||||
String consumerGroup = entry.getKey();
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
GroupConsumeInfo consumeInfo = queryGroup(consumerGroup, address);
|
||||
consumeInfo.setAddress(entry.getValue());
|
||||
groupConsumeInfoList.add(consumeInfo);
|
||||
} catch (Exception e) {
|
||||
logger.error("queryGroup exception, consumerGroup: {}", consumerGroup, e);
|
||||
} finally {
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
try {
|
||||
countDownLatch.await(30, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("query consumerGroup countDownLatch await Exception", e);
|
||||
}
|
||||
|
||||
if (!skipSysGroup) {
|
||||
groupConsumeInfoList.stream().map(group -> {
|
||||
if (SYSTEM_GROUP_SET.contains(group.getGroup())) {
|
||||
group.setGroup(String.format("%s%s", "%SYS%", group.getGroup()));
|
||||
}
|
||||
return group;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
Collections.sort(groupConsumeInfoList);
|
||||
return groupConsumeInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public GroupConsumeInfo queryGroup(String consumerGroup) {
|
||||
public GroupConsumeInfo queryGroup(String consumerGroup, String address) {
|
||||
GroupConsumeInfo groupConsumeInfo = new GroupConsumeInfo();
|
||||
try {
|
||||
ConsumeStats consumeStats = null;
|
||||
@@ -99,14 +190,28 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
ConsumerConnection consumerConnection = null;
|
||||
boolean isFifoType = examineSubscriptionGroupConfig(consumerGroup)
|
||||
.stream().map(ConsumerConfigInfo::getSubscriptionGroupConfig)
|
||||
.allMatch(SubscriptionGroupConfig::isConsumeMessageOrderly);
|
||||
|
||||
try {
|
||||
if (StringUtils.isNotEmpty(address)) {
|
||||
consumerConnection = proxyAdmin.examineConsumerConnectionInfo(address, consumerGroup);
|
||||
} else {
|
||||
consumerConnection = mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
logger.warn("examineConsumeStats exception to consumerGroup {}, response [{}]", consumerGroup, e.getMessage());
|
||||
}
|
||||
|
||||
groupConsumeInfo.setGroup(consumerGroup);
|
||||
if (SYSTEM_GROUP_SET.contains(consumerGroup)) {
|
||||
groupConsumeInfo.setSubGroupType("SYSTEM");
|
||||
} else if (isFifoType) {
|
||||
groupConsumeInfo.setSubGroupType("FIFO");
|
||||
} else {
|
||||
groupConsumeInfo.setSubGroupType("NORMAL");
|
||||
}
|
||||
|
||||
if (consumeStats != null) {
|
||||
groupConsumeInfo.setConsumeTps((int)consumeStats.getConsumeTps());
|
||||
@@ -128,20 +233,34 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName) {
|
||||
return queryConsumeStatsList(null, groupName);
|
||||
public List<TopicConsumerInfo> queryConsumeStatsListByGroupName(String groupName, String address) {
|
||||
ConsumeStats consumeStats;
|
||||
String topic = null;
|
||||
try {
|
||||
String[] addresses = address.split(",");
|
||||
String addr = addresses[0];
|
||||
consumeStats = mqAdminExt.examineConsumeStats(addr, groupName, null, 3000);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return toTopicConsumerInfoList(topic, consumeStats, groupName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public List<TopicConsumerInfo> queryConsumeStatsList(final String topic, String groupName) {
|
||||
ConsumeStats consumeStats = null;
|
||||
try {
|
||||
consumeStats = mqAdminExt.examineConsumeStats(groupName, topic);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return toTopicConsumerInfoList(topic, consumeStats, groupName);
|
||||
}
|
||||
|
||||
private List<TopicConsumerInfo> toTopicConsumerInfoList(String topic, ConsumeStats consumeStats, String groupName) {
|
||||
List<MessageQueue> mqList = Lists.newArrayList(Iterables.filter(consumeStats.getOffsetTable().keySet(), new Predicate<MessageQueue>() {
|
||||
@Override
|
||||
public boolean apply(MessageQueue o) {
|
||||
@@ -184,7 +303,6 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public Map<String /*groupName*/, TopicConsumerInfo> queryConsumeStatsListByTopicName(String topic) {
|
||||
Map<String, TopicConsumerInfo> group2ConsumerInfoMap = Maps.newHashMap();
|
||||
try {
|
||||
@@ -201,12 +319,12 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
return group2ConsumerInfoMap;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public Map<String, ConsumerGroupRollBackStat> resetOffset(ResetOffsetRequest resetOffsetRequest) {
|
||||
Map<String, ConsumerGroupRollBackStat> groupRollbackStats = Maps.newHashMap();
|
||||
for (String consumerGroup : resetOffsetRequest.getConsumerGroupList()) {
|
||||
@@ -251,7 +369,6 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public List<ConsumerConfigInfo> examineSubscriptionGroupConfig(String group) {
|
||||
List<ConsumerConfigInfo> consumerConfigInfoList = Lists.newArrayList();
|
||||
try {
|
||||
@@ -266,27 +383,50 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return consumerConfigInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public boolean deleteSubGroup(DeleteSubGroupRequest deleteSubGroupRequest) {
|
||||
Set<String> brokerSet = this.fetchBrokerNameSetBySubscriptionGroup(deleteSubGroupRequest.getGroupName());
|
||||
List<String> brokerList = deleteSubGroupRequest.getBrokerNameList();
|
||||
boolean deleteInNsFlag = false;
|
||||
// If the list of brokers passed in by the request contains the list of brokers that the consumer is in, delete RETRY and DLQ topic in namesrv
|
||||
if (brokerList.containsAll(brokerSet)) {
|
||||
deleteInNsFlag = true;
|
||||
}
|
||||
try {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
for (String brokerName : deleteSubGroupRequest.getBrokerNameList()) {
|
||||
logger.info("addr={} groupName={}", clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName());
|
||||
mqAdminExt.deleteSubscriptionGroup(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName());
|
||||
mqAdminExt.deleteSubscriptionGroup(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), deleteSubGroupRequest.getGroupName(), true);
|
||||
// Delete %RETRY%+Group and %DLQ%+Group in broker and namesrv
|
||||
deleteResources(MixAll.RETRY_GROUP_TOPIC_PREFIX + deleteSubGroupRequest.getGroupName(), brokerName, clusterInfo, deleteInNsFlag);
|
||||
deleteResources(MixAll.DLQ_GROUP_TOPIC_PREFIX + deleteSubGroupRequest.getGroupName(), brokerName, clusterInfo, deleteInNsFlag);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void deleteResources(String topic, String brokerName, ClusterInfo clusterInfo, boolean deleteInNsFlag) throws Exception {
|
||||
mqAdminExt.deleteTopicInBroker(Sets.newHashSet(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr()), topic);
|
||||
Set<String> nameServerSet = null;
|
||||
if (StringUtils.isNotBlank(configure.getNamesrvAddr())) {
|
||||
String[] ns = configure.getNamesrvAddr().split(";");
|
||||
nameServerSet = new HashSet<>(Arrays.asList(ns));
|
||||
}
|
||||
if (deleteInNsFlag) {
|
||||
mqAdminExt.deleteTopicInNameServer(nameServerSet, topic);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAndUpdateSubscriptionGroupConfig(ConsumerConfigInfo consumerConfigInfo) {
|
||||
try {
|
||||
@@ -297,13 +437,13 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@MultiMQAdminCmdMethod
|
||||
public Set<String> fetchBrokerNameSetBySubscriptionGroup(String group) {
|
||||
Set<String> brokerNameSet = Sets.newHashSet();
|
||||
try {
|
||||
@@ -313,19 +453,22 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return brokerNameSet;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsumerConnection getConsumerConnection(String consumerGroup) {
|
||||
public ConsumerConnection getConsumerConnection(String consumerGroup, String address) {
|
||||
try {
|
||||
return mqAdminExt.examineConsumerConnectionInfo(consumerGroup);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
String[] addresses = address.split(",");
|
||||
String addr = addresses[0];
|
||||
return mqAdminExt.examineConsumerConnectionInfo(consumerGroup, addr);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +478,8 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
return mqAdminExt.getConsumerRunningInfo(consumerGroup, clientId, jstack);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -107,7 +107,8 @@ public class DashboardCollectServiceImpl implements DashboardCollectService {
|
||||
strings = Files.readLines(file, Charsets.UTF_8);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (String string : strings) {
|
||||
|
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.remoting.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageResendResult;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
import org.apache.rocketmq.dashboard.service.DlqMessageService;
|
||||
import org.apache.rocketmq.dashboard.service.MessageService;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DlqMessageServiceImpl implements DlqMessageService {
|
||||
|
||||
@Resource
|
||||
private MQAdminExt mqAdminExt;
|
||||
|
||||
@Resource
|
||||
private MessageService messageService;
|
||||
|
||||
@Override
|
||||
public MessagePage queryDlqMessageByPage(MessageQuery query) {
|
||||
List<MessageView> messageViews = new ArrayList<>();
|
||||
PageRequest page = PageRequest.of(query.getPageNum(), query.getPageSize());
|
||||
String topic = query.getTopic();
|
||||
try {
|
||||
mqAdminExt.examineTopicRouteInfo(topic);
|
||||
} catch (MQClientException e) {
|
||||
// If the %DLQ%Group does not exist, the message returns null
|
||||
if (topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX)
|
||||
&& e.getResponseCode() == ResponseCode.TOPIC_NOT_EXIST) {
|
||||
return new MessagePage(new PageImpl<>(messageViews, page, 0), query.getTaskId());
|
||||
} else {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return messageService.queryMessageByPage(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DlqMessageResendResult> batchResendDlqMessage(List<DlqMessageRequest> dlqMessages) {
|
||||
List<DlqMessageResendResult> batchResendResults = new LinkedList<>();
|
||||
for (DlqMessageRequest dlqMessage : dlqMessages) {
|
||||
ConsumeMessageDirectlyResult result = messageService.consumeMessageDirectly(dlqMessage.getTopicName(),
|
||||
dlqMessage.getMsgId(), dlqMessage.getConsumerGroup(),
|
||||
dlqMessage.getClientId());
|
||||
DlqMessageResendResult resendResult = new DlqMessageResendResult(result, dlqMessage.getMsgId());
|
||||
batchResendResults.add(resendResult);
|
||||
}
|
||||
return batchResendResults;
|
||||
}
|
||||
}
|
@@ -31,14 +31,15 @@ import org.apache.rocketmq.acl.common.SessionCredentials;
|
||||
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
|
||||
import org.apache.rocketmq.client.consumer.PullResult;
|
||||
import org.apache.rocketmq.client.consumer.PullStatus;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.message.MessageClientIDSetter;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.message.MessageQueue;
|
||||
import org.apache.rocketmq.common.protocol.body.Connection;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.Connection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
|
||||
@@ -111,7 +112,11 @@ public class MessageServiceImpl implements MessageService {
|
||||
}
|
||||
});
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
if (err instanceof MQClientException) {
|
||||
throw new ServiceException(-1, ((MQClientException) err).getErrorMessage());
|
||||
}
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +186,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
});
|
||||
return messageViewList;
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
consumer.shutdown();
|
||||
}
|
||||
@@ -205,7 +211,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
try {
|
||||
return mqAdminExt.consumeMessageDirectly(consumerGroup, clientId, topic, msgId);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +226,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
return mqAdminExt.consumeMessageDirectly(consumerGroup, connection.getClientId(), topic, msgId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
throw new IllegalStateException("NO CONSUMER");
|
||||
|
||||
@@ -268,7 +276,7 @@ public class MessageServiceImpl implements MessageService {
|
||||
int idx = 0;
|
||||
for (MessageQueue messageQueue : messageQueues) {
|
||||
Long minOffset = consumer.searchOffset(messageQueue, query.getBegin());
|
||||
Long maxOffset = consumer.searchOffset(messageQueue, query.getEnd()) + 1;
|
||||
Long maxOffset = consumer.searchOffset(messageQueue, query.getEnd());
|
||||
queueOffsetInfos.add(new QueueOffsetInfo(idx++, minOffset, maxOffset, minOffset, minOffset, messageQueue));
|
||||
}
|
||||
|
||||
@@ -325,7 +333,7 @@ public class MessageServiceImpl implements MessageService {
|
||||
List<MessageExt> msgFoundList = pullResult.getMsgFoundList();
|
||||
for (int i = msgFoundList.size() - 1; i >= 0; i--) {
|
||||
MessageExt messageExt = msgFoundList.get(i);
|
||||
if (messageExt.getStoreTimestamp() < query.getBegin()) {
|
||||
if (messageExt.getStoreTimestamp() > query.getEnd()) {
|
||||
end--;
|
||||
} else {
|
||||
hasIllegalOffset = false;
|
||||
@@ -384,7 +392,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
PageImpl<MessageView> page = new PageImpl<>(messageViews, query.page(), total);
|
||||
return new MessagePageTask(page, queueOffsetInfos);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
consumer.shutdown();
|
||||
}
|
||||
@@ -451,7 +460,8 @@ public class MessageServiceImpl implements MessageService {
|
||||
}
|
||||
return new PageImpl<>(messageViews, query.page(), total);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
consumer.shutdown();
|
||||
}
|
||||
|
@@ -20,8 +20,6 @@ package org.apache.rocketmq.dashboard.service.impl;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -33,7 +31,9 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.client.trace.TraceType;
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.MessageTraceView;
|
||||
import org.apache.rocketmq.dashboard.model.trace.ProducerNode;
|
||||
import org.apache.rocketmq.dashboard.model.trace.MessageTraceGraph;
|
||||
@@ -65,7 +65,7 @@ public class MessageTraceServiceImpl implements MessageTraceService {
|
||||
|
||||
@Override
|
||||
public List<MessageTraceView> queryMessageTraceKey(String key) {
|
||||
String queryTopic = configure.getMsgTrackTopicNameOrDefault();
|
||||
String queryTopic = TopicValidator.RMQ_SYS_TRACE_TOPIC;
|
||||
logger.info("query data topic name is:{}", queryTopic);
|
||||
return queryMessageTraceByTopicAndKey(queryTopic, key);
|
||||
}
|
||||
@@ -81,13 +81,16 @@ public class MessageTraceServiceImpl implements MessageTraceService {
|
||||
}
|
||||
return messageTraceViews;
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
throw new ServiceException(-1, String.format("Failed to query message trace by msgId %s", key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageTraceGraph queryMessageTraceGraph(String key) {
|
||||
List<MessageTraceView> messageTraceViews = queryMessageTraceKey(key);
|
||||
public MessageTraceGraph queryMessageTraceGraph(String key, String topic) {
|
||||
if (StringUtils.isEmpty(topic)) {
|
||||
topic = TopicValidator.RMQ_SYS_TRACE_TOPIC;
|
||||
}
|
||||
List<MessageTraceView> messageTraceViews = queryMessageTraceByTopicAndKey(topic, key);
|
||||
return buildMessageTraceGraph(messageTraceViews);
|
||||
}
|
||||
|
||||
|
@@ -82,7 +82,8 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
MixAll.string2File(dataStr, path);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,16 +16,18 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
|
||||
import org.apache.rocketmq.dashboard.service.OpsService;
|
||||
import org.apache.rocketmq.dashboard.service.checker.CheckerType;
|
||||
import org.apache.rocketmq.dashboard.service.checker.RocketMqChecker;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -34,13 +36,17 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@Autowired
|
||||
private GenericObjectPool<MQAdminExt> mqAdminExtPool;
|
||||
|
||||
@Resource
|
||||
private List<RocketMqChecker> rocketMqCheckerList;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> homePageInfo() {
|
||||
Map<String, Object> homePageInfoMap = Maps.newHashMap();
|
||||
homePageInfoMap.put("namesvrAddrList", Splitter.on(";").splitToList(configure.getNamesrvAddr()));
|
||||
homePageInfoMap.put("currentNamesrv", configure.getNamesrvAddr());
|
||||
homePageInfoMap.put("namesvrAddrList", configure.getNamesrvAddrs());
|
||||
homePageInfoMap.put("useVIPChannel", Boolean.valueOf(configure.getIsVIPChannel()));
|
||||
homePageInfoMap.put("useTLS", configure.isUseTLS());
|
||||
return homePageInfoMap;
|
||||
@@ -49,6 +55,8 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
@Override
|
||||
public void updateNameSvrAddrList(String nameSvrAddrList) {
|
||||
configure.setNamesrvAddr(nameSvrAddrList);
|
||||
// when update namesrvAddr, clean the mqAdminExt objects pool.
|
||||
mqAdminExtPool.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,14 +73,26 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
return checkResultMap;
|
||||
}
|
||||
|
||||
@Override public boolean updateIsVIPChannel(String useVIPChannel) {
|
||||
@Override
|
||||
public boolean updateIsVIPChannel(String useVIPChannel) {
|
||||
configure.setIsVIPChannel(useVIPChannel);
|
||||
mqAdminExtPool.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateUseTLS(boolean useTLS) {
|
||||
configure.setUseTLS(useTLS);
|
||||
mqAdminExtPool.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNameSvrAddr(String namesrvAddr) {
|
||||
List<String> namesrvAddrs = configure.getNamesrvAddrs();
|
||||
if (namesrvAddrs != null && !namesrvAddrs.contains(namesrvAddr)) {
|
||||
namesrvAddrs.add(namesrvAddr);
|
||||
}
|
||||
configure.setNamesrvAddrs(namesrvAddrs);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
import org.apache.rocketmq.dashboard.service.PermissionService;
|
||||
import org.apache.rocketmq.dashboard.util.MatcherUtil;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.ADMIN;
|
||||
import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.ORDINARY;
|
||||
|
||||
@Service
|
||||
public class PermissionServiceImpl implements PermissionService, InitializingBean {
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
private PermissionFileStore permissionFileStore;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (configure.isLoginRequired()) {
|
||||
permissionFileStore = new PermissionFileStore(configure);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkUrlAvailable(UserInfo userInfo, String url) {
|
||||
int type = userInfo.getUser().getType();
|
||||
// if it is admin, it could access all resources
|
||||
if (type == ADMIN.getRoleType()) {
|
||||
return true;
|
||||
}
|
||||
String loginUserRole = ORDINARY.getRoleName();
|
||||
Map<String, List<String>> rolePerms = PermissionFileStore.rolePerms;
|
||||
List<String> perms = rolePerms.get(loginUserRole);
|
||||
for (String perm : perms) {
|
||||
if (MatcherUtil.match(perm, url)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class PermissionFileStore extends AbstractFileStore {
|
||||
private static final String FILE_NAME = "role-permission.yml";
|
||||
|
||||
private static Map<String/**role**/, List<String>/**accessUrls**/> rolePerms = new ConcurrentHashMap<>();
|
||||
|
||||
public PermissionFileStore(RMQConfigure configure) {
|
||||
super(configure, FILE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(InputStream inputStream) {
|
||||
Yaml yaml = new Yaml();
|
||||
JSONObject rolePermsData = null;
|
||||
try {
|
||||
if (inputStream == null) {
|
||||
rolePermsData = yaml.loadAs(new FileReader(filePath), JSONObject.class);
|
||||
} else {
|
||||
rolePermsData = yaml.loadAs(inputStream, JSONObject.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("load user-permission.yml failed", e);
|
||||
throw new ServiceException(0, String.format("Failed to load rolePermission property file: %s", filePath));
|
||||
}
|
||||
rolePerms.clear();
|
||||
rolePerms.putAll(rolePermsData.getObject("rolePerms", Map.class));
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,7 +19,7 @@ package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.dashboard.service.ProducerService;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -35,7 +35,8 @@ public class ProducerServiceImpl implements ProducerService {
|
||||
return mqAdminExt.examineProducerConnectionInfo(producerGroup, topic);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.service.ProxyService;
|
||||
import org.apache.rocketmq.dashboard.service.client.ProxyAdmin;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ProxyServiceImpl implements ProxyService {
|
||||
@Resource
|
||||
protected ProxyAdmin proxyAdmin;
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@Override
|
||||
public void addProxyAddrList(String proxyAddr) {
|
||||
List<String> proxyAddrs = configure.getProxyAddrs();
|
||||
if (proxyAddrs != null && !proxyAddrs.contains(proxyAddr)) {
|
||||
proxyAddrs.add(proxyAddr);
|
||||
}
|
||||
configure.setProxyAddrs(proxyAddrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProxyAddrList(String proxyAddr) {
|
||||
configure.setProxyAddr(proxyAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getProxyHomePage() {
|
||||
Map<String, Object> homePageInfoMap = Maps.newHashMap();
|
||||
homePageInfoMap.put("currentProxyAddr", configure.getProxyAddr());
|
||||
homePageInfoMap.put("proxyAddrList", configure.getProxyAddrs());
|
||||
return homePageInfoMap;
|
||||
}
|
||||
}
|
@@ -18,6 +18,7 @@
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -25,34 +26,49 @@ import org.apache.rocketmq.acl.common.AclClientRPCHook;
|
||||
import org.apache.rocketmq.acl.common.SessionCredentials;
|
||||
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
||||
import org.apache.rocketmq.client.producer.SendResult;
|
||||
import org.apache.rocketmq.client.producer.TransactionListener;
|
||||
import org.apache.rocketmq.client.producer.TransactionMQProducer;
|
||||
import org.apache.rocketmq.client.producer.LocalTransactionState;
|
||||
import org.apache.rocketmq.client.trace.TraceContext;
|
||||
import org.apache.rocketmq.client.trace.TraceDispatcher;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.TopicConfig;
|
||||
import org.apache.rocketmq.common.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.common.attribute.TopicMessageType;
|
||||
import org.apache.rocketmq.common.message.Message;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicTypeMeta;
|
||||
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
|
||||
import org.apache.rocketmq.dashboard.service.TopicService;
|
||||
import org.apache.rocketmq.remoting.RPCHook;
|
||||
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.tools.command.CommandUtil;
|
||||
import org.joor.Reflect;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE;
|
||||
|
||||
@Service
|
||||
public class TopicServiceImpl extends AbstractCommonService implements TopicService {
|
||||
@@ -61,28 +77,64 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
private RMQConfigure configure;
|
||||
|
||||
@Override
|
||||
public TopicList fetchAllTopicList(boolean skipSysProcess) {
|
||||
public TopicList fetchAllTopicList(boolean skipSysProcess, boolean skipRetryAndDlq) {
|
||||
try {
|
||||
TopicList allTopics = mqAdminExt.fetchAllTopicList();
|
||||
if (skipSysProcess) {
|
||||
return allTopics;
|
||||
}
|
||||
|
||||
TopicList sysTopics = getSystemTopicList();
|
||||
Set<String> topics = new HashSet<>();
|
||||
|
||||
for (String topic : allTopics.getTopicList()) {
|
||||
if (sysTopics.getTopicList().contains(topic)) {
|
||||
topics.add(String.format("%s%s", "%SYS%", topic));
|
||||
} else {
|
||||
topics.add(topic);
|
||||
Set<String> topics =
|
||||
allTopics.getTopicList().stream().map(topic -> {
|
||||
if (!skipSysProcess && sysTopics.getTopicList().contains(topic)) {
|
||||
topic = String.format("%s%s", "%SYS%", topic);
|
||||
}
|
||||
return topic;
|
||||
}).filter(topic -> {
|
||||
if (skipRetryAndDlq) {
|
||||
return !(topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)
|
||||
|| topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX));
|
||||
}
|
||||
return true;
|
||||
}).collect(Collectors.toSet());
|
||||
allTopics.getTopicList().clear();
|
||||
allTopics.getTopicList().addAll(topics);
|
||||
return allTopics;
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopicTypeList examineAllTopicType() {
|
||||
ArrayList<TopicTypeMeta> topicTypes = new ArrayList<>();
|
||||
ArrayList<String> names = new ArrayList<>();
|
||||
ArrayList<String> messageTypes = new ArrayList<>();
|
||||
TopicList topicList = fetchAllTopicList(false, false);
|
||||
checkTopicType(topicList, topicTypes);
|
||||
topicTypes.sort((t1, t2) -> t1.getTopicName().compareTo(t2.getTopicName()));
|
||||
for (TopicTypeMeta topicTypeMeta : topicTypes) {
|
||||
names.add(topicTypeMeta.getTopicName());
|
||||
messageTypes.add(topicTypeMeta.getMessageType());
|
||||
}
|
||||
return new TopicTypeList(names, messageTypes);
|
||||
}
|
||||
|
||||
private void checkTopicType(TopicList topicList, ArrayList<TopicTypeMeta> topicTypes) {
|
||||
for (String topicName : topicList.getTopicList()) {
|
||||
TopicTypeMeta topicType = new TopicTypeMeta();
|
||||
topicType.setTopicName(topicName);
|
||||
if (topicName.startsWith("%R")) {
|
||||
topicType.setMessageType("RETRY");
|
||||
} else if (topicName.startsWith("%D")) {
|
||||
topicType.setMessageType("DELAY");
|
||||
} else if (topicName.startsWith("%S")) {
|
||||
topicType.setMessageType("SYSTEM");
|
||||
} else {
|
||||
List<TopicConfigInfo> topicConfigInfos = examineTopicConfig(topicName);
|
||||
if (!CollectionUtils.isEmpty(topicConfigInfos)) {
|
||||
topicType.setMessageType(topicConfigInfos.get(0).getMessageType());
|
||||
}
|
||||
}
|
||||
topicTypes.add(topicType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +143,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
return mqAdminExt.examineTopicStats(topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +153,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
return mqAdminExt.examineTopicRouteInfo(topic);
|
||||
} catch (Exception ex) {
|
||||
throw Throwables.propagate(ex);
|
||||
Throwables.throwIfUnchecked(ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +163,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
return mqAdminExt.queryTopicConsumeByWho(topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +172,11 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
public void createOrUpdate(TopicConfigInfo topicCreateOrUpdateRequest) {
|
||||
TopicConfig topicConfig = new TopicConfig();
|
||||
BeanUtils.copyProperties(topicCreateOrUpdateRequest, topicConfig);
|
||||
String messageType = topicCreateOrUpdateRequest.getMessageType();
|
||||
if (StringUtils.isBlank(messageType)) {
|
||||
messageType = TopicMessageType.NORMAL.name();
|
||||
}
|
||||
topicConfig.setAttributes(ImmutableMap.of("+".concat(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName()), messageType));
|
||||
try {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
for (String brokerName : changeToBrokerNameSet(clusterInfo.getClusterAddrTable(),
|
||||
@@ -124,7 +184,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
mqAdminExt.createAndUpdateTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topicConfig);
|
||||
}
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,10 +194,11 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
ClusterInfo clusterInfo = null;
|
||||
try {
|
||||
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
return mqAdminExt.examineTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topic);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,6 +210,11 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
TopicConfig topicConfig = examineTopicConfig(topic, brokerData.getBrokerName());
|
||||
BeanUtils.copyProperties(topicConfig, topicConfigInfo);
|
||||
topicConfigInfo.setBrokerNameList(Lists.newArrayList(brokerData.getBrokerName()));
|
||||
String messageType = topicConfig.getAttributes().get(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName());
|
||||
if (StringUtils.isBlank(messageType)) {
|
||||
messageType = TopicMessageType.UNSPECIFIED.name();
|
||||
}
|
||||
topicConfigInfo.setMessageType(messageType);
|
||||
topicConfigInfoList.add(topicConfigInfo);
|
||||
}
|
||||
return topicConfigInfoList;
|
||||
@@ -168,7 +235,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
}
|
||||
mqAdminExt.deleteTopicInNameServer(nameServerSet, topic);
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -179,7 +247,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
} catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
for (String clusterName : clusterInfo.getClusterAddrTable().keySet()) {
|
||||
deleteTopic(topic, clusterName);
|
||||
@@ -195,11 +264,13 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
try {
|
||||
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mqAdminExt.deleteTopicInBroker(Sets.newHashSet(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr()), topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -209,7 +280,13 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
}
|
||||
|
||||
public DefaultMQProducer buildDefaultMQProducer(String producerGroup, RPCHook rpcHook, boolean traceEnabled) {
|
||||
DefaultMQProducer defaultMQProducer = new DefaultMQProducer(producerGroup, rpcHook, traceEnabled, configure.getMsgTrackTopicNameOrDefault());
|
||||
DefaultMQProducer defaultMQProducer = new DefaultMQProducer(producerGroup, rpcHook, traceEnabled, TopicValidator.RMQ_SYS_TRACE_TOPIC);
|
||||
defaultMQProducer.setUseTLS(configure.isUseTLS());
|
||||
return defaultMQProducer;
|
||||
}
|
||||
|
||||
public TransactionMQProducer buildTransactionMQProducer(String producerGroup, RPCHook rpcHook, boolean traceEnabled) {
|
||||
TransactionMQProducer defaultMQProducer = new TransactionMQProducer(null, producerGroup, rpcHook, traceEnabled, TopicValidator.RMQ_SYS_TRACE_TOPIC);
|
||||
defaultMQProducer.setUseTLS(configure.isUseTLS());
|
||||
return defaultMQProducer;
|
||||
}
|
||||
@@ -228,7 +305,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
producer.start();
|
||||
return producer.getDefaultMQProducerImpl().getmQClientFactory().getMQClientAPIImpl().getSystemTopicList(20000L);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
producer.shutdown();
|
||||
}
|
||||
@@ -236,7 +314,8 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
|
||||
@Override
|
||||
public SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest) {
|
||||
DefaultMQProducer producer = null;
|
||||
List<TopicConfigInfo> topicConfigInfos = examineTopicConfig(sendTopicMessageRequest.getTopic());
|
||||
String messageType = topicConfigInfos.get(0).getMessageType();
|
||||
AclClientRPCHook rpcHook = null;
|
||||
if (configure.isACLEnabled()) {
|
||||
rpcHook = new AclClientRPCHook(new SessionCredentials(
|
||||
@@ -244,6 +323,32 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
configure.getSecretKey()
|
||||
));
|
||||
}
|
||||
if (TopicMessageType.TRANSACTION.getValue().equals(messageType)) {
|
||||
// transaction message
|
||||
TransactionListener transactionListener = new TransactionListenerImpl();
|
||||
|
||||
TransactionMQProducer producer = buildTransactionMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
|
||||
producer.setNamesrvAddr(configure.getNamesrvAddr());
|
||||
producer.setTransactionListener(transactionListener);
|
||||
try {
|
||||
producer.start();
|
||||
Message msg = new Message(sendTopicMessageRequest.getTopic(),
|
||||
sendTopicMessageRequest.getTag(),
|
||||
sendTopicMessageRequest.getKey(),
|
||||
sendTopicMessageRequest.getMessageBody().getBytes()
|
||||
);
|
||||
return producer.sendMessageInTransaction(msg, null);
|
||||
} catch (Exception e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.shutdown();
|
||||
}
|
||||
} else {
|
||||
// no transaction message
|
||||
DefaultMQProducer producer = null;
|
||||
producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
|
||||
producer.setNamesrvAddr(configure.getNamesrvAddr());
|
||||
@@ -256,13 +361,16 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
);
|
||||
return producer.send(msg);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
|
||||
producer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void waitSendTraceFinish(DefaultMQProducer producer, boolean traceEnabled) {
|
||||
if (!traceEnabled) {
|
||||
return;
|
||||
@@ -282,4 +390,20 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
static class TransactionListenerImpl implements TransactionListener {
|
||||
private AtomicInteger transactionIndex = new AtomicInteger(0);
|
||||
|
||||
private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
|
||||
return LocalTransactionState.COMMIT_MESSAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
|
||||
return LocalTransactionState.COMMIT_MESSAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,15 +21,11 @@ import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.User;
|
||||
import org.apache.rocketmq.dashboard.service.UserService;
|
||||
import org.apache.rocketmq.srvutil.FileWatchService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
@@ -40,9 +36,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService, InitializingBean {
|
||||
@Resource
|
||||
RMQConfigure configure;
|
||||
private RMQConfigure configure;
|
||||
|
||||
FileBasedUserInfoStore fileBasedUserInfoStore;
|
||||
private FileBasedUserInfoStore fileBasedUserInfoStore;
|
||||
|
||||
@Override
|
||||
public User queryByName(String name) {
|
||||
@@ -61,40 +57,17 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileBasedUserInfoStore {
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
public static class FileBasedUserInfoStore extends AbstractFileStore {
|
||||
private static final String FILE_NAME = "users.properties";
|
||||
|
||||
private String filePath;
|
||||
private final Map<String, User> userMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static Map<String, User> userMap = new ConcurrentHashMap<>();
|
||||
|
||||
public FileBasedUserInfoStore(RMQConfigure configure) {
|
||||
filePath = configure.getRocketMqDashboardDataPath() + File.separator + FILE_NAME;
|
||||
if (!new File(filePath).exists()) {
|
||||
//Use the default path
|
||||
InputStream inputStream = getClass().getResourceAsStream("/" + FILE_NAME);
|
||||
if (inputStream == null) {
|
||||
log.error(String.format("Can not found the file %s in Spring Boot jar", FILE_NAME));
|
||||
System.out.printf(String.format("Can not found file %s in Spring Boot jar or %s, stop the dashboard starting",
|
||||
FILE_NAME, configure.getRocketMqDashboardDataPath()));
|
||||
System.exit(1);
|
||||
} else {
|
||||
load(inputStream);
|
||||
}
|
||||
} else {
|
||||
log.info(String.format("Login Users configure file is %s", filePath));
|
||||
load();
|
||||
watch();
|
||||
}
|
||||
super(configure, FILE_NAME);
|
||||
}
|
||||
|
||||
private void load() {
|
||||
load(null);
|
||||
}
|
||||
|
||||
private void load(InputStream inputStream) {
|
||||
|
||||
@Override
|
||||
public void load(InputStream inputStream) {
|
||||
Properties prop = new Properties();
|
||||
try {
|
||||
if (inputStream == null) {
|
||||
@@ -112,7 +85,8 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
int role;
|
||||
for (String key : prop.stringPropertyNames()) {
|
||||
String v = prop.getProperty(key);
|
||||
if (v == null) continue;
|
||||
if (v == null)
|
||||
continue;
|
||||
arrs = v.split(",", 2);
|
||||
if (arrs.length == 0) {
|
||||
continue;
|
||||
@@ -125,30 +99,10 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
loadUserMap.put(key, new User(key, arrs[0].trim(), role));
|
||||
}
|
||||
|
||||
|
||||
userMap.clear();
|
||||
userMap.putAll(loadUserMap);
|
||||
}
|
||||
|
||||
private boolean watch() {
|
||||
try {
|
||||
FileWatchService fileWatchService = new FileWatchService(new String[]{filePath}, new FileWatchService.Listener() {
|
||||
@Override
|
||||
public void onChanged(String path) {
|
||||
log.info("The loginUserInfo property file changed, reload the context");
|
||||
load();
|
||||
}
|
||||
});
|
||||
fileWatchService.start();
|
||||
log.info("Succeed to start LoginUserWatcherService");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to start LoginUserWatcherService", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public User queryByName(String name) {
|
||||
return userMap.get(name);
|
||||
}
|
||||
@@ -158,7 +112,6 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
if (user != null && password.equals(user.getPassword())) {
|
||||
return user.cloneOne();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -34,11 +34,12 @@ public class GlobalExceptionHandler {
|
||||
public JsonResult<Object> jsonErrorHandler(HttpServletRequest req, Exception ex) throws Exception {
|
||||
JsonResult<Object> value = null;
|
||||
if (ex != null) {
|
||||
logger.error("op=global_exception_handler_print_error", ex);
|
||||
if (ex instanceof ServiceException) {
|
||||
logger.error("Occur service exception: {}", ex.getMessage());
|
||||
value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage());
|
||||
}
|
||||
else {
|
||||
logger.error("op=global_exception_handler_print_error", ex);
|
||||
value = new JsonResult<Object>(-1, ex.getMessage() == null ? ex.toString() : ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.task;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.stats.Stats;
|
||||
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.remoting.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
|
||||
|
||||
@Slf4j
|
||||
public class CollectTaskRunnble implements Runnable {
|
||||
|
||||
private String topic;
|
||||
|
||||
private MQAdminExt mqAdminExt;
|
||||
|
||||
private DashboardCollectService dashboardCollectService;
|
||||
|
||||
public CollectTaskRunnble(String topic, MQAdminExt mqAdminExt,
|
||||
DashboardCollectService dashboardCollectService) {
|
||||
this.topic = topic;
|
||||
this.mqAdminExt = mqAdminExt;
|
||||
this.dashboardCollectService = dashboardCollectService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Date date = new Date();
|
||||
try {
|
||||
TopicRouteData topicRouteData = mqAdminExt.examineTopicRouteInfo(topic);
|
||||
GroupList groupList = mqAdminExt.queryTopicConsumeByWho(topic);
|
||||
double inTPS = 0;
|
||||
long inMsgCntToday = 0;
|
||||
double outTPS = 0;
|
||||
long outMsgCntToday = 0;
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, Stats.TOPIC_PUT_NUMS, topic);
|
||||
inTPS += bsd.getStatsMinute().getTps();
|
||||
inMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
} catch (Exception e) {
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data TOPIC_PUT_NUMS failed, topic [{}]", topic, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (groupList != null && !groupList.getGroupList().isEmpty()) {
|
||||
for (String group : groupList.getGroupList()) {
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
String statsKey = String.format("%s@%s", topic, group);
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, Stats.GROUP_GET_NUMS, statsKey);
|
||||
outTPS += bsd.getStatsMinute().getTps();
|
||||
outMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
} catch (Exception e) {
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data GROUP_GET_NUMS failed, topic [{}], group [{}]", topic, group, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> list;
|
||||
try {
|
||||
list = dashboardCollectService.getTopicMap().get(topic);
|
||||
} catch (ExecutionException e) {
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (null == list) {
|
||||
list = Lists.newArrayList();
|
||||
}
|
||||
|
||||
list.add(date.getTime() + "," + new BigDecimal(inTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + inMsgCntToday + "," + new BigDecimal(outTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + outMsgCntToday);
|
||||
dashboardCollectService.getTopicMap().put(topic, list);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to collect topic: {} data", topic, e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,18 +16,6 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.task;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.dashboard.aspect.admin.annotation.MultiMQAdminCmdMethod;
|
||||
import org.apache.rocketmq.store.stats.BrokerStatsManager;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -43,13 +31,18 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.remoting.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.topic.TopicValidator;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -68,15 +61,14 @@ public class DashboardCollectTask {
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(DashboardCollectTask.class);
|
||||
|
||||
@Resource
|
||||
private ExecutorService collectExecutor;
|
||||
|
||||
@Scheduled(cron = "30 0/1 * * * ?")
|
||||
@MultiMQAdminCmdMethod(timeoutMillis = 5000)
|
||||
public void collectTopic() {
|
||||
if (!rmqConfigure.isEnableDashBoardCollect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Date date = new Date();
|
||||
Stopwatch stopwatch = Stopwatch.createUnstarted();
|
||||
try {
|
||||
TopicList topicList = mqAdminExt.fetchAllTopicList();
|
||||
Set<String> topicSet = topicList.getTopicList();
|
||||
@@ -87,80 +79,13 @@ public class DashboardCollectTask {
|
||||
|| TopicValidator.isSystemTopic(topic)) {
|
||||
continue;
|
||||
}
|
||||
TopicRouteData topicRouteData = mqAdminExt.examineTopicRouteInfo(topic);
|
||||
|
||||
GroupList groupList = mqAdminExt.queryTopicConsumeByWho(topic);
|
||||
|
||||
double inTPS = 0;
|
||||
|
||||
long inMsgCntToday = 0;
|
||||
|
||||
double outTPS = 0;
|
||||
|
||||
long outMsgCntToday = 0;
|
||||
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
stopwatch.start();
|
||||
log.info("start time: {}", stopwatch.toString());
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, BrokerStatsManager.TOPIC_PUT_NUMS, topic);
|
||||
stopwatch.stop();
|
||||
log.info("stop time : {}", stopwatch.toString());
|
||||
|
||||
inTPS += bsd.getStatsMinute().getTps();
|
||||
inMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
CollectTaskRunnble collectTask = new CollectTaskRunnble(topic, mqAdminExt, dashboardCollectService);
|
||||
collectExecutor.submit(collectTask);
|
||||
}
|
||||
catch (Exception e) {
|
||||
stopwatch.reset();
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data TOPIC_PUT_NUMS failed");
|
||||
log.warn("Response [{}] ", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groupList != null && !groupList.getGroupList().isEmpty()) {
|
||||
|
||||
for (String group : groupList.getGroupList()) {
|
||||
for (BrokerData bd : topicRouteData.getBrokerDatas()) {
|
||||
String masterAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
|
||||
if (masterAddr != null) {
|
||||
try {
|
||||
String statsKey = String.format("%s@%s", topic, group);
|
||||
BrokerStatsData bsd = mqAdminExt.viewBrokerStatsData(masterAddr, BrokerStatsManager.GROUP_GET_NUMS, statsKey);
|
||||
outTPS += bsd.getStatsMinute().getTps();
|
||||
outMsgCntToday += StatsAllSubCommand.compute24HourSum(bsd);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception caught: mqAdminExt get broker stats data GROUP_GET_NUMS failed");
|
||||
log.warn("Response [{}] ", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> list;
|
||||
try {
|
||||
list = dashboardCollectService.getTopicMap().get(topic);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
if (null == list) {
|
||||
list = Lists.newArrayList();
|
||||
}
|
||||
|
||||
list.add(date.getTime() + "," + new BigDecimal(inTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + inMsgCntToday + "," + new BigDecimal(outTPS).setScale(5, BigDecimal.ROUND_HALF_UP) + "," + outMsgCntToday);
|
||||
dashboardCollectService.getTopicMap().put(topic, list);
|
||||
|
||||
}
|
||||
|
||||
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
Throwables.throwIfUnchecked(err);
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +129,8 @@ public class DashboardCollectTask {
|
||||
log.debug("Broker Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getBrokerMap().asMap()));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,10 +146,12 @@ public class DashboardCollectTask {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
catch (InterruptedException e1) {
|
||||
throw Throwables.propagate(e1);
|
||||
Throwables.throwIfUnchecked(e1);
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
fetchBrokerRuntimeStats(brokerAddr, retryTime - 1);
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +201,8 @@ public class DashboardCollectTask {
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
Throwables.throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,10 +255,11 @@ public class DashboardCollectTask {
|
||||
|
||||
private void addSystemTopic() throws Exception {
|
||||
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
HashMap<String, Set<String>> clusterTable = clusterInfo.getClusterAddrTable();
|
||||
Map<String, Set<String>> clusterTable = clusterInfo.getClusterAddrTable();
|
||||
for (Map.Entry<String, Set<String>> entry : clusterTable.entrySet()) {
|
||||
String clusterName = entry.getKey();
|
||||
TopicValidator.addSystemTopic(clusterName);
|
||||
TopicValidator.addSystemTopic(MixAll.getReplyTopic(clusterName));
|
||||
Set<String> brokerNames = entry.getValue();
|
||||
for (String brokerName : brokerNames) {
|
||||
TopicValidator.addSystemTopic(brokerName);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user