mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-11 03:49:06 +08:00
Compare commits
27 Commits
develop
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
|
c09d97dac8 | ||
|
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 |
@@ -20,3 +20,5 @@ script:
|
||||
# - 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'
|
||||
|
2
LICENSE
2
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.
|
||||
|
2
NOTICE
2
NOTICE
@@ -1,5 +1,5 @@
|
||||
Apache RocketMQ
|
||||
Copyright 2016-2021 The Apache Software Foundation
|
||||
Copyright 2016-2022 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
@@ -1,5 +1,7 @@
|
||||
## [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)
|
||||
## [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)
|
||||
|
@@ -1645,6 +1645,11 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
|
||||
"@tootallnate/once@1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@types/anymatch@*":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
|
||||
@@ -2131,10 +2136,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
|
||||
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
|
||||
|
||||
abab@^2.0.3:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
||||
integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==
|
||||
abab@^2.0.3, abab@^2.0.5:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
|
||||
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
|
||||
|
||||
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
|
||||
version "1.3.7"
|
||||
@@ -2172,6 +2177,11 @@ acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0:
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
acorn@^8.2.4:
|
||||
version "8.7.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
|
||||
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||
|
||||
address@1.1.2, address@^1.0.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6"
|
||||
@@ -2185,6 +2195,13 @@ adjust-sourcemap-loader@3.0.0:
|
||||
loader-utils "^2.0.0"
|
||||
regex-parser "^2.2.11"
|
||||
|
||||
agent-base@6:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
||||
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
|
||||
dependencies:
|
||||
debug "4"
|
||||
|
||||
aggregate-error@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
|
||||
@@ -2203,7 +2220,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
|
||||
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
|
||||
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
|
||||
|
||||
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
|
||||
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||
@@ -2422,18 +2439,6 @@ asn1.js@^5.2.0:
|
||||
minimalistic-assert "^1.0.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
|
||||
|
||||
assert@^1.1.1:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
|
||||
@@ -2477,7 +2482,7 @@ async@^2.6.2:
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
at-least-node@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -2502,16 +2507,6 @@ autoprefixer@^9.6.1:
|
||||
postcss "^7.0.32"
|
||||
postcss-value-parser "^4.1.0"
|
||||
|
||||
aws-sign2@~0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
||||
axe-core@^4.0.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224"
|
||||
@@ -2719,13 +2714,6 @@ batch@0.6.1:
|
||||
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
|
||||
integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
bfj@^7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.0.2.tgz#1988ce76f3add9ac2913fd8ba47aad9e651bfbb2"
|
||||
@@ -3116,11 +3104,6 @@ case-sensitive-paths-webpack-plugin@2.3.0:
|
||||
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7"
|
||||
integrity sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
||||
|
||||
chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
@@ -3345,7 +3328,7 @@ colorette@^1.2.1:
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
|
||||
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
@@ -3518,7 +3501,7 @@ core-js@^3.6.5:
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.0.tgz#790b1bb11553a2272b36e2625c7179db345492f8"
|
||||
integrity sha512-PyFBJaLq93FlyYdsndE5VaueA9K5cNB7CGzeCj191YYLhkQM0gdZR2SKihM70oF0wdqKSKClv/tEBOpoRmdOVQ==
|
||||
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
@@ -3848,7 +3831,7 @@ cssom@~0.3.6:
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
|
||||
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
|
||||
|
||||
cssstyle@^2.2.0:
|
||||
cssstyle@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852"
|
||||
integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==
|
||||
@@ -3873,13 +3856,6 @@ damerau-levenshtein@^1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791"
|
||||
integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==
|
||||
|
||||
dashdash@^1.12.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
data-urls@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b"
|
||||
@@ -3896,6 +3872,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
debug@^3.1.1, debug@^3.2.6:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
|
||||
@@ -3915,10 +3898,10 @@ decamelize@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||
|
||||
decimal.js@^10.2.0:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3"
|
||||
integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==
|
||||
decimal.js@^10.2.1:
|
||||
version "10.3.1"
|
||||
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
|
||||
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
||||
|
||||
decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -3942,11 +3925,16 @@ deep-equal@^1.0.1:
|
||||
object-keys "^1.1.1"
|
||||
regexp.prototype.flags "^1.2.0"
|
||||
|
||||
deep-is@^0.1.3, deep-is@~0.1.3:
|
||||
deep-is@^0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||
|
||||
deep-is@~0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
||||
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
||||
|
||||
deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
@@ -4005,7 +3993,7 @@ del@^4.1.1:
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
depd@~1.1.2:
|
||||
version "1.1.2"
|
||||
@@ -4208,14 +4196,6 @@ duplexify@^3.4.2, duplexify@^3.6.0:
|
||||
readable-stream "^2.0.0"
|
||||
stream-shift "^1.0.0"
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
@@ -4425,13 +4405,13 @@ escape-string-regexp@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
escodegen@^1.14.1:
|
||||
version "1.14.3"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
|
||||
integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
|
||||
escodegen@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
|
||||
integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==
|
||||
dependencies:
|
||||
esprima "^4.0.1"
|
||||
estraverse "^4.2.0"
|
||||
estraverse "^5.2.0"
|
||||
esutils "^2.0.2"
|
||||
optionator "^0.8.1"
|
||||
optionalDependencies:
|
||||
@@ -4655,16 +4635,21 @@ esrecurse@^4.1.0, esrecurse@^4.3.0:
|
||||
dependencies:
|
||||
estraverse "^5.2.0"
|
||||
|
||||
estraverse@^4.1.1, estraverse@^4.2.0:
|
||||
estraverse@^4.1.1:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
|
||||
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
||||
|
||||
estraverse@^5.1.0, estraverse@^5.2.0:
|
||||
estraverse@^5.1.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
|
||||
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
|
||||
|
||||
estraverse@^5.2.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
|
||||
estree-walker@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
|
||||
@@ -4831,11 +4816,6 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
|
||||
assign-symbols "^1.0.0"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
extglob@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
|
||||
@@ -4850,16 +4830,6 @@ extglob@^2.0.4:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
|
||||
|
||||
extsprintf@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
@@ -5077,11 +5047,6 @@ for-in@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
fork-ts-checker-webpack-plugin@4.1.6:
|
||||
version "4.1.6"
|
||||
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5"
|
||||
@@ -5095,13 +5060,13 @@ fork-ts-checker-webpack-plugin@4.1.6:
|
||||
tapable "^1.0.0"
|
||||
worker-rpc "^0.1.0"
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
|
||||
form-data@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
forwarded@~0.1.2:
|
||||
@@ -5250,13 +5215,6 @@ get-value@^2.0.3, get-value@^2.0.6:
|
||||
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
|
||||
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
glob-parent@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
|
||||
@@ -5370,19 +5328,6 @@ handle-thing@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e"
|
||||
integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||
|
||||
har-validator@~5.1.3:
|
||||
version "5.1.5"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
|
||||
integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
|
||||
dependencies:
|
||||
ajv "^6.12.3"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
harmony-reflect@^1.4.6:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.1.tgz#c108d4f2bb451efef7a37861fdbdae72c9bdefa9"
|
||||
@@ -5611,6 +5556,15 @@ http-parser-js@>=0.5.1:
|
||||
resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9"
|
||||
integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==
|
||||
|
||||
http-proxy-agent@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
|
||||
integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
|
||||
dependencies:
|
||||
"@tootallnate/once" "1"
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
http-proxy-middleware@0.19.1:
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a"
|
||||
@@ -5630,20 +5584,19 @@ http-proxy@^1.17.0:
|
||||
follow-redirects "^1.0.0"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
https-browserify@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||
|
||||
https-proxy-agent@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
|
||||
integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
|
||||
dependencies:
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
human-signals@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||
@@ -6068,10 +6021,10 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
||||
dependencies:
|
||||
isobject "^3.0.1"
|
||||
|
||||
is-potential-custom-element-name@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
|
||||
integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
|
||||
is-potential-custom-element-name@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
|
||||
integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
|
||||
|
||||
is-regex@^1.0.4, is-regex@^1.1.1:
|
||||
version "1.1.2"
|
||||
@@ -6125,7 +6078,7 @@ is-symbol@^1.0.2:
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
is-typedarray@^1.0.0, is-typedarray@~1.0.0:
|
||||
is-typedarray@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
@@ -6169,11 +6122,6 @@ isobject@^3.0.0, isobject@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||
|
||||
istanbul-lib-coverage@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
|
||||
@@ -6678,41 +6626,37 @@ js-yaml@^3.13.1:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
jsdom@^16.4.0:
|
||||
version "16.4.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
|
||||
integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
|
||||
version "16.7.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710"
|
||||
integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==
|
||||
dependencies:
|
||||
abab "^2.0.3"
|
||||
acorn "^7.1.1"
|
||||
abab "^2.0.5"
|
||||
acorn "^8.2.4"
|
||||
acorn-globals "^6.0.0"
|
||||
cssom "^0.4.4"
|
||||
cssstyle "^2.2.0"
|
||||
cssstyle "^2.3.0"
|
||||
data-urls "^2.0.0"
|
||||
decimal.js "^10.2.0"
|
||||
decimal.js "^10.2.1"
|
||||
domexception "^2.0.1"
|
||||
escodegen "^1.14.1"
|
||||
escodegen "^2.0.0"
|
||||
form-data "^3.0.0"
|
||||
html-encoding-sniffer "^2.0.1"
|
||||
is-potential-custom-element-name "^1.0.0"
|
||||
http-proxy-agent "^4.0.1"
|
||||
https-proxy-agent "^5.0.0"
|
||||
is-potential-custom-element-name "^1.0.1"
|
||||
nwsapi "^2.2.0"
|
||||
parse5 "5.1.1"
|
||||
request "^2.88.2"
|
||||
request-promise-native "^1.0.8"
|
||||
saxes "^5.0.0"
|
||||
parse5 "6.0.1"
|
||||
saxes "^5.0.1"
|
||||
symbol-tree "^3.2.4"
|
||||
tough-cookie "^3.0.1"
|
||||
tough-cookie "^4.0.0"
|
||||
w3c-hr-time "^1.0.2"
|
||||
w3c-xmlserializer "^2.0.0"
|
||||
webidl-conversions "^6.1.0"
|
||||
whatwg-encoding "^1.0.5"
|
||||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
ws "^7.2.3"
|
||||
whatwg-url "^8.5.0"
|
||||
ws "^7.4.6"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
jsesc@^2.5.1:
|
||||
@@ -6745,21 +6689,11 @@ json-schema-traverse@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
|
||||
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
|
||||
|
||||
json-stable-stringify-without-jsonify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
|
||||
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
|
||||
|
||||
json-stringify-safe@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
|
||||
json3@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81"
|
||||
@@ -6795,16 +6729,6 @@ jsonfile@^6.0.1:
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
|
||||
dependencies:
|
||||
assert-plus "1.0.0"
|
||||
extsprintf "1.3.0"
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82"
|
||||
@@ -6888,7 +6812,7 @@ levn@^0.4.1:
|
||||
levn@~0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
|
||||
integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
|
||||
integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
|
||||
dependencies:
|
||||
prelude-ls "~1.1.2"
|
||||
type-check "~0.3.2"
|
||||
@@ -6983,11 +6907,6 @@ lodash.memoize@^4.1.2:
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||
|
||||
lodash.template@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
|
||||
@@ -7008,7 +6927,7 @@ lodash.uniq@^4.5.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5:
|
||||
"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5, lodash@^4.7.0:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
@@ -7197,7 +7116,19 @@ mime-db@1.46.0, "mime-db@>= 1.43.0 < 2":
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee"
|
||||
integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==
|
||||
|
||||
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@^2.1.12:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24:
|
||||
version "2.1.29"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2"
|
||||
integrity sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==
|
||||
@@ -7579,11 +7510,6 @@ nwsapi@^2.2.0:
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
|
||||
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
@@ -7915,10 +7841,10 @@ parse-json@^5.0.0:
|
||||
json-parse-even-better-errors "^2.3.0"
|
||||
lines-and-columns "^1.1.6"
|
||||
|
||||
parse5@5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
|
||||
integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
|
||||
parse5@6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
|
||||
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||
|
||||
parseurl@~1.3.2, parseurl@~1.3.3:
|
||||
version "1.3.3"
|
||||
@@ -8778,7 +8704,7 @@ prelude-ls@^1.2.1:
|
||||
prelude-ls@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
||||
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
|
||||
|
||||
prepend-http@^1.0.0:
|
||||
version "1.0.4"
|
||||
@@ -8882,7 +8808,7 @@ prr@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
|
||||
|
||||
psl@^1.1.28:
|
||||
psl@^1.1.33:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
||||
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
|
||||
@@ -8954,11 +8880,6 @@ qs@6.7.0:
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
query-string@^4.1.0:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
|
||||
@@ -9407,48 +9328,6 @@ repeat-string@^1.6.1:
|
||||
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
|
||||
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
|
||||
|
||||
request-promise-core@1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f"
|
||||
integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==
|
||||
dependencies:
|
||||
lodash "^4.17.19"
|
||||
|
||||
request-promise-native@^1.0.8:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28"
|
||||
integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==
|
||||
dependencies:
|
||||
request-promise-core "1.1.4"
|
||||
stealthy-require "^1.1.1"
|
||||
tough-cookie "^2.3.3"
|
||||
|
||||
request@^2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
@@ -9666,7 +9545,7 @@ safe-regex@^1.1.0:
|
||||
dependencies:
|
||||
ret "~0.1.10"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
@@ -9707,7 +9586,7 @@ sax@~1.2.4:
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
saxes@^5.0.0:
|
||||
saxes@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
|
||||
integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==
|
||||
@@ -10132,21 +10011,6 @@ sprintf-js@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
||||
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
bcrypt-pbkdf "^1.0.0"
|
||||
dashdash "^1.12.0"
|
||||
ecc-jsbn "~0.1.1"
|
||||
getpass "^0.1.1"
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.0.2"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
ssri@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
|
||||
@@ -10191,11 +10055,6 @@ static-extend@^0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
|
||||
|
||||
stealthy-require@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
||||
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
|
||||
|
||||
stream-browserify@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
|
||||
@@ -10645,27 +10504,19 @@ toidentifier@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
|
||||
tough-cookie@^2.3.3, tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
tough-cookie@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
|
||||
integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
|
||||
dependencies:
|
||||
psl "^1.1.28"
|
||||
psl "^1.1.33"
|
||||
punycode "^2.1.1"
|
||||
universalify "^0.1.2"
|
||||
|
||||
tough-cookie@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2"
|
||||
integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==
|
||||
dependencies:
|
||||
ip-regex "^2.1.0"
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tr46@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479"
|
||||
integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==
|
||||
tr46@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240"
|
||||
integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
|
||||
dependencies:
|
||||
punycode "^2.1.1"
|
||||
|
||||
@@ -10716,18 +10567,6 @@ tty-browserify@0.0.0:
|
||||
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
|
||||
integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
||||
@@ -10738,7 +10577,7 @@ type-check@^0.4.0, type-check@~0.4.0:
|
||||
type-check@~0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
|
||||
integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
|
||||
integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
|
||||
dependencies:
|
||||
prelude-ls "~1.1.2"
|
||||
|
||||
@@ -10866,7 +10705,7 @@ unique-string@^1.0.0:
|
||||
dependencies:
|
||||
crypto-random-string "^1.0.0"
|
||||
|
||||
universalify@^0.1.0:
|
||||
universalify@^0.1.0, universalify@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
||||
@@ -11049,15 +10888,6 @@ vendors@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e"
|
||||
integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
vm-browserify@^1.0.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
@@ -11260,13 +11090,13 @@ whatwg-mimetype@^2.3.0:
|
||||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
|
||||
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
|
||||
|
||||
whatwg-url@^8.0.0:
|
||||
version "8.4.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837"
|
||||
integrity sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==
|
||||
whatwg-url@^8.0.0, whatwg-url@^8.5.0:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77"
|
||||
integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==
|
||||
dependencies:
|
||||
lodash.sortby "^4.7.0"
|
||||
tr46 "^2.0.2"
|
||||
lodash "^4.7.0"
|
||||
tr46 "^2.1.0"
|
||||
webidl-conversions "^6.1.0"
|
||||
|
||||
which-module@^2.0.0:
|
||||
@@ -11500,10 +11330,10 @@ ws@^6.2.1:
|
||||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
ws@^7.2.3:
|
||||
version "7.4.3"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.3.tgz#1f9643de34a543b8edb124bdcbc457ae55a6e5cd"
|
||||
integrity sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==
|
||||
ws@^7.4.6:
|
||||
version "7.5.8"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a"
|
||||
integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==
|
||||
|
||||
xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
|
40
pom.xml
40
pom.xml
@@ -90,18 +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>4.9.3</rocketmq.version>
|
||||
<surefire.version>2.19.1</surefire.version>
|
||||
<aspectj.version>1.9.6</aspectj.version>
|
||||
<lombok.version>1.18.12</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.30</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>
|
||||
@@ -125,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>
|
||||
@@ -203,17 +220,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>
|
||||
@@ -246,6 +263,17 @@
|
||||
<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>
|
||||
|
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
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;
|
||||
@@ -33,6 +34,8 @@ public class MQAdminFactory {
|
||||
this.rmqConfigure = rmqConfigure;
|
||||
}
|
||||
|
||||
private final AtomicLong adminIndex = new AtomicLong(0);
|
||||
|
||||
public MQAdminExt getInstance() throws Exception {
|
||||
RPCHook rpcHook = null;
|
||||
final String accessKey = rmqConfigure.getAccessKey();
|
||||
@@ -47,6 +50,7 @@ public class MQAdminFactory {
|
||||
} 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()));
|
||||
|
@@ -50,17 +50,19 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
if (configure.isLoginRequired()) {
|
||||
registry.addInterceptor(authInterceptor).addPathPatterns(
|
||||
"/cluster/**",
|
||||
"/consumer/**",
|
||||
"/dashboard/**",
|
||||
"/message/**",
|
||||
"/messageTrace/**",
|
||||
"/monitor/**",
|
||||
"/rocketmq/**",
|
||||
"/ops/**",
|
||||
"/producer/**",
|
||||
"/test/**",
|
||||
"/topic/**");
|
||||
"/cluster/**",
|
||||
"/consumer/**",
|
||||
"/dashboard/**",
|
||||
"/dlqMessage/**",
|
||||
"/message/**",
|
||||
"/messageTrace/**",
|
||||
"/monitor/**",
|
||||
"/rocketmq/**",
|
||||
"/ops/**",
|
||||
"/producer/**",
|
||||
"/test/**",
|
||||
"/topic/**",
|
||||
"/acl/**");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,9 +77,9 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
|
||||
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
|
||||
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
|
||||
UserInfo userInfo = (UserInfo) WebUtil.getValueFromSession((HttpServletRequest) nativeWebRequest.getNativeRequest(),
|
||||
UserInfo.USER_INFO);
|
||||
UserInfo.USER_INFO);
|
||||
if (userInfo != null) {
|
||||
return userInfo;
|
||||
}
|
||||
|
@@ -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,6 +16,8 @@
|
||||
*/
|
||||
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.slf4j.Logger;
|
||||
@@ -29,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;
|
||||
|
||||
@@ -57,6 +60,8 @@ public class RMQConfigure {
|
||||
|
||||
private Long timeoutMillis;
|
||||
|
||||
private List<String> namesrvAddrs = new ArrayList<>();
|
||||
|
||||
public String getAccessKey() {
|
||||
return accessKey;
|
||||
}
|
||||
@@ -77,6 +82,17 @@ public class RMQConfigure {
|
||||
return namesrvAddr;
|
||||
}
|
||||
|
||||
public List<String> getNamesrvAddrs() {
|
||||
return namesrvAddrs;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -51,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();
|
||||
|
@@ -17,12 +17,16 @@
|
||||
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;
|
||||
@@ -30,6 +34,7 @@ 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;
|
||||
@@ -39,6 +44,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@Controller
|
||||
@RequestMapping("/dlqMessage")
|
||||
@Permission
|
||||
@Slf4j
|
||||
public class DlqMessageController {
|
||||
|
||||
@Resource
|
||||
@@ -70,4 +76,33 @@ public class DlqMessageController {
|
||||
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!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ 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,9 @@
|
||||
*/
|
||||
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;
|
||||
@@ -46,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) {
|
||||
@@ -53,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) {
|
||||
|
@@ -25,9 +25,11 @@ 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)
|
||||
@@ -66,6 +68,10 @@ public class DlqMessageExcelModel extends BaseRowModel implements Serializable {
|
||||
@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();
|
||||
|
@@ -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.common.protocol.body.CMResult;
|
||||
import org.apache.rocketmq.common.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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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,10 +17,15 @@
|
||||
|
||||
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);
|
||||
}
|
||||
|
@@ -31,4 +31,6 @@ public interface OpsService {
|
||||
boolean updateIsVIPChannel(String useVIPChannel);
|
||||
|
||||
boolean updateUseTLS(boolean useTLS);
|
||||
|
||||
void addNameSvrAddr(String namesrvAddr);
|
||||
}
|
||||
|
@@ -91,29 +91,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
|
||||
@@ -235,6 +240,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 +283,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
|
||||
@@ -511,9 +523,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
|
||||
|
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* 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.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.common.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);
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncData(PlainAccessConfig config) {
|
||||
try {
|
||||
for (String addr : getBrokerAddrs()) {
|
||||
mqAdminExt.createAndUpdatePlainAccessConfig(addr, config);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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) {
|
||||
throw Throwables.propagate(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;
|
||||
}
|
||||
}
|
@@ -23,12 +23,14 @@ 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.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
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;
|
||||
@@ -46,6 +48,7 @@ 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.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.model.ConsumerGroupRollBackStat;
|
||||
import org.apache.rocketmq.dashboard.model.GroupConsumeInfo;
|
||||
import org.apache.rocketmq.dashboard.model.QueueStatInfo;
|
||||
@@ -65,6 +68,9 @@ import static com.google.common.base.Throwables.propagate;
|
||||
public class ConsumerServiceImpl extends AbstractCommonService implements ConsumerService {
|
||||
private Logger logger = LoggerFactory.getLogger(ConsumerServiceImpl.class);
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
private static final Set<String> SYSTEM_GROUP_SET = new HashSet<>();
|
||||
|
||||
static {
|
||||
@@ -290,11 +296,21 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
|
||||
@Override
|
||||
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) {
|
||||
@@ -303,6 +319,18 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
||||
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 {
|
||||
|
@@ -19,12 +19,16 @@ 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.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.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;
|
||||
@@ -65,4 +69,17 @@ public class DlqMessageServiceImpl implements DlqMessageService {
|
||||
}
|
||||
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,6 +31,7 @@ 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;
|
||||
@@ -111,6 +112,9 @@ public class MessageServiceImpl implements MessageService {
|
||||
}
|
||||
});
|
||||
} catch (Exception err) {
|
||||
if (err instanceof MQClientException) {
|
||||
throw new ServiceException(-1, ((MQClientException) err).getErrorMessage());
|
||||
}
|
||||
throw Throwables.propagate(err);
|
||||
}
|
||||
}
|
||||
@@ -325,7 +329,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;
|
||||
|
@@ -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;
|
||||
@@ -35,6 +33,7 @@ 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;
|
||||
@@ -82,7 +81,7 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
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;
|
||||
@@ -46,7 +45,8 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
@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;
|
||||
@@ -73,7 +73,8 @@ 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;
|
||||
@@ -85,4 +86,13 @@ public class OpsServiceImpl extends AbstractCommonService implements OpsService
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -135,10 +135,10 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
|
||||
ClusterInfo clusterInfo = null;
|
||||
try {
|
||||
clusterInfo = mqAdminExt.examineBrokerClusterInfo();
|
||||
return mqAdminExt.examineTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topic);
|
||||
} catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
return mqAdminExt.examineTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topic);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -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.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.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.common.protocol.body.GroupList;
|
||||
import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.service.DashboardCollectService;
|
||||
import org.apache.rocketmq.store.stats.BrokerStatsManager;
|
||||
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, BrokerStatsManager.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, 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, topic [{}], group [{}]", topic, group, 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);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to collect topic: {} data", topic, e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,17 +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.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;
|
||||
@@ -42,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.common.protocol.body.ClusterInfo;
|
||||
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.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;
|
||||
@@ -67,14 +61,14 @@ public class DashboardCollectTask {
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(DashboardCollectTask.class);
|
||||
|
||||
@Resource
|
||||
private ExecutorService collectExecutor;
|
||||
|
||||
@Scheduled(cron = "30 0/1 * * * ?")
|
||||
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();
|
||||
@@ -85,77 +79,9 @@ 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);
|
||||
}
|
||||
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);
|
||||
|
||||
CollectTaskRunnble collectTask = new CollectTaskRunnble(topic, mqAdminExt, dashboardCollectService);
|
||||
collectExecutor.submit(collectTask);
|
||||
}
|
||||
|
||||
log.debug("Topic Collected Data in memory = {}" + JsonUtil.obj2String(dashboardCollectService.getTopicMap().asMap()));
|
||||
}
|
||||
catch (Exception err) {
|
||||
throw Throwables.propagate(err);
|
||||
@@ -328,6 +254,7 @@ public class DashboardCollectTask {
|
||||
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);
|
||||
|
@@ -1,54 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
server.address=0.0.0.0
|
||||
server.port=8080
|
||||
|
||||
### SSL setting
|
||||
#server.ssl.key-store=classpath:rmqcngkeystore.jks
|
||||
#server.ssl.key-store-password=rocketmq
|
||||
#server.ssl.keyStoreType=PKCS12
|
||||
#server.ssl.keyAlias=rmqcngkey
|
||||
|
||||
#spring.application.index=true
|
||||
spring.application.name=rocketmq-dashboard
|
||||
spring.http.encoding.charset=UTF-8
|
||||
spring.http.encoding.enabled=true
|
||||
spring.http.encoding.force=true
|
||||
logging.level.root=INFO
|
||||
logging.config=classpath:logback.xml
|
||||
#if this value is empty,use env value rocketmq.config.namesrvAddr NAMESRV_ADDR | now, you can set it in ops page.default localhost:9876
|
||||
rocketmq.config.namesrvAddr=
|
||||
#if you use rocketmq version < 3.5.8, rocketmq.config.isVIPChannel should be false.default true
|
||||
rocketmq.config.isVIPChannel=
|
||||
#timeout for mqadminExt, default 5000ms
|
||||
rocketmq.config.timeoutMillis=
|
||||
#rocketmq-console's data path:dashboard/monitor
|
||||
rocketmq.config.dataPath=/tmp/rocketmq-console/data
|
||||
#set it false if you don't want use dashboard.default true
|
||||
rocketmq.config.enableDashBoardCollect=true
|
||||
#set the message track trace topic if you don't want use the default one
|
||||
rocketmq.config.msgTrackTopicName=
|
||||
rocketmq.config.ticketKey=ticket
|
||||
|
||||
#Must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
||||
rocketmq.config.loginRequired=false
|
||||
|
||||
#set the accessKey and secretKey if you used acl
|
||||
#rocketmq.config.accessKey=
|
||||
#rocketmq.config.secretKey=
|
||||
rocketmq.config.useTLS=false
|
69
src/main/resources/application.yml
Normal file
69
src/main/resources/application.yml
Normal file
@@ -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.
|
||||
#
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
servlet:
|
||||
encoding:
|
||||
charset: UTF-8
|
||||
enabled: true
|
||||
force: true
|
||||
## SSL setting
|
||||
# ssl:
|
||||
# key-store: classpath:rmqcngkeystore.jks
|
||||
# key-store-password: rocketmq
|
||||
# key-store-type: PKCS12
|
||||
# key-alias: rmqcngkey
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: rocketmq-dashboard
|
||||
|
||||
logging:
|
||||
config: classpath:logback.xml
|
||||
|
||||
rocketmq:
|
||||
config:
|
||||
# if this value is empty,use env value rocketmq.config.namesrvAddr NAMESRV_ADDR | now, default localhost:9876
|
||||
# configure multiple namesrv addresses to manage multiple different clusters
|
||||
namesrvAddrs:
|
||||
- 127.0.0.1:9876
|
||||
- 127.0.0.2:9876
|
||||
# if you use rocketmq version < 3.5.8, rocketmq.config.isVIPChannel should be false.default true
|
||||
isVIPChannel:
|
||||
# timeout for mqadminExt, default 5000ms
|
||||
timeoutMillis:
|
||||
# rocketmq-console's data path:dashboard/monitor
|
||||
dataPath: /tmp/rocketmq-console/data
|
||||
# set it false if you don't want use dashboard.default true
|
||||
enableDashBoardCollect: true
|
||||
# set the message track trace topic if you don't want use the default one
|
||||
msgTrackTopicName:
|
||||
ticketKey: ticket
|
||||
# must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
||||
loginRequired: false
|
||||
useTLS: false
|
||||
# set the accessKey and secretKey if you used acl
|
||||
accessKey: # if version > 4.4.0
|
||||
secretKey: # if version > 4.4.0
|
||||
|
||||
threadpool:
|
||||
config:
|
||||
coreSize: 10
|
||||
maxSize: 10
|
||||
keepAliveTime: 3000
|
||||
queueSize: 5000
|
@@ -19,7 +19,7 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder charset="UTF-8">
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %5p %m%n</pattern>
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<MaxHistory>10</MaxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %5p %m%n</pattern>
|
||||
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t - %m%n</pattern>
|
||||
<charset class="java.nio.charset.Charset">UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
@@ -23,13 +23,18 @@
|
||||
|
||||
rolePerms:
|
||||
ordinary:
|
||||
- /rocketmq/nsaddr
|
||||
- /ops/*
|
||||
- /dashboard/**
|
||||
- /rocketmq/*.query
|
||||
- /ops/*.query
|
||||
- /dashboard/*.query
|
||||
- /topic/*.query
|
||||
- /topic/sendTopicMessage.do
|
||||
- /producer/*.query
|
||||
- /message/*
|
||||
- /messageTrace/*
|
||||
- /monitor/*
|
||||
|
||||
- /message/*.query
|
||||
- /messageTrace/*.query
|
||||
- /monitor/*.query
|
||||
- /consumer/*.query
|
||||
- /cluster/*.query
|
||||
- /dlqMessage/*.query
|
||||
- /dlqMessage/exportDlqMessage.do
|
||||
- /dlqMessage/batchResendDlqMessage.do
|
||||
- /acl/*.query
|
||||
|
@@ -113,5 +113,6 @@
|
||||
<script type="text/javascript" src="src/remoteApi/remoteApi.js"></script>
|
||||
<script type="text/javascript" src="vendor/preLoading/main.js"></script>
|
||||
<script type="text/javascript" src="src/login.js"></script>
|
||||
<script type="text/javascript" src="src/acl.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
540
src/main/resources/static/src/acl.js
Normal file
540
src/main/resources/static/src/acl.js
Normal file
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
var module = app;
|
||||
|
||||
module.controller('aclController', ['$scope', 'ngDialog', '$http', 'Notification', '$window', function ($scope, ngDialog, $http, Notification, $window) {
|
||||
$scope.paginationConf = {
|
||||
currentPage: 1,
|
||||
totalItems: 0,
|
||||
itemsPerPage: 10,
|
||||
pagesLength: 15,
|
||||
perPageOptions: [10],
|
||||
rememberPerPage: 'perPageItems',
|
||||
onChange: function () {
|
||||
$scope.showPlainAccessConfigs(this.currentPage, this.totalItems);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.plainAccessConfigs = [];
|
||||
$scope.allPlainAccessConfigs = [];
|
||||
$scope.globalWhiteAddrs = [];
|
||||
$scope.allGlobalWhiteAddrs = [];
|
||||
$scope.userRole = $window.sessionStorage.getItem("userrole");
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
$scope.showSecretKeyType = {};
|
||||
|
||||
$scope.refreshPlainAccessConfigs = function () {
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "acl/config.query",
|
||||
params: {}
|
||||
}).success(function (resp) {
|
||||
|
||||
// globalWhiteAddrs
|
||||
// plainAccessConfigs
|
||||
if (resp.status == 0) {
|
||||
$scope.allPlainAccessConfigs = resp.data.plainAccessConfigs;
|
||||
$scope.allGlobalWhiteAddrs = resp.data.globalWhiteAddrs;
|
||||
$scope.showSecretKeyType = {};
|
||||
$scope.allPlainAccessConfigs.forEach(e => $scope.showSecretKeyType[e.accessKey] = {
|
||||
type: 'password',
|
||||
action: 'SHOW'
|
||||
});
|
||||
$scope.showPlainAccessConfigs(1, $scope.allPlainAccessConfigs.length);
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
$scope.filterStr = "";
|
||||
$scope.$watch('filterStr', function () {
|
||||
$scope.paginationConf.currentPage = 1;
|
||||
$scope.filterList(1);
|
||||
});
|
||||
|
||||
$scope.filterList = function (currentPage) {
|
||||
var lowExceptStr = $scope.filterStr.toLowerCase();
|
||||
var canShowList = [];
|
||||
|
||||
$scope.allPlainAccessConfigs.forEach(function (element) {
|
||||
if (element.accessKey.toLowerCase().indexOf(lowExceptStr) != -1) {
|
||||
canShowList.push(element);
|
||||
}
|
||||
});
|
||||
$scope.paginationConf.totalItems = canShowList.length;
|
||||
var perPage = $scope.paginationConf.itemsPerPage;
|
||||
var from = (currentPage - 1) * perPage;
|
||||
var to = (from + perPage) > canShowList.length ? canShowList.length : from + perPage;
|
||||
$scope.plainAccessConfigs = canShowList.slice(from, to);
|
||||
};
|
||||
|
||||
$scope.showPlainAccessConfigs = function (currentPage, totalItem) {
|
||||
var perPage = $scope.paginationConf.itemsPerPage;
|
||||
var from = (currentPage - 1) * perPage;
|
||||
var to = (from + perPage) > totalItem ? totalItem : from + perPage;
|
||||
$scope.plainAccessConfigs = $scope.allPlainAccessConfigs.slice(from, to);
|
||||
$scope.paginationConf.totalItems = totalItem;
|
||||
$scope.filterList($scope.paginationConf.currentPage)
|
||||
};
|
||||
|
||||
|
||||
// add acl account
|
||||
$scope.openAddDialog = function () {
|
||||
var request = {};
|
||||
request.accessKey = '';
|
||||
request.secretKey = '';
|
||||
request.admin = false;
|
||||
request.defaultTopicPerm = 'DENY';
|
||||
request.defaultGroupPerm = 'SUB';
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addAclAccountDialog',
|
||||
controller: 'addAclAccountDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deleteAclConfig = function (accessKey) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/delete.do",
|
||||
data: {accessKey: accessKey}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.openUpdateDialog = function (request) {
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'updateAclAccountDialog',
|
||||
controller: 'updateAclAccountDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// add acl topic permission
|
||||
$scope.openAddTopicDialog = function (request) {
|
||||
$.extend(request, {pub: true, sub: true, deny: false})
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addAclTopicDialog',
|
||||
controller: 'addAclTopicDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// update acl topic permission
|
||||
$scope.openUpdateTopicDialog = function (request, topic) {
|
||||
var perm = {pub: false, sub: false, deny: false};
|
||||
var topicInfo = topic.split('=');
|
||||
$.each(topicInfo[1].split('|'), function (i, e) {
|
||||
switch (e) {
|
||||
case 'PUB':
|
||||
perm.pub = true;
|
||||
break;
|
||||
case 'SUB':
|
||||
perm.sub = true;
|
||||
break;
|
||||
case 'DENY':
|
||||
perm.deny = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(request, perm, {topic: topicInfo[0]});
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'updateAclTopicDialog',
|
||||
controller: 'updateAclTopicDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// add acl group permission
|
||||
$scope.openAddGroupDialog = function (request) {
|
||||
$.extend(request, {pub: true, sub: true, deny: false})
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addAclGroupDialog',
|
||||
controller: 'addAclGroupDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
// update acl group permission
|
||||
$scope.openUpdateGroupDialog = function (request, group) {
|
||||
var perm = {pub: false, sub: false, deny: false};
|
||||
var groupInfo = group.split('=');
|
||||
$.each(groupInfo[1].split('|'), function (i, e) {
|
||||
switch (e) {
|
||||
case 'PUB':
|
||||
perm.pub = true;
|
||||
break;
|
||||
case 'SUB':
|
||||
perm.sub = true;
|
||||
break;
|
||||
case 'DENY':
|
||||
perm.deny = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(request, perm, {group: groupInfo[0]});
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'updateAclGroupDialog',
|
||||
controller: 'updateAclGroupDialogController',
|
||||
data: request
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deletePermConfig = function (config, name, type) {
|
||||
var request = {config: config};
|
||||
switch (type) {
|
||||
case 'topic':
|
||||
request.topicPerm = name;
|
||||
break;
|
||||
case 'group':
|
||||
request.groupPerm = name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/perm/delete.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.synchronizeData = function (request) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/sync.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.openAddAddrDialog = function () {
|
||||
ngDialog.open({
|
||||
preCloseCallback: function (value) {
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
},
|
||||
template: 'addWhiteListDialog',
|
||||
controller: 'addWhiteListDialogController'
|
||||
});
|
||||
}
|
||||
|
||||
$scope.deleteGlobalWhiteAddr = function (request) {
|
||||
$http({
|
||||
method: "DELETE",
|
||||
url: "acl/white/list/delete.do?request=" + request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.synchronizeWhiteList = function (request) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/white/list/sync.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
$scope.refreshPlainAccessConfigs();
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.switchSecretKeyType = function (accessKey) {
|
||||
if ($scope.showSecretKeyType[accessKey].type == 'password') {
|
||||
$scope.showSecretKeyType[accessKey] = {type: 'text', action: 'HIDE'};
|
||||
} else {
|
||||
$scope.showSecretKeyType[accessKey] = {type: 'password', action: 'SHOW'};
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
||||
module.controller('addAclAccountDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.addRequest = function (requestItem) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/add.do",
|
||||
data: requestItem
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('updateAclAccountDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/update.do",
|
||||
data: requestItem
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('addAclTopicDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
if (!requestItem.topic) {
|
||||
alert("topic is null");
|
||||
return false;
|
||||
}
|
||||
//var request = requestItem.originalData;
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.topicPerms) {
|
||||
originalData.topicPerms = new Array();
|
||||
}
|
||||
var topicPerm = concatPerm(requestItem.topic, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
originalData.topicPerms.push(topicPerm);
|
||||
var request = {topicPerm: topicPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/topic/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('updateAclTopicDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.topicPerms) {
|
||||
originalData.topicPerms = new Array();
|
||||
}
|
||||
var topicPerm = concatPerm(requestItem.topic, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
|
||||
for (var i = 0; i < originalData.topicPerms.length; i++) {
|
||||
if (originalData.topicPerms[i].split('=')[0] == requestItem.topic) {
|
||||
originalData.topicPerms[i] = topicPerm;
|
||||
}
|
||||
}
|
||||
var request = {topicPerm: topicPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/topic/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('addAclGroupDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
//var request = requestItem.originalData;
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.groupPerms) {
|
||||
originalData.groupPerms = new Array();
|
||||
}
|
||||
var groupPerm = concatPerm(requestItem.group, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
originalData.groupPerms.push(groupPerm);
|
||||
var request = {groupPerm: groupPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/group/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('updateAclGroupDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.updateAclAccountRequest = function (requestItem) {
|
||||
if ((requestItem.deny && requestItem.sub) || (requestItem.deny && requestItem.pub)) {
|
||||
alert("Forbid deny && pub/sub.");
|
||||
return false;
|
||||
}
|
||||
var originalData = $.extend(true, {}, requestItem.originalData);
|
||||
if (!originalData.groupPerms) {
|
||||
originalData.groupPerms = new Array();
|
||||
}
|
||||
var groupPerm = concatPerm(requestItem.group, requestItem.pub ? 0x01 : 0, requestItem.sub ? 0x02 : 0, requestItem.deny ? 0x04 : 0);
|
||||
|
||||
for (var i = 0; i < originalData.groupPerms.length; i++) {
|
||||
if (originalData.groupPerms[i].split('=')[0] == requestItem.group) {
|
||||
originalData.groupPerms[i] = groupPerm;
|
||||
}
|
||||
}
|
||||
var request = {groupPerm: groupPerm, config: originalData};
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/group/add.do",
|
||||
data: request
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* pub: 0x01, sub: 0x02, deny: 0x04
|
||||
*/
|
||||
function concatPerm(name, pub, sub, deny) {
|
||||
var perm = '';
|
||||
|
||||
switch (pub | sub | deny) {
|
||||
case 0x01:
|
||||
perm = 'PUB';
|
||||
break;
|
||||
case 0x02:
|
||||
perm = 'SUB';
|
||||
break;
|
||||
case 0x03:
|
||||
perm = 'PUB|SUB';
|
||||
break;
|
||||
case 0x04:
|
||||
perm = 'DENY';
|
||||
break;
|
||||
default:
|
||||
perm = 'DENY';
|
||||
break;
|
||||
}
|
||||
|
||||
return name + '=' + perm;
|
||||
}
|
||||
|
||||
module.controller('addWhiteListDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.addWhiteListRequest = function (requestItem) {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/white/list/add.do",
|
||||
data: requestItem.split(',')
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
||||
module.controller('aclBelongItemDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
$scope.postBelongItemRequest = function (topicRequestItem) {
|
||||
topicRequestItem.type = 1
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "acl/belong/item/add.do",
|
||||
data: topicRequestItem
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "success!", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
);
|
@@ -49,6 +49,15 @@ var app = angular.module('app', [
|
||||
}
|
||||
console.log('initFlag0='+ initFlag + ' loginFlag0==='+loginFlag);
|
||||
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "acl/enable.query"
|
||||
}).success(function (resp) {
|
||||
if (resp && resp.status == 0) {
|
||||
$rootScope.show = resp.data;
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('$locationChangeStart', function (event, next, current) {
|
||||
// redirect to login page if not logged in and trying to access a restricted page
|
||||
init(function(resp){
|
||||
@@ -204,6 +213,9 @@ app.config(['$routeProvider', '$httpProvider','$cookiesProvider','getDictNamePro
|
||||
}).when('/ops', {
|
||||
templateUrl: 'view/pages/ops.html',
|
||||
controller:'opsController'
|
||||
}).when('/acl', {
|
||||
templateUrl: 'view/pages/acl.html',
|
||||
controller: 'aclController'
|
||||
}).when('/404', {
|
||||
templateUrl: 'view/pages/404.html'
|
||||
}).otherwise('/404');
|
||||
|
@@ -82,6 +82,9 @@ module.controller('dlqMessageController', ['$scope', 'ngDialog', '$http', 'Notif
|
||||
if ($scope.messageShowList.length == 0){
|
||||
$("#noMsgTip").removeAttr("style");
|
||||
}
|
||||
for (const message of $scope.messageShowList) {
|
||||
message.checked = false;
|
||||
}
|
||||
console.log($scope.messageShowList);
|
||||
if (resp.data.page.first) {
|
||||
$scope.paginationConf.currentPage = 1;
|
||||
@@ -180,5 +183,115 @@ module.controller('dlqMessageController', ['$scope', 'ngDialog', '$http', 'Notif
|
||||
|
||||
$scope.exportDlqMessage = function (msgId, consumerGroup) {
|
||||
window.location.href = "dlqMessage/exportDlqMessage.do?msgId=" + msgId + "&consumerGroup=" + consumerGroup;
|
||||
};
|
||||
|
||||
$scope.selectedDlqMessage = [];
|
||||
$scope.batchResendDlqMessage = function (consumerGroup) {
|
||||
if ($("#batchResendBtn").hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
for (const message of $scope.messageCheckedList) {
|
||||
const dlqMessage = {};
|
||||
dlqMessage.topic = message.properties.RETRY_TOPIC;
|
||||
dlqMessage.msgId = message.properties.ORIGIN_MESSAGE_ID;
|
||||
dlqMessage.consumerGroup = consumerGroup;
|
||||
$scope.selectedDlqMessage.push(dlqMessage);
|
||||
}
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "dlqMessage/batchResendDlqMessage.do",
|
||||
data: $scope.selectedDlqMessage
|
||||
}).success(function (resp) {
|
||||
$scope.selectedDlqMessage = [];
|
||||
if (resp.status == 0) {
|
||||
ngDialog.open({
|
||||
template: 'operationResultDialog',
|
||||
data: {
|
||||
result: resp.data
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ngDialog.open({
|
||||
template: 'operationResultDialog',
|
||||
data: {
|
||||
result: resp.errMsg
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.batchExportDlqMessage = function (consumerGroup) {
|
||||
if ($("#batchExportBtn").hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
for (const message of $scope.messageCheckedList) {
|
||||
const dlqMessage = {};
|
||||
dlqMessage.msgId = message.msgId;
|
||||
dlqMessage.consumerGroup = consumerGroup;
|
||||
$scope.selectedDlqMessage.push(dlqMessage);
|
||||
}
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "dlqMessage/batchExportDlqMessage.do",
|
||||
data: $scope.selectedDlqMessage,
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
},
|
||||
responseType: "arraybuffer"
|
||||
}).success(function (resp) {
|
||||
$scope.selectedDlqMessage = [];
|
||||
const blob = new Blob([resp], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.download = 'dlqs.xlsx';
|
||||
a.href = objectUrl;
|
||||
a.click();
|
||||
document.body.removeChild(a)
|
||||
});
|
||||
};
|
||||
|
||||
$scope.checkedAll = false;
|
||||
$scope.messageCheckedList = [];
|
||||
$scope.selectAll = function () {
|
||||
$scope.messageCheckedList = [];
|
||||
if ($scope.checkedAll == true) {
|
||||
angular.forEach($scope.messageShowList, function (item, index) {
|
||||
item.checked = true;
|
||||
$scope.messageCheckedList.push(item);
|
||||
});
|
||||
} else {
|
||||
angular.forEach($scope.messageShowList, function (item, index) {
|
||||
item.checked = false;
|
||||
});
|
||||
}
|
||||
checkBtn($scope.messageCheckedList)
|
||||
console.log($scope.messageCheckedList)
|
||||
}
|
||||
|
||||
$scope.selectItem = function () {
|
||||
var flag = true;
|
||||
$scope.messageCheckedList = [];
|
||||
angular.forEach($scope.messageShowList, function (item, index) {
|
||||
if (item.checked) {
|
||||
$scope.messageCheckedList.push(item);
|
||||
} else {
|
||||
flag = false;
|
||||
}
|
||||
})
|
||||
$scope.checkedAll = flag;
|
||||
checkBtn($scope.messageCheckedList)
|
||||
console.log($scope.messageCheckedList);
|
||||
}
|
||||
|
||||
function checkBtn(messageCheckList) {
|
||||
if (messageCheckList.length == 0) {
|
||||
$("#batchResendBtn").addClass("disabled");
|
||||
$("#batchExportBtn").addClass("disabled");
|
||||
} else {
|
||||
$("#batchResendBtn").removeClass("disabled");
|
||||
$("#batchExportBtn").removeClass("disabled");
|
||||
}
|
||||
}
|
||||
}]);
|
@@ -21,8 +21,8 @@ var en = {
|
||||
"NO": "NO.",
|
||||
"ADDRESS": "Address",
|
||||
"VERSION": "Version",
|
||||
"PRO_MSG_TPS": "Produce Massage TPS",
|
||||
"CUS_MSG_TPS": "Consumer Massage TPS",
|
||||
"PRO_MSG_TPS": "Produce Message TPS",
|
||||
"CUS_MSG_TPS": "Consumer Message TPS",
|
||||
"YESTERDAY_PRO_COUNT": "Yesterday Produce Count",
|
||||
"YESTERDAY_CUS_COUNT": "Yesterday Consume Count",
|
||||
"TODAY_PRO_COUNT": "Today Produce Count",
|
||||
@@ -111,5 +111,17 @@ var en = {
|
||||
"TRACE_TOPIC":"TraceTopic",
|
||||
"SELECT_TRACE_TOPIC":"selectTraceTopic",
|
||||
"EXPORT": "export",
|
||||
"NO_MATCH_RESULT": "no match result"
|
||||
}
|
||||
"NO_MATCH_RESULT": "no match result",
|
||||
"BATCH_RESEND": "batchReSend",
|
||||
"BATCH_EXPORT": "batchExport",
|
||||
"WHITE_LIST":"White List",
|
||||
"ACCOUNT_INFO":"Account Info",
|
||||
"IS_ADMIN":"Is Admin",
|
||||
"DEFAULT_TOPIC_PERM":"Default Topic Permission",
|
||||
"DEFAULT_GROUP_PERM":"Default Group Permission",
|
||||
"TOPIC_PERM":"Topic Permission",
|
||||
"GROUP_PERM":"Group Permission",
|
||||
"SYNCHRONIZE":"Synchronize Data",
|
||||
"SHOW":"Show",
|
||||
"HIDE":"Hide"
|
||||
}
|
||||
|
@@ -112,5 +112,17 @@ var zh = {
|
||||
"TRACE_TOPIC":"消息轨迹主题",
|
||||
"SELECT_TRACE_TOPIC":"选择消息轨迹主题",
|
||||
"EXPORT": "导出",
|
||||
"NO_MATCH_RESULT": "没有查到符合条件的结果"
|
||||
"NO_MATCH_RESULT": "没有查到符合条件的结果",
|
||||
"BATCH_RESEND": "批量重发",
|
||||
"BATCH_EXPORT": "批量导出",
|
||||
"WHITE_LIST":"白名单",
|
||||
"ACCOUNT_INFO":"账户信息",
|
||||
"IS_ADMIN":"是否管理员",
|
||||
"DEFAULT_TOPIC_PERM":"topic默认权限",
|
||||
"DEFAULT_GROUP_PERM":"消费组默认权限",
|
||||
"TOPIC_PERM":"topic权限",
|
||||
"GROUP_PERM":"消费组权限",
|
||||
"SYNCHRONIZE":"同步",
|
||||
"SHOW":"显示",
|
||||
"HIDE":"隐藏"
|
||||
}
|
@@ -58,6 +58,7 @@ module.controller('messageController', ['$scope', 'ngDialog', '$http', 'Notifica
|
||||
};
|
||||
|
||||
$scope.queryMessagePageByTopic = function () {
|
||||
$("#noMsgTip").css("display", "none");
|
||||
if ($scope.timepickerEnd < $scope.timepickerBegin) {
|
||||
Notification.error({message: "endTime is later than beginTime!", delay: 2000});
|
||||
return
|
||||
@@ -80,6 +81,9 @@ module.controller('messageController', ['$scope', 'ngDialog', '$http', 'Notifica
|
||||
if (resp.status === 0) {
|
||||
console.log(resp);
|
||||
$scope.messageShowList = resp.data.page.content;
|
||||
if ($scope.messageShowList.length == 0){
|
||||
$("#noMsgTip").removeAttr("style");
|
||||
}
|
||||
if (resp.data.page.first) {
|
||||
$scope.paginationConf.currentPage = 1;
|
||||
}
|
||||
@@ -206,7 +210,8 @@ module.controller('messageController', ['$scope', 'ngDialog', '$http', 'Notifica
|
||||
}]);
|
||||
|
||||
module.controller('messageDetailViewDialogController', ['$scope', 'ngDialog', '$http', 'Notification', function ($scope, ngDialog, $http, Notification) {
|
||||
|
||||
$scope.messageTrackList = $scope.ngDialogData.messageTrackList;
|
||||
$scope.messageTrackShowList = $scope.ngDialogData.messageTrackList;
|
||||
$scope.resendMessage = function (messageView, consumerGroup) {
|
||||
var topic = messageView.topic;
|
||||
var msgId = messageView.msgId;
|
||||
@@ -258,5 +263,18 @@ module.controller('messageDetailViewDialogController', ['$scope', 'ngDialog', '$
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.filterConsumerGroup = "";
|
||||
$scope.$watch('filterConsumerGroup', function () {
|
||||
const lowExceptStr = $scope.filterConsumerGroup.toLowerCase();
|
||||
const canShowList = [];
|
||||
|
||||
$scope.messageTrackList.forEach(function (element) {
|
||||
if (element.consumerGroup.toLowerCase().indexOf(lowExceptStr) != -1) {
|
||||
canShowList.push(element);
|
||||
}
|
||||
});
|
||||
$scope.messageTrackShowList = canShowList;
|
||||
});
|
||||
}]
|
||||
);
|
@@ -22,6 +22,7 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
$scope.userRole = $window.sessionStorage.getItem("userrole");
|
||||
$scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false);
|
||||
$scope.inputReadonly = !$scope.writeOperationEnabled;
|
||||
$scope.newNamesrvAddr = "";
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "ops/homePage.query"
|
||||
@@ -30,6 +31,7 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
$scope.namesvrAddrList = resp.data.namesvrAddrList;
|
||||
$scope.useVIPChannel = resp.data.useVIPChannel;
|
||||
$scope.useTLS = resp.data.useTLS;
|
||||
$scope.selectedNamesrv = resp.data.currentNamesrv;
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
@@ -43,7 +45,7 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "ops/updateNameSvrAddr.do",
|
||||
params: {nameSvrAddrList: $scope.namesvrAddrList.join(";")}
|
||||
params: {nameSvrAddrList: $scope.selectedNamesrv}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: "SUCCESS", delay: 2000});
|
||||
@@ -52,6 +54,26 @@ app.controller('opsController', ['$scope', '$location', '$http', 'Notification',
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addNameSvrAddr = function () {
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "ops/addNameSvrAddr.do",
|
||||
params: {newNamesrvAddr: $scope.newNamesrvAddr}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
if ($scope.namesvrAddrList.indexOf($scope.newNamesrvAddr) == -1) {
|
||||
$scope.namesvrAddrList.push($scope.newNamesrvAddr);
|
||||
}
|
||||
$("#namesrvAddr").val("");
|
||||
$scope.newNamesrvAddr = "";
|
||||
Notification.info({message: "SUCCESS", delay: 2000});
|
||||
} else {
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updateIsVIPChannel = function () {
|
||||
$http({
|
||||
method: "POST",
|
||||
|
@@ -54,7 +54,7 @@ app.service('remoteApi', ['$http','tools', function ($http,tools) {
|
||||
}
|
||||
|
||||
var queryTopicCurrentData = function(callback){
|
||||
var url = 'dashboard/topicCurrent';
|
||||
var url = 'dashboard/topicCurrent.query';
|
||||
var setting = {
|
||||
type: "GET",
|
||||
timeout:15000,//data is too large,so master set time out is long enough
|
||||
|
@@ -289,3 +289,15 @@
|
||||
.table.text-middle>tbody>tr>td,.table.text-middle>tbody>tr>th{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.perm-table{width: 100%;}
|
||||
.perm-table .perm-tg{width: 70%;}
|
||||
.perm-table .center{border-left: 1px solid #e4dddd; border-right: 1px solid #e4dddd;}
|
||||
|
||||
.input-none {
|
||||
border: 0;
|
||||
outline: none;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
cursor: text !important;
|
||||
width: 60%;
|
||||
}
|
@@ -36,6 +36,7 @@
|
||||
<li ng-class="path =='message' ? 'active':''"><a ng-href="#/message">{{'MESSAGE' | translate}}</a></li>
|
||||
<li ng-class="path =='dlqMessage' ? 'active':''"><a ng-href="#/dlqMessage">{{'DLQ_MESSAGE' | translate}}</a></li>
|
||||
<li ng-class="path =='messageTrace' ? 'active':''"><a ng-href="#/messageTrace">{{'MESSAGETRACE' | translate}}</a></li>
|
||||
<li ng-show="{{ show }}" ng-class="path =='acl' ? 'active':''"><a ng-href="#/acl">Acl</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
|
483
src/main/resources/static/view/pages/acl.html
Normal file
483
src/main/resources/static/view/pages/acl.html
Normal file
@@ -0,0 +1,483 @@
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<div class="container-fluid" id="deployHistoryList">
|
||||
<div class="modal-body">
|
||||
<div ng-cloak="" class="tabsdemoDynamicHeight">
|
||||
<md-content>
|
||||
<md-tabs md-dynamic-height="" md-border-bottom="">
|
||||
<md-tab label="Account Info">
|
||||
<md-content class="md-padding" style="min-height:600px">
|
||||
<form class="form-inline pull-left col-sm-12">
|
||||
<div class="form-group">
|
||||
<label>Access Key:</label>
|
||||
<input class="form-control" style="width: 450px" type="text" ng-model="filterStr"/>
|
||||
</div>
|
||||
|
||||
<button ng-show="writeOperationEnabled" class="btn btn-raised btn-sm btn-primary"
|
||||
type="button"
|
||||
ng-click="openAddDialog()">{{'ADD' |
|
||||
translate}}
|
||||
</button>
|
||||
</form>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th class="text-center">Access Key</th>
|
||||
<th ng-show="writeOperationEnabled" class="text-center">Secret Key</th>
|
||||
<th class="text-center">{{'IS_ADMIN' | translate}}</th>
|
||||
<th class="text-center">{{'DEFAULT_TOPIC_PERM' | translate}}</th>
|
||||
<th class="text-center">{{'DEFAULT_GROUP_PERM' | translate}}</th>
|
||||
<th class="text-center">{{'TOPIC_PERM' | translate}}</th>
|
||||
<th class="text-center">{{'GROUP_PERM' | translate}}</th>
|
||||
<th ng-show="writeOperationEnabled" class="text-center">
|
||||
{{'OPERATION' | translate}}
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="item in plainAccessConfigs">
|
||||
<td class="text-center">{{item.accessKey}}</td>
|
||||
<td ng-show="writeOperationEnabled" class="text-center">
|
||||
<input type="{{showSecretKeyType[item.accessKey].type}}"
|
||||
value="{{item.secretKey}}" class="input-none" ng-disabled="true"/>
|
||||
<a href="javascript:;"
|
||||
ng-click="switchSecretKeyType(item.accessKey)">{{showSecretKeyType[item.accessKey].action | translate}}</a>
|
||||
</td>
|
||||
<td class="text-center">{{item.admin}}</td>
|
||||
<td class="text-center">{{item.defaultTopicPerm}}</td>
|
||||
<td class="text-center">{{item.defaultGroupPerm}}</td>
|
||||
<td class="text-center">
|
||||
<table ng-repeat="topic in item.topicPerms" class="perm-table">
|
||||
<tr>
|
||||
<td class="perm-tg">{{topic}}</td>
|
||||
<td ng-show="writeOperationEnabled" class="center"><a
|
||||
href="javascript:;"
|
||||
ng-click="openUpdateTopicDialog(item, topic)">
|
||||
{{'UPDATE' | translate}}</a></td>
|
||||
<td ng-show="writeOperationEnabled"><a href="javascript:;"
|
||||
ng-confirm-click="Are you sure to delete {{topic}}?"
|
||||
confirmed-click="deletePermConfig(item, topic, 'topic')">{{'DELETE' | translate}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<table ng-repeat="group in item.groupPerms" class="perm-table">
|
||||
<tr>
|
||||
<td class="perm-tg">{{group}}</td>
|
||||
<td ng-show="writeOperationEnabled" class="center"><a
|
||||
href="javascript:;"
|
||||
ng-click="openUpdateGroupDialog(item, group)">
|
||||
{{'UPDATE' | translate}}</a></td>
|
||||
<td ng-show="writeOperationEnabled"><a href="javascript:;"
|
||||
ng-confirm-click="Are you sure to delete {{group}}?"
|
||||
confirmed-click="deletePermConfig(item, group, 'group')">{{'DELETE' | translate}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td ng-show="writeOperationEnabled" class="text-center">
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="openAddTopicDialog(item)">
|
||||
{{'ADD' | translate}}topic
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="openAddGroupDialog(item)">
|
||||
{{'ADD' | translate}}group
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="openUpdateDialog(item)">
|
||||
{{'UPDATE' | translate}}
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-danger" type="button"
|
||||
ng-confirm-click="Are you sure to delete {{item.accessKey}}?"
|
||||
confirmed-click="deleteAclConfig(item.accessKey)">{{'DELETE' | translate}}
|
||||
</button>
|
||||
<button class="btn btn-raised btn-sm btn-danger" type="button"
|
||||
ng-click="synchronizeData(item)">{{'SYNCHRONIZE' | translate}}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<tm-pagination conf="paginationConf"></tm-pagination>
|
||||
</md-content>
|
||||
</md-tab>
|
||||
<md-tab label="Global White List">
|
||||
<md-content class="md-padding" style="min-height:600px">
|
||||
<form class="form-inline pull-left col-sm-12">
|
||||
<button ng-show="writeOperationEnabled" class="btn btn-raised btn-sm btn-primary"
|
||||
type="button"
|
||||
ng-click="openAddAddrDialog()">{{'ADD' |
|
||||
translate}}
|
||||
</button>
|
||||
<button ng-show="writeOperationEnabled" class="btn btn-raised btn-sm btn-danger"
|
||||
type="button"
|
||||
ng-confirm-click="Are you sure to synchronize white list to all broker int the cluster?"
|
||||
confirmed-click="synchronizeWhiteList(allGlobalWhiteAddrs)">
|
||||
{{'SYNCHRONIZE' | translate}}
|
||||
</button>
|
||||
</form>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th class="text-center">{{'WHITE_LIST' | translate}}</th>
|
||||
<th ng-show="writeOperationEnabled" class="text-center">
|
||||
{{'OPERATION' | translate}}
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-repeat="item in allGlobalWhiteAddrs">
|
||||
<td class="text-center">{{item}}
|
||||
</td>
|
||||
<td ng-show="writeOperationEnabled" class="text-center">
|
||||
<button class="btn btn-raised btn-sm btn-danger" type="button"
|
||||
ng-confirm-click="Are you sure to delete {{item}}?"
|
||||
confirmed-click="deleteGlobalWhiteAddr(item)">{{'DELETE' | translate}}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</md-content>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
</md-content>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="addAclAccountDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addAppForm" name="addAppForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'IS_ADMIN' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-switch class="md-primary" md-no-ink aria-label="Switch No Ink"
|
||||
ng-model="ngDialogData.admin">
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultTopicPerm" type="text" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultGroupPerm" type="text" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="addRequest({'accessKey':ngDialogData.accessKey, 'secretKey': ngDialogData.secretKey, 'admin': ngDialogData.admin, 'defaultTopicPerm': ngDialogData.defaultTopicPerm, 'defaultGroupPerm': ngDialogData.defaultGroupPerm})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="updateAclAccountDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'UPDATE' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="updateAccountForm" name="updateAccountForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'IS_ADMIN' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-switch class="md-primary" md-no-ink aria-label="Switch No Ink"
|
||||
ng-model="ngDialogData.admin">
|
||||
</md-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultTopicPerm" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'DEFAULT_GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.defaultGroupPerm" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'accessKey':ngDialogData.accessKey, 'secretKey': ngDialogData.secretKey, 'admin': ngDialogData.admin, 'defaultTopicPerm': ngDialogData.defaultTopicPerm, 'defaultGroupPerm': ngDialogData.defaultGroupPerm})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addAclTopicDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}{{'TOPIC_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addAclTopicForm" name="addAclTopicForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="topic" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'topic': topic , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="updateAclTopicDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'UPDATE' | translate }}{{'TOPIC_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="updateAclTopicForm" name="updateAclTopicForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.topic" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'TOPIC_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'topic': ngDialogData.topic , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addAclGroupDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}{{'GROUP_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addAclGroupForm" name="addAclGroupForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'CONSUMER' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="group" type="text" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'group': group , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="updateAclGroupDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'UPDATE' | translate }}{{'GROUP_PERM' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="updateAclGroupForm" name="updateAclGroupForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Access Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.accessKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">Secret Key:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.secretKey" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'CONSUMER' | translate}}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ngDialogData.group" type="text" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'GROUP_PERM' | translate}}:</label>
|
||||
<div class="col-sm-8">
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.pub">PUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.sub">SUB</md-checkbox>
|
||||
<md-checkbox class="md-primary" ng-model="ngDialogData.deny">DENY</md-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="updateAclAccountRequest({'originalData':ngDialogData,'group': ngDialogData.group , 'pub': ngDialogData.pub, 'sub': ngDialogData.sub, 'deny': ngDialogData.deny})">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="addWhiteListDialog">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{'ADD' | translate }}{{'WHITE_LIST' | translate }}</h4>
|
||||
</div>
|
||||
<div class="modal-body ">
|
||||
<form id="addWhiteListForm" name="addWhiteListForm" class="form-horizontal" novalidate>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">{{'WHITE_LIST' | translate }}:</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" ng-model="ip" type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<div class="ngdialog-buttons">
|
||||
<button type="button" class="ngdialog-button ngdialog-button-primary"
|
||||
ng-click="addWhiteListRequest(ip)">
|
||||
{{ 'COMMIT' | translate }}
|
||||
</button>
|
||||
<button type="button" class="ngdialog-button ngdialog-button-secondary"
|
||||
ng-click="closeThisDialog('Cancel')">{{ 'CLOSE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
@@ -64,9 +64,22 @@
|
||||
ng-click="queryDlqMessageByConsumerGroup()">
|
||||
<span class="glyphicon glyphicon-search"></span> {{ 'SEARCH' | translate}}
|
||||
</button>
|
||||
<button type="button" id="batchResendBtn"
|
||||
class="btn btn-raised btn-sm btn-primary disabled"
|
||||
data-toggle="modal"
|
||||
ng-click="batchResendDlqMessage(selectedConsumerGroup)">
|
||||
<span class="glyphicon glyphicon-send"></span> {{ 'BATCH_RESEND' | translate}}
|
||||
</button>
|
||||
<button type="button" id="batchExportBtn"
|
||||
class="btn btn-raised btn-sm btn-primary disabled"
|
||||
data-toggle="modal"
|
||||
ng-click="batchExportDlqMessage(selectedConsumerGroup)">
|
||||
<span class="glyphicon glyphicon-export"></span> {{ 'BATCH_EXPORT' | translate}}
|
||||
</button>
|
||||
</form>
|
||||
<table class="table table-bordered text-middle">
|
||||
<tr>
|
||||
<th class="text-center"><input type="checkbox" ng-model='checkedAll' ng-change="selectAll()"/></th>
|
||||
<th class="text-center">Message ID</th>
|
||||
<th class="text-center">Tag</th>
|
||||
<th class="text-center">Key</th>
|
||||
@@ -77,6 +90,9 @@
|
||||
<td colspan="6" style="text-align: center">{{'NO_MATCH_RESULT' | translate}}</td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in messageShowList">
|
||||
<td class="text-center">
|
||||
<input type="checkbox" ng-model='item.checked' ng-change="selectItem()"/>
|
||||
</td>
|
||||
<td class="text-center">{{item.msgId}}</td>
|
||||
<td class="text-center">{{item.properties.TAGS}}</td>
|
||||
<td class="text-center">{{item.properties.KEYS}}</td>
|
||||
@@ -192,7 +208,7 @@
|
||||
<label class="control-label col-sm-2">Properties:</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control"
|
||||
style="min-height:60px; resize: none"
|
||||
style="min-height:100px; resize: none"
|
||||
readonly>{{ngDialogData.messageView.properties}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -73,6 +73,9 @@
|
||||
<th class="text-center">StoreTime</th>
|
||||
<th class="text-center">Operation</th>
|
||||
</tr>
|
||||
<tr style="display: none" id="noMsgTip">
|
||||
<td colspan="5" style="text-align: center">{{'NO_MATCH_RESULT' | translate}}</td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in messageShowList">
|
||||
<td class="text-center">{{item.msgId}}</td>
|
||||
<td class="text-center">{{item.properties.TAGS}}</td>
|
||||
@@ -227,7 +230,13 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<p>messageTrackList:</p>
|
||||
<div style="font-weight:700; color:#000">messageTrackList:</div>
|
||||
<form class="form-inline">
|
||||
<div class="form-group">
|
||||
<label>consumerGroup:</label>
|
||||
<input type="text" class="form-control" ng-model="filterConsumerGroup">
|
||||
</div>
|
||||
</form>
|
||||
<table class="table-bordered table text-middle">
|
||||
<tr>
|
||||
<th class="text-center">consumerGroup</th>
|
||||
@@ -235,7 +244,7 @@
|
||||
<!--<th class="text-center">exceptionDesc</th>-->
|
||||
<th class="text-center">Operation</th>
|
||||
</tr>
|
||||
<tr ng-repeat="item in ngDialogData.messageTrackList">
|
||||
<tr ng-repeat="item in messageTrackShowList">
|
||||
<td class="text-center">{{item.consumerGroup}}</td>
|
||||
<td class="text-center">{{item.trackType}}</td>
|
||||
<td class="text-center">
|
||||
|
@@ -17,15 +17,26 @@
|
||||
<div class="container-fluid" id="deployHistoryList">
|
||||
<div class="page-content">
|
||||
<h2 class="md-title">NameServerAddressList</h2>
|
||||
<div class="pull-left">
|
||||
<md-chips ng-model="namesvrAddrList" md-on-add="eleChange(namesvrAddrList)"
|
||||
md-on-remove="eleChange(namesvrAddrList)" readonly="inputReadonly" md-removable="ctrl.removable"></md-chips>
|
||||
<div class="pull-left" style="min-width: 400px; max-width: 500px; padding: 10px 10px 10px 0">
|
||||
<select ng-model="selectedNamesrv" chosen
|
||||
ng-options="x for x in namesvrAddrList"
|
||||
ng-change="updateNameSvrAddr()"
|
||||
required></select>
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button" ng-show="{{writeOperationEnabled}}"
|
||||
ng-click="updateNameSvrAddr()">{{'UPDATE' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
<form class="form-inline pull-left" style="margin-left: 20px" ng-show="{{writeOperationEnabled}}">
|
||||
<div class="form-group" style="margin: 0">
|
||||
<label for="namesrvAddr">NamesrvAddr:</label>
|
||||
<input id="namesrvAddr" class="form-control" style="width: 300px; margin: 0 10px 0 10px" type="text" ng-model="newNamesrvAddr" required/>
|
||||
<button class="btn btn-raised btn-sm btn-primary" type="button"
|
||||
ng-click="addNameSvrAddr()"> {{ 'ADD' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<br/>
|
||||
<br/>
|
||||
<h2 class="md-title">IsUseVIPChannel</h2>
|
||||
|
@@ -418,8 +418,10 @@ public class MQAdminExtImplTest {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
{
|
||||
doNothing().when(defaultMQAdminExt).deleteSubscriptionGroup(anyString(), anyString());
|
||||
doNothing().when(defaultMQAdminExt).deleteSubscriptionGroup(anyString(), anyString(), anyBoolean());
|
||||
}
|
||||
mqAdminExtImpl.deleteSubscriptionGroup(brokerAddr, "group_test");
|
||||
mqAdminExtImpl.deleteSubscriptionGroup(brokerAddr, "group_test", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -758,16 +760,6 @@ public class MQAdminExtImplTest {
|
||||
Assert.assertNotNull(wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllTopicGroup() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
{
|
||||
when(defaultMQAdminExt.getAllTopicGroup(anyString(), anyLong())).thenReturn(new TopicConfigSerializeWrapper());
|
||||
}
|
||||
TopicConfigSerializeWrapper wrapper = mqAdminExtImpl.getAllTopicGroup(brokerAddr, 5000L);
|
||||
Assert.assertNotNull(wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConsumeOffset() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
@@ -801,4 +793,42 @@ public class MQAdminExtImplTest {
|
||||
Assert.assertFalse(mqAdminExtImpl.resumeCheckHalfMessage("topic_test", "7F000001ACC018B4AAC2116AF6500000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddWritePermOfBroker() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
{
|
||||
when(defaultMQAdminExt.addWritePermOfBroker(anyString(), anyString())).thenReturn(6);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.addWritePermOfBroker("127.0.0.1:9876", "broker-a"), 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserSubscriptionGroup() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
SubscriptionGroupWrapper wrapper = new SubscriptionGroupWrapper();
|
||||
{
|
||||
when(defaultMQAdminExt.getUserSubscriptionGroup(anyString(), anyLong())).thenReturn(wrapper);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.getUserSubscriptionGroup("127.0.0.1:10911", 3000), wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllTopicConfig() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
TopicConfigSerializeWrapper wrapper = new TopicConfigSerializeWrapper();
|
||||
{
|
||||
when(defaultMQAdminExt.getAllTopicConfig(anyString(), anyLong())).thenReturn(wrapper);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.getAllTopicConfig("127.0.0.1:10911", 3000), wrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserTopicConfig() throws Exception {
|
||||
assertNotNull(mqAdminExtImpl);
|
||||
TopicConfigSerializeWrapper wrapper = new TopicConfigSerializeWrapper();
|
||||
{
|
||||
when(defaultMQAdminExt.getUserTopicConfig(anyString(), anyBoolean(), anyLong())).thenReturn(wrapper);
|
||||
}
|
||||
Assert.assertEquals(mqAdminExtImpl.getUserTopicConfig("127.0.0.1:10911", true, 3000), wrapper);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CollectExecutorConfigTest {
|
||||
|
||||
private final static int COUNT = 100;
|
||||
|
||||
@Test
|
||||
public void testCollectExecutor() throws Exception {
|
||||
AtomicInteger num = new AtomicInteger(0);
|
||||
CollectExecutorConfig config = new CollectExecutorConfig();
|
||||
config.setCoreSize(10);
|
||||
config.setMaxSize(10);
|
||||
config.setQueueSize(500);
|
||||
config.setKeepAliveTime(3000);
|
||||
ExecutorService collectExecutor = config.collectExecutor(config);
|
||||
Assert.assertNotNull(collectExecutor);
|
||||
CountDownLatch countDownLatch = new CountDownLatch(COUNT);
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
collectExecutor.submit(() -> {
|
||||
num.getAndIncrement();
|
||||
countDownLatch.countDown();
|
||||
});
|
||||
}
|
||||
countDownLatch.await();
|
||||
System.out.println(collectExecutor.isTerminated());
|
||||
Assert.assertEquals(COUNT, num.get());
|
||||
}
|
||||
}
|
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.config;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.File;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@@ -39,6 +40,7 @@ public class RMQConfigureTest {
|
||||
rmqConfigure.setLoginRequired(true);
|
||||
rmqConfigure.setNamesrvAddr("127.0.0.1:9876");
|
||||
rmqConfigure.setTimeoutMillis(3000L);
|
||||
rmqConfigure.setNamesrvAddrs(Lists.asList("127.0.0.1:9876", new String[] {"127.0.0.2:9876"}));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -54,6 +56,7 @@ public class RMQConfigureTest {
|
||||
Assert.assertTrue(rmqConfigure.isEnableDashBoardCollect());
|
||||
Assert.assertTrue(rmqConfigure.isLoginRequired());
|
||||
Assert.assertEquals(rmqConfigure.getNamesrvAddr(), "127.0.0.1:9876");
|
||||
Assert.assertEquals(rmqConfigure.getNamesrvAddrs().size(), 2);
|
||||
Assert.assertEquals(rmqConfigure.getTimeoutMillis().longValue(), 3000L);
|
||||
ErrorPageRegistrar registrar = rmqConfigure.errorPageRegistrar();
|
||||
registrar.registerErrorPages(new ErrorPageRegistry() {
|
||||
|
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* 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.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.PlainAccessConfig;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.AclRequest;
|
||||
import org.apache.rocketmq.dashboard.service.impl.AclServiceImpl;
|
||||
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Spy;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
public class AclControllerTest extends BaseControllerTest {
|
||||
|
||||
@InjectMocks
|
||||
private AclController aclController;
|
||||
|
||||
@Spy
|
||||
private AclServiceImpl aclService;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
AclConfig aclConfig = MockObjectUtil.createAclConfig();
|
||||
when(mqAdminExt.examineBrokerClusterAclConfig(anyString())).thenReturn(aclConfig);
|
||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||
doNothing().when(mqAdminExt).createAndUpdatePlainAccessConfig(anyString(), any(PlainAccessConfig.class));
|
||||
doNothing().when(mqAdminExt).deletePlainAccessConfig(anyString(), anyString());
|
||||
doNothing().when(mqAdminExt).updateGlobalWhiteAddrConfig(anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEnableAcl() throws Exception {
|
||||
final String url = "/acl/enable.query";
|
||||
// 1. disable acl.
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").value(false));
|
||||
|
||||
// 2.enable acl.
|
||||
super.mockRmqConfigure();
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAclConfig() throws Exception {
|
||||
final String url = "/acl/config.query";
|
||||
|
||||
// 1. broker addr table is not empty.
|
||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs[0].secretKey").isNotEmpty());
|
||||
|
||||
// 2. broker addr table is empty.
|
||||
clusterInfo.getBrokerAddrTable().clear();
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isEmpty());
|
||||
|
||||
// 3. login required and user info is null.
|
||||
when(configure.isLoginRequired()).thenReturn(true);
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(MockObjectUtil.createClusterInfo());
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
.andExpect(jsonPath("$.data.globalWhiteAddrs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs").isNotEmpty())
|
||||
.andExpect(jsonPath("$.data.plainAccessConfigs[0].secretKey").isEmpty());
|
||||
// 4. login required, but user is not admin. emmmm, Mockito may can not mock static method.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAclConfig() throws Exception {
|
||||
final String url = "/acl/add.do";
|
||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
|
||||
// 1. access key is null.
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. secret key is null.
|
||||
accessConfig.setAccessKey("test-access-key");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
ClusterInfo clusterInfo = MockObjectUtil.createClusterInfo();
|
||||
when(mqAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
|
||||
|
||||
// 3. add if the access key not exist.
|
||||
accessConfig.setSecretKey("12345678");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 4. add failed if the access key is existed.
|
||||
accessConfig.setAccessKey("rocketmq2");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 5. add failed if there is no alive broker.
|
||||
clusterInfo.getBrokerAddrTable().clear();
|
||||
accessConfig.setAccessKey("test-access-key");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAclConfig() throws Exception {
|
||||
final String url = "/acl/delete.do";
|
||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
|
||||
// 1. access key is null.
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. access key is not null.
|
||||
accessConfig.setAccessKey("rocketmq");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAclConfig() throws Exception {
|
||||
final String url = "/acl/update.do";
|
||||
PlainAccessConfig accessConfig = new PlainAccessConfig();
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
|
||||
// 1. secret key is null.
|
||||
accessConfig.setAccessKey("rocketmq");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. update.
|
||||
accessConfig.setSecretKey("abcdefghjkl");
|
||||
requestBuilder.content(JSON.toJSONString(accessConfig));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAclTopicConfig() throws Exception {
|
||||
final String url = "/acl/topic/add.do";
|
||||
AclRequest request = new AclRequest();
|
||||
request.setConfig(createDefaultPlainAccessConfig());
|
||||
|
||||
// 1. if not exist.
|
||||
request.setTopicPerm("test_topic=PUB");
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 2. if exist.
|
||||
request.setTopicPerm("topicA=PUB");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 3. if access key not exist.
|
||||
request.getConfig().setAccessKey("test_access_key123");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAclGroupConfig() throws Exception {
|
||||
final String url = "/acl/group/add.do";
|
||||
AclRequest request = new AclRequest();
|
||||
request.setConfig(createDefaultPlainAccessConfig());
|
||||
|
||||
// 1. if not exist.
|
||||
request.setGroupPerm("test_consumer=PUB|SUB");
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 2. if exist.
|
||||
request.setGroupPerm("groupA=PUB|SUB");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 3. if access key not exist.
|
||||
request.getConfig().setAccessKey("test_access_key123");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletePermConfig() throws Exception {
|
||||
final String url = "/acl/perm/delete.do";
|
||||
AclRequest request = new AclRequest();
|
||||
request.setConfig(createDefaultPlainAccessConfig());
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// if access key not exist.
|
||||
request.getConfig().setAccessKey("test_access_key123");
|
||||
requestBuilder.content(JSON.toJSONString(request));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyncConfig() throws Exception {
|
||||
final String url = "/acl/sync.do";
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(createDefaultPlainAccessConfig()));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddWhiteList() throws Exception {
|
||||
final String url = "/acl/white/list/add.do";
|
||||
List<String> whiteList = Lists.newArrayList("192.168.0.1");
|
||||
|
||||
// 1. if global white list is not null.
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
|
||||
// 2. if global white list is null.
|
||||
AclConfig aclConfig = MockObjectUtil.createAclConfig();
|
||||
aclConfig.setGlobalWhiteAddrs(null);
|
||||
when(mqAdminExt.examineBrokerClusterAclConfig(anyString())).thenReturn(aclConfig);
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteWhiteAddr() throws Exception {
|
||||
final String url = "/acl/white/list/delete.do";
|
||||
requestBuilder = MockMvcRequestBuilders.delete(url);
|
||||
requestBuilder.param("request", "localhost");
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronizeWhiteList() throws Exception {
|
||||
final String url = "/acl/white/list/sync.do";
|
||||
List<String> whiteList = Lists.newArrayList();
|
||||
|
||||
// 1. if white list for syncing is empty.
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(-1))
|
||||
.andExpect(jsonPath("$.errMsg").exists());
|
||||
|
||||
// 2. if white list for syncing is not empty.
|
||||
whiteList.add("localhost");
|
||||
requestBuilder.content(JSON.toJSONString(whiteList));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value(0));
|
||||
}
|
||||
|
||||
@Override protected Object getTestController() {
|
||||
return aclController;
|
||||
}
|
||||
|
||||
private PlainAccessConfig createDefaultPlainAccessConfig() {
|
||||
PlainAccessConfig config = new PlainAccessConfig();
|
||||
config.setAdmin(false);
|
||||
config.setAccessKey("rocketmq");
|
||||
config.setSecretKey("123456789");
|
||||
config.setDefaultGroupPerm("SUB");
|
||||
config.setDefaultTopicPerm("DENY");
|
||||
config.setTopicPerms(Lists.newArrayList("topicA=DENY", "topicB=PUB|SUB"));
|
||||
config.setGroupPerms(Lists.newArrayList("groupA=DENY", "groupB=PUB|SUB"));
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
@@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.rocketmq.dashboard.BaseTest;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
|
||||
@@ -62,6 +63,7 @@ public abstract class BaseControllerTest extends BaseTest {
|
||||
when(configure.getAccessKey()).thenReturn("12345678");
|
||||
when(configure.getSecretKey()).thenReturn("rocketmq");
|
||||
when(configure.getNamesrvAddr()).thenReturn("127.0.0.1:9876");
|
||||
when(configure.getNamesrvAddrs()).thenReturn(Lists.newArrayList("127.0.0.1:9876", "127.0.0.2:9876"));
|
||||
when(configure.isACLEnabled()).thenReturn(true);
|
||||
when(configure.isUseTLS()).thenReturn(false);
|
||||
}
|
||||
|
@@ -182,6 +182,8 @@ public class ConsumerControllerTest extends BaseControllerTest {
|
||||
final String url = "/consumer/deleteSubGroup.do";
|
||||
{
|
||||
doNothing().when(mqAdminExt).deleteSubscriptionGroup(any(), anyString());
|
||||
doNothing().when(mqAdminExt).deleteTopicInBroker(any(), anyString());
|
||||
doNothing().when(mqAdminExt).deleteTopicInNameServer(any(), anyString());
|
||||
}
|
||||
DeleteSubGroupRequest request = new DeleteSubGroupRequest();
|
||||
request.setBrokerNameList(Lists.newArrayList("broker-a"));
|
||||
|
@@ -152,7 +152,7 @@ public class DashboardControllerTest extends BaseControllerTest {
|
||||
|
||||
@Test
|
||||
public void testTopicCurrent() throws Exception {
|
||||
final String url = "/dashboard/topicCurrent";
|
||||
final String url = "/dashboard/topicCurrent.query";
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
|
@@ -18,10 +18,14 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.protocol.ResponseCode;
|
||||
import org.apache.rocketmq.common.protocol.body.CMResult;
|
||||
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
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;
|
||||
@@ -128,10 +132,46 @@ public class DlqMessageControllerTest extends BaseControllerTest {
|
||||
// 2、export dlqMessage success
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().is(200))
|
||||
.andExpect(content().contentType("application/vnd.ms-excel"));
|
||||
.andExpect(content().contentType("application/vnd.ms-excel;charset=utf-8"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchResendDlqMessage() throws Exception {
|
||||
final String url = "/dlqMessage/batchResendDlqMessage.do";
|
||||
List<DlqMessageRequest> dlqMessages = MockObjectUtil.createDlqMessageRequest();
|
||||
{
|
||||
ConsumeMessageDirectlyResult result = new ConsumeMessageDirectlyResult();
|
||||
result.setConsumeResult(CMResult.CR_SUCCESS);
|
||||
when(messageService.consumeMessageDirectly(any(), any(), any(), any())).thenReturn(result);
|
||||
}
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(dlqMessages));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data", hasSize(2)))
|
||||
.andExpect(jsonPath("$.data[0].consumeResult").value("CR_SUCCESS"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchExportDlqMessage() throws Exception {
|
||||
final String url = "/dlqMessage/batchExportDlqMessage.do";
|
||||
{
|
||||
when(mqAdminExt.viewMessage("%DLQ%group_test", "0A9A003F00002A9F0000000000000310"))
|
||||
.thenThrow(new RuntimeException());
|
||||
when(mqAdminExt.viewMessage("%DLQ%group_test", "0A9A003F00002A9F0000000000000311"))
|
||||
.thenReturn(MockObjectUtil.createMessageExt());
|
||||
}
|
||||
List<DlqMessageRequest> dlqMessages = MockObjectUtil.createDlqMessageRequest();
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.contentType(MediaType.APPLICATION_JSON_UTF8);
|
||||
requestBuilder.content(JSON.toJSONString(dlqMessages));
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().is(200))
|
||||
.andExpect(content().contentType("application/vnd.ms-excel;charset=utf-8"));
|
||||
}
|
||||
|
||||
@Override protected Object getTestController() {
|
||||
return dlqMessageController;
|
||||
}
|
||||
|
@@ -62,6 +62,7 @@ public class MessageTraceControllerTest extends BaseControllerTest {
|
||||
messageList.add(messageExt);
|
||||
QueryResult queryResult = new QueryResult(System.currentTimeMillis(), messageList);
|
||||
when(mqAdminExt.queryMessage(anyString(), anyString(), anyInt(), anyLong(), anyLong()))
|
||||
.thenThrow(new RuntimeException())
|
||||
.thenReturn(queryResult);
|
||||
}
|
||||
|
||||
@@ -100,6 +101,11 @@ public class MessageTraceControllerTest extends BaseControllerTest {
|
||||
final String url = "/messageTrace/viewMessageTraceDetail.query";
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
requestBuilder.param("msgId", "0A9A003F00002A9F0000000000000319");
|
||||
// query message trace exception
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
performErrorExpect(perform);
|
||||
|
||||
// query message trace success
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data", hasSize(4)))
|
||||
@@ -114,6 +120,11 @@ public class MessageTraceControllerTest extends BaseControllerTest {
|
||||
final String url = "/messageTrace/viewMessageTraceGraph.query";
|
||||
requestBuilder = MockMvcRequestBuilders.get(url);
|
||||
requestBuilder.param("msgId", "0A9A003F00002A9F0000000000000319");
|
||||
// query message trace exception
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
performErrorExpect(perform);
|
||||
|
||||
// query message trace success
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
|
@@ -34,7 +34,7 @@ public class NamesvrControllerTest extends BaseControllerTest {
|
||||
|
||||
@Test
|
||||
public void testNsaddr() throws Exception {
|
||||
final String url = "/rocketmq/nsaddr";
|
||||
final String url = "/rocketmq/nsaddr.query";
|
||||
{
|
||||
super.mockRmqConfigure();
|
||||
}
|
||||
|
@@ -35,6 +35,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
@@ -64,7 +65,7 @@ public class OpsControllerTest extends BaseControllerTest {
|
||||
.andExpect(jsonPath("$.data").isMap())
|
||||
.andExpect(jsonPath("$.data.useVIPChannel").value(false))
|
||||
.andExpect(jsonPath("$.data.namesvrAddrList").isArray())
|
||||
.andExpect(jsonPath("$.data.namesvrAddrList", hasSize(1)))
|
||||
.andExpect(jsonPath("$.data.namesvrAddrList", hasSize(2)))
|
||||
.andExpect(jsonPath("$.data.namesvrAddrList[0]").value("127.0.0.1:9876"));
|
||||
}
|
||||
|
||||
@@ -83,6 +84,20 @@ public class OpsControllerTest extends BaseControllerTest {
|
||||
Assert.assertEquals(configure.getNamesrvAddr(), "127.0.0.1:9876");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNameSvrAddr() throws Exception {
|
||||
final String url = "/ops/addNameSvrAddr.do";
|
||||
{
|
||||
doNothing().when(configure).setNamesrvAddrs(any());
|
||||
}
|
||||
requestBuilder = MockMvcRequestBuilders.post(url);
|
||||
requestBuilder.param("newNamesrvAddr", "127.0.0.3:9876");
|
||||
perform = mockMvc.perform(requestBuilder);
|
||||
perform.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
Assert.assertEquals(configure.getNamesrvAddrs().size(), 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateIsVIPChannel() throws Exception {
|
||||
final String url = "/ops/updateIsVIPChannel.do";
|
||||
@@ -96,7 +111,6 @@ public class OpsControllerTest extends BaseControllerTest {
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpdateUseTLS() throws Exception {
|
||||
final String url = "/ops/updateUseTLS.do";
|
||||
|
@@ -30,6 +30,8 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
|
||||
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
|
||||
@@ -38,6 +40,7 @@ import org.apache.rocketmq.common.protocol.body.KVTable;
|
||||
import org.apache.rocketmq.common.protocol.body.TopicList;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.dashboard.BaseTest;
|
||||
import org.apache.rocketmq.dashboard.config.CollectExecutorConfig;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.service.impl.DashboardCollectServiceImpl;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
@@ -68,6 +71,9 @@ public class DashboardCollectTaskTest extends BaseTest {
|
||||
@Mock
|
||||
private RMQConfigure rmqConfigure;
|
||||
|
||||
@Mock
|
||||
private ExecutorService collectExecutor;
|
||||
|
||||
private int taskExecuteNum = 10;
|
||||
|
||||
private File brokerFile;
|
||||
@@ -96,6 +102,7 @@ public class DashboardCollectTaskTest extends BaseTest {
|
||||
{
|
||||
TopicList topicList = new TopicList();
|
||||
Set<String> topicSet = new HashSet<>();
|
||||
topicSet.add("rmq_sys_xxx");
|
||||
topicSet.add("topic_test");
|
||||
topicSet.add("%RETRY%group_test");
|
||||
topicSet.add("%DLQ%group_test");
|
||||
@@ -121,19 +128,35 @@ public class DashboardCollectTaskTest extends BaseTest {
|
||||
} catch (Exception e) {
|
||||
Assert.assertEquals(e.getMessage(), "fetchAllTopicList exception");
|
||||
}
|
||||
dashboardCollectTask.collectTopic();
|
||||
|
||||
// multiple topic collection
|
||||
CollectExecutorConfig config = new CollectExecutorConfig();
|
||||
config.setCoreSize(10);
|
||||
config.setMaxSize(10);
|
||||
config.setQueueSize(500);
|
||||
config.setKeepAliveTime(3000);
|
||||
ExecutorService collectExecutor = config.collectExecutor(config);
|
||||
for (int i = 0; i < taskExecuteNum; i++) {
|
||||
dashboardCollectTask.collectTopic();
|
||||
CollectTaskRunnble collectTask = new CollectTaskRunnble("topic_test" + i, mqAdminExt, dashboardCollectService);
|
||||
collectExecutor.submit(collectTask);
|
||||
}
|
||||
collectExecutor.shutdown();
|
||||
boolean loop = true;
|
||||
do {
|
||||
// Wait for all collectTasks to complete
|
||||
loop = !collectExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
|
||||
}
|
||||
while (loop);
|
||||
LoadingCache<String, List<String>> map = dashboardCollectService.getTopicMap();
|
||||
Assert.assertEquals(map.size(), 1);
|
||||
Assert.assertEquals(map.get("topic_test").size(), taskExecuteNum);
|
||||
Assert.assertEquals(map.size(), taskExecuteNum);
|
||||
dashboardCollectTask.saveData();
|
||||
Assert.assertEquals(topicFile.exists(), true);
|
||||
Map<String, List<String>> topicData =
|
||||
JsonUtil.string2Obj(MixAll.file2String(topicFile),
|
||||
new TypeReference<Map<String, List<String>>>() {
|
||||
});
|
||||
Assert.assertEquals(topicData.get("topic_test").size(), taskExecuteNum);
|
||||
Assert.assertEquals(topicData.size(), taskExecuteNum);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -187,8 +210,8 @@ public class DashboardCollectTaskTest extends BaseTest {
|
||||
|
||||
private void mockBrokerFileExistBeforeSaveData() throws Exception {
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
map.put("broker-a" + ":" + MixAll.MASTER_ID, Lists.asList("1000", new String[] {"1000"}));
|
||||
map.put("broker-b" + ":" + MixAll.MASTER_ID, Lists.asList("1000", new String[] {"1000"}));
|
||||
map.put("broker-a" + ":" + MixAll.MASTER_ID, Lists.asList("1000", new String[] {"1000"}));
|
||||
map.put("broker-b" + ":" + MixAll.MASTER_ID, Lists.asList("1000", new String[] {"1000"}));
|
||||
MixAll.string2File(JsonUtil.obj2String(map), brokerFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
@@ -16,8 +16,10 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.util;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -30,8 +32,10 @@ import java.util.concurrent.ConcurrentMap;
|
||||
import org.apache.rocketmq.client.producer.LocalTransactionState;
|
||||
import org.apache.rocketmq.client.trace.TraceConstants;
|
||||
import org.apache.rocketmq.client.trace.TraceType;
|
||||
import org.apache.rocketmq.common.AclConfig;
|
||||
import org.apache.rocketmq.common.DataVersion;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
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.OffsetWrapper;
|
||||
@@ -57,7 +61,9 @@ import org.apache.rocketmq.common.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.common.protocol.route.QueueData;
|
||||
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
|
||||
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
|
||||
import org.apache.rocketmq.dashboard.model.DlqMessageRequest;
|
||||
import org.apache.rocketmq.remoting.protocol.LanguageCode;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
|
||||
import static org.apache.rocketmq.common.protocol.heartbeat.ConsumeType.CONSUME_ACTIVELY;
|
||||
|
||||
@@ -298,4 +304,38 @@ public class MockObjectUtil {
|
||||
brokerStatsData.setStatsMinute(statsMinute);
|
||||
return brokerStatsData;
|
||||
}
|
||||
|
||||
public static List<DlqMessageRequest> createDlqMessageRequest() {
|
||||
List<DlqMessageRequest> dlqMessages = new ArrayList<>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
DlqMessageRequest dlqMessageRequest = new DlqMessageRequest();
|
||||
dlqMessageRequest.setConsumerGroup("group_test");
|
||||
dlqMessageRequest.setTopicName("topic_test");
|
||||
dlqMessageRequest.setMsgId("0A9A003F00002A9F000000000000031" + i);
|
||||
dlqMessages.add(dlqMessageRequest);
|
||||
}
|
||||
return dlqMessages;
|
||||
}
|
||||
|
||||
public static AclConfig createAclConfig() {
|
||||
PlainAccessConfig adminConfig = new PlainAccessConfig();
|
||||
adminConfig.setAdmin(true);
|
||||
adminConfig.setAccessKey("rocketmq2");
|
||||
adminConfig.setSecretKey("12345678");
|
||||
|
||||
PlainAccessConfig normalConfig = new PlainAccessConfig();
|
||||
normalConfig.setAdmin(false);
|
||||
normalConfig.setAccessKey("rocketmq");
|
||||
normalConfig.setSecretKey("123456789");
|
||||
normalConfig.setDefaultGroupPerm("SUB");
|
||||
normalConfig.setDefaultTopicPerm("DENY");
|
||||
normalConfig.setTopicPerms(Lists.newArrayList("topicA=DENY", "topicB=PUB|SUB"));
|
||||
normalConfig.setGroupPerms(Lists.newArrayList("groupA=DENY", "groupB=PUB|SUB"));
|
||||
|
||||
|
||||
AclConfig aclConfig = new AclConfig();
|
||||
aclConfig.setPlainAccessConfigs(Lists.newArrayList(adminConfig, normalConfig));
|
||||
aclConfig.setGlobalWhiteAddrs(Lists.newArrayList("localhost"));
|
||||
return aclConfig;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user