Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Jolokia): Support native Jolokia 2.1.x optimization mode (fixes #… #1222

Merged
merged 1 commit into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/hawtio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"dependencies": {
"@hawtio/camel-model-v4_4": "npm:@hawtio/camel-model@~4.4.3",
"@hawtio/camel-model-v4_8": "npm:@hawtio/camel-model@~4.8.1",
"@jolokia.js/simple": "^2.1.7",
"@jolokia.js/simple": "^2.1.8",
"@module-federation/utilities": "^3.1.16",
"@monaco-editor/react": "^4.6.0",
"@patternfly/react-charts": "~7.3.0",
Expand All @@ -57,7 +57,7 @@
"@types/react-router-dom": "^5.3.3",
"dagre": "^0.8.5",
"eventemitter3": "^5.0.1",
"jolokia.js": "^2.1.7",
"jolokia.js": "^2.1.8",
"jquery": "^3.7.1",
"js-logger": "^1.6.1",
"jwt-decode": "^4.0.0",
Expand Down
7 changes: 6 additions & 1 deletion packages/hawtio/src/plugins/rbac/tree-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ export const rbacTreeProcessor: TreeProcessor = async (tree: MBeanTree) => {
const mbeans = tree.flatten()
const listMethod = await jolokiaService.getListMethod()
switch (listMethod) {
case JolokiaListMethod.NATIVE:
case JolokiaListMethod.OPTIMISED: {
log.debug('Process JMX tree: optimised list mode')
if (listMethod === JolokiaListMethod.NATIVE) {
log.debug('Process JMX tree: native list mode')
} else {
log.debug('Process JMX tree: optimised list mode')
}
// Check if RBACDecorator has been already applied to the MBean tree at server side.
const decorated = Object.values(mbeans).every(node => node.isRBACDecorated())
if (decorated) {
Expand Down
33 changes: 32 additions & 1 deletion packages/hawtio/src/plugins/shared/jolokia-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('JolokiaService', () => {
await expect(jolokiaService.getJolokiaUrl()).resolves.toBeNull()
}, 10000)

test('getJolokia - optimised', async () => {
test('getJolokia - optimised (mbean)', async () => {
jolokiaService.getJolokiaUrl = jest.fn(async () => '/test')
Jolokia.prototype.list = jest.fn(
(path?: string | string[] | jolokia.RequestOptions, opts?: SimpleRequestOptions) => {
Expand All @@ -42,11 +42,34 @@ describe('JolokiaService', () => {
return null
},
)
Jolokia.prototype.version = jest.fn((opts?: SimpleRequestOptions) => {
;(opts!.success! as SimpleResponseCallback)({
agent: 'test',
protocol: '7.3',
info: {},
config: {},
})
})

await expect(jolokiaService.getJolokia()).resolves.not.toThrow()
await expect(jolokiaService.getListMethod()).resolves.toEqual(JolokiaListMethod.OPTIMISED)
})

test('getJolokia - optimised (native)', async () => {
jolokiaService.getJolokiaUrl = jest.fn(async () => '/test')
Jolokia.prototype.version = jest.fn((opts?: SimpleRequestOptions) => {
;(opts!.success! as SimpleResponseCallback)({
agent: 'test',
protocol: '8.0',
info: {},
config: {},
})
})

await expect(jolokiaService.getJolokia()).resolves.not.toThrow()
await expect(jolokiaService.getListMethod()).resolves.toEqual(JolokiaListMethod.NATIVE)
})

test('getJolokia - default', async () => {
jolokiaService.getJolokiaUrl = jest.fn(async () => '/test')
Jolokia.prototype.list = jest.fn((...params: (string[] | string | SimpleRequestOptions)[]) => {
Expand Down Expand Up @@ -82,6 +105,14 @@ describe('JolokiaService', () => {
)
return null
})
Jolokia.prototype.version = jest.fn((opts?: SimpleRequestOptions) => {
;(opts!.success! as SimpleResponseCallback)({
agent: 'test',
protocol: '7.3',
info: {},
config: {},
})
})

await expect(jolokiaService.getJolokia()).resolves.not.toThrow()
await expect(jolokiaService.getListMethod()).resolves.toEqual(JolokiaListMethod.DEFAULT)
Expand Down
50 changes: 41 additions & 9 deletions packages/hawtio/src/plugins/shared/jolokia-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ const JOLOKIA_PATHS = ['jolokia', '/hawtio/jolokia', '/jolokia'] as const
export enum JolokiaListMethod {
/** The default LIST+EXEC Jolokia operations. */
DEFAULT,
/** The optimised list operations provided by Hawtio RBACRegistry MBean. */
/** The optimised list operation provided by Hawtio RBACRegistry MBean. */
OPTIMISED,
/** THe optimised list operation provided directly by Jolokia 2.1+ */
NATIVE,
/** Not determined. */
UNDETERMINED,
}
Expand Down Expand Up @@ -437,11 +439,38 @@ class JolokiaService implements IJolokiaService {
log.debug('Check if we can call optimised jolokia.list() operation')
// hawtio/hawtio-next#635: we pass an executor which accepts only resolve cb - we never call reject cb even
// on error, but we ensure that resolve cb is called

const path = escapeMBeanPath(this.config.mbean)
async function checkCapabilities(
successFn: SimpleResponseCallback,
errorFn: ErrorCallback,
options: SimpleRequestOptions,
) {
// check for Jolokia version (TODO: use single call)
await jolokia.version(onVersionSuccessAndError(successFn, errorFn, options))
// check for special MBean
await jolokia.list(path, onListSuccessAndError(successFn, errorFn, options))
}

return new Promise<void>(resolve => {
const successFn: SimpleResponseCallback = (value: JolokiaResponseValue) => {
// check if the MBean exists by testing whether the returned value has
// the 'op' property
if (isMBeanInfo(value) && isObject(value.op)) {
// check if this is a version response - since protocol version 8.0 we can get optimized response directly
if (this.config.method === JolokiaListMethod.NATIVE) {
resolve()
return
}
if (value && typeof value === 'object' && 'protocol' in value) {
const protocolVersion = value.protocol
if (parseFloat(protocolVersion as string) >= 8.0) {
this.config.method = JolokiaListMethod.NATIVE
log.debug('Jolokia list method:', JolokiaListMethod[this.config.method])
resolve()
}
// return without resolve
return
} else if (isMBeanInfo(value) && isObject(value.op)) {
// check if the MBean exists by testing whether the returned value has
// the 'op' property
this.config.method = JolokiaListMethod.OPTIMISED
} else {
// we could get 403 error, mark the method as special case,
Expand All @@ -458,10 +487,7 @@ class JolokiaService implements IJolokiaService {
resolve() // optimisation not happening
}

jolokia.list(
escapeMBeanPath(this.config.mbean),
onListSuccessAndError(successFn, errorFn, { fetchError: this.fetchError(resolve) }),
)
checkCapabilities(successFn, errorFn, { fetchError: this.fetchError(resolve) })
})
}

Expand Down Expand Up @@ -582,8 +608,14 @@ class JolokiaService implements IJolokiaService {
}
case JolokiaListMethod.DEFAULT:
case JolokiaListMethod.UNDETERMINED:
case JolokiaListMethod.NATIVE:
default: {
log.debug('Invoke Jolokia list MBean in default mode:', paths)
if (method === JolokiaListMethod.NATIVE) {
options.listCache = true
log.debug('Invoke Jolokia list MBean in native mode:', paths)
} else {
log.debug('Invoke Jolokia list MBean in default mode:', paths)
}
const listOptions = onListSuccessAndError(
value => {
// For empty or single list, the first path should be enough
Expand Down
22 changes: 11 additions & 11 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2019,7 +2019,7 @@ __metadata:
dependencies:
"@hawtio/camel-model-v4_4": "npm:@hawtio/camel-model@~4.4.3"
"@hawtio/camel-model-v4_8": "npm:@hawtio/camel-model@~4.8.1"
"@jolokia.js/simple": "npm:^2.1.7"
"@jolokia.js/simple": "npm:^2.1.8"
"@module-federation/utilities": "npm:^3.1.16"
"@monaco-editor/react": "npm:^4.6.0"
"@patternfly/react-charts": "npm:~7.3.0"
Expand Down Expand Up @@ -2047,7 +2047,7 @@ __metadata:
jest-environment-jsdom: "npm:^29.7.0"
jest-fetch-mock: "npm:^3.0.3"
jest-watch-typeahead: "npm:^2.2.2"
jolokia.js: "npm:^2.1.7"
jolokia.js: "npm:^2.1.8"
jquery: "npm:^3.7.1"
js-logger: "npm:^1.6.1"
jwt-decode: "npm:^4.0.0"
Expand Down Expand Up @@ -2382,12 +2382,12 @@ __metadata:
languageName: node
linkType: hard

"@jolokia.js/simple@npm:^2.1.7":
version: 2.1.7
resolution: "@jolokia.js/simple@npm:2.1.7"
"@jolokia.js/simple@npm:^2.1.8":
version: 2.1.8
resolution: "@jolokia.js/simple@npm:2.1.8"
dependencies:
jolokia.js: "npm:^2.1.7"
checksum: 10/26bc017c64df1600325f5185c39d48f600d0f3e43c5bed9e79c738c9f248eba03c9bf8a68303d7aee9bfcb9f34d44cafba705f4c5ebdd74adfdda238b29826f3
jolokia.js: "npm:^2.1.8"
checksum: 10/b60f874c93c55444998702e2948c7b5821cdecce8e12d93506260ca5787bb6d7fad81542cbf509cd9112360b6c31839bab970669b77df57d48459b1aa434ace3
languageName: node
linkType: hard

Expand Down Expand Up @@ -10210,10 +10210,10 @@ __metadata:
languageName: node
linkType: hard

"jolokia.js@npm:^2.1.7":
version: 2.1.7
resolution: "jolokia.js@npm:2.1.7"
checksum: 10/7e10e0b842c96853ea2815d46cc7cea278470d259d8660711fbfda58c3a730764790ee28dd9ad346ebcb8324bd500f109408675f19d8c0a75578703522956d91
"jolokia.js@npm:^2.1.8":
version: 2.1.8
resolution: "jolokia.js@npm:2.1.8"
checksum: 10/4dd3db2954abbaf875a3630591257056c866a201df5f3bab36148eee9e2e1520061c3b14d6873f3f0af71b2938323ecaa9540a9e37c3d952711bee077b99aca5
languageName: node
linkType: hard

Expand Down