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(jmx,camel): make Operations more robust on potential Jolokia max depth shortage error #672

Merged
merged 1 commit into from
Nov 17, 2023
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
9 changes: 6 additions & 3 deletions packages/hawtio/src/plugins/shared/jolokia-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,10 @@ class JolokiaService implements IJolokiaService {
}
// Overwrite max depth as listing MBeans requires some constant depth to work
// See: https://github.com/hawtio/hawtio-next/issues/670
options.maxDepth = JOLOKIA_LIST_MAX_DEPTH
const { maxDepth } = this.loadJolokiaStoredOptions()
if (maxDepth < JOLOKIA_LIST_MAX_DEPTH) {
options.maxDepth = JOLOKIA_LIST_MAX_DEPTH
}
switch (method) {
case JolokiaListMethod.OPTIMISED: {
log.debug('Invoke Jolokia list MBean in optimised mode:', paths)
Expand Down Expand Up @@ -799,8 +802,8 @@ class JolokiaService implements IJolokiaService {
loadJolokiaStoredOptions(): JolokiaStoredOptions {
const item = localStorage.getItem(STORAGE_KEY_JOLOKIA_OPTIONS)
const options: JolokiaStoredOptions = item ? JSON.parse(item) : {}
const maxDepth = options.maxDepth || DEFAULT_MAX_DEPTH
const maxCollectionSize = options.maxCollectionSize || DEFAULT_MAX_COLLECTION_SIZE
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH
const maxCollectionSize = options.maxCollectionSize ?? DEFAULT_MAX_COLLECTION_SIZE
return { maxDepth, maxCollectionSize }
}

Expand Down
6 changes: 3 additions & 3 deletions packages/hawtio/src/plugins/shared/operations/Operations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { createOperations } from './operation'
export const Operations: React.FunctionComponent = () => {
const { selectedNode } = useContext(PluginNodeSelectionContext)

if (!selectedNode || !selectedNode.objectName || !selectedNode.mbean) {
if (!selectedNode || !selectedNode.mbean) {
return null
}

const { objectName, mbean } = selectedNode
const { mbean } = selectedNode

if (!mbean.op || isEmpty(mbean.op)) {
return <HawtioEmptyCard message='This MBean has no JMX operations.' />
}

const operations = createOperations(objectName, mbean.op)
const operations = createOperations(mbean.op)

const OperationList = () => (
<DataList id='jmx-operation-list' aria-label='operation list' isCompact>
Expand Down
51 changes: 32 additions & 19 deletions packages/hawtio/src/plugins/shared/operations/operation.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,50 @@
import { eventService } from '@hawtiosrc/core'
import { stringSorter, trimEnd } from '@hawtiosrc/util/strings'
import { log } from '../globals'
import { OptimisedMBeanOperation, OptimisedMBeanOperations } from '../tree'

/**
* Factory function for Operation objects.
*/
export function createOperations(objectName: string, jmxOperations: OptimisedMBeanOperations): Operation[] {
export function createOperations(jmxOperations: OptimisedMBeanOperations): Operation[] {
const operations: Operation[] = []
const operationMap: Record<string, Operation> = {}
const errors: string[] = []
Object.entries(jmxOperations).forEach(([name, op]) => {
if (Array.isArray(op)) {
op.forEach(op => addOperation(operations, operationMap, name, op))
op.forEach(op => addOperation(operations, name, op, errors))
} else {
addOperation(operations, operationMap, name, op)
addOperation(operations, name, op, errors)
}
})
if (errors.length > 0) {
eventService.notify({
type: 'danger',
message: `Please try increasing max depth for Jolokia in the Connect preferences. Failed to load operations: ${errors.join(
', ',
)}.`,
duration: 30 * 1000, // 30 sec.
})
}
return operations.sort((a, b) => stringSorter(a.readableName, b.readableName))
}

function addOperation(
operations: Operation[],
operationMap: Record<string, Operation>,
name: string,
op: OptimisedMBeanOperation,
): void {
const operation = new Operation(
name,
op.args.map(arg => new OperationArgument(arg.name, arg.type, arg.desc)),
op.desc,
op.ret,
op.canInvoke,
)
operations.push(operation)
operationMap[operation.name] = operation
function addOperation(operations: Operation[], name: string, op: OptimisedMBeanOperation, errors: string[]) {
try {
const operation = new Operation(
name,
op.args.map(arg => new OperationArgument(arg.name, arg.type, arg.desc)),
op.desc,
op.ret,
op.canInvoke,
)
operations.push(operation)
} catch (error) {
// Error can happen when max depth for Jolokia LIST is too small and part of
// the returned MBeans are compressed in a string form. In that case, the user
// needs to increase max depth for Jolokia requests in Connect preferences.
log.error('Operations - Error creating operation:', name, error)
errors.push(name)
}
}

export class Operation {
Expand Down
Loading