getEnvironment() {
+ return this.env;
+ }
+
+ @Override
+ public JMXServiceURL serviceUrl() {
+ return this.connectUrl;
+ }
+
+}
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/Messages.java b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/Messages.java
new file mode 100644
index 0000000000..a47e8a9ee3
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/Messages.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Kantega AS. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at http://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.kubernetes;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.openjdk.jmc.kubernetes.messages"; //$NON-NLS-1$
+ public static String KubernetesDiscoveryListener_CouldNotFindSecret;
+ public static String KubernetesDiscoveryListener_Description;
+ public static String KubernetesDiscoveryListener_ErrConnectingToJvm;
+ public static String KubernetesDiscoveryListener_HttpOrHttps;
+ public static String KubernetesDiscoveryListener_InNamespace;
+ public static String KubernetesDiscoveryListener_JolokiaProtocol;
+ public static String KubernetesDiscoveryListener_MustProvidePassword;
+ public static String KubernetesDiscoveryListener_UnableToFindContexts;
+ public static String KubernetesDiscoveryListener_UnableToScan;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/messages.properties b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/messages.properties
new file mode 100644
index 0000000000..ea0166360a
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/messages.properties
@@ -0,0 +1,9 @@
+KubernetesDiscoveryListener_CouldNotFindSecret=Could not find secret named
+KubernetesDiscoveryListener_Description=List JVM in kubernetes cluster
+KubernetesDiscoveryListener_ErrConnectingToJvm=Error connecting to JVM in pod
+KubernetesDiscoveryListener_HttpOrHttps=' must be either 'http' or 'https'
+KubernetesDiscoveryListener_InNamespace=\ in namespace
+KubernetesDiscoveryListener_JolokiaProtocol=Jolokia protocol '
+KubernetesDiscoveryListener_MustProvidePassword=Password must be specified when username is specified
+KubernetesDiscoveryListener_UnableToFindContexts=Unable to find all kubernetes contexts
+KubernetesDiscoveryListener_UnableToScan=Unable to scan kubernetes context
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/JmcKubernetesPreferenceForm.java b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/JmcKubernetesPreferenceForm.java
new file mode 100644
index 0000000000..1efb921d61
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/JmcKubernetesPreferenceForm.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Kantega AS. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at http://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.kubernetes.preferences;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.openjdk.jmc.common.security.CredentialsNotAvailableException;
+import org.openjdk.jmc.common.security.SecurityException;
+import org.openjdk.jmc.kubernetes.JmcKubernetesPlugin;
+
+/**
+ * This class represents a preference page that is contributed to the Preferences dialog. By
+ * subclassing FieldEditorPreferencePage, we can use the field support built into JFace
+ * that allows us to create a page that is small and knows how to save, restore and apply itself.
+ *
+ * This page is used to modify preferences only. They are stored in the preference store that
+ * belongs to the main plug-in class. That way, preferences can be accessed directly via the
+ * preference store.
+ */
+public class JmcKubernetesPreferenceForm extends FieldEditorPreferencePage
+ implements IWorkbenchPreferencePage, PreferenceConstants {
+
+ private Map dependantControls = new WeakHashMap<>();
+ private Text userField;
+ private Text passwordField;
+ private boolean credentialsDirty;
+
+ public JmcKubernetesPreferenceForm() {
+ super(GRID);
+ setPreferenceStore(JmcKubernetesPlugin.getDefault().getPreferenceStore());
+ setDescription(Messages.JmcKubernetesPreferenceForm_FormDescription);
+ }
+
+ /**
+ * Creates the field editors. Field editors are abstractions of the common GUI blocks needed to
+ * manipulate various types of preferences. Each field editor knows how to save and restore
+ * itself.
+ */
+ public void createFieldEditors() {
+ BooleanFieldEditor mainEnabler = new BooleanFieldEditor(P_SCAN_FOR_INSTANCES,
+ Messages.JmcKubernetesPreferenceForm_ScanForPods, getFieldEditorParent()) {
+ @Override
+ protected void valueChanged(boolean oldValue, boolean newValue) {
+ super.valueChanged(oldValue, newValue);
+ enableDependantFields(newValue);
+ }
+ };
+ addField(mainEnabler);
+
+ final BooleanFieldEditor scanContextsEditor = new BooleanFieldEditor(P_SCAN_ALL_CONTEXTS,
+ Messages.JmcKubernetesPreferenceForm_AllContexts, getFieldEditorParent());
+ this.addDependantField(scanContextsEditor, scanContextsEditor.getDescriptionControl(getFieldEditorParent()));
+ final BooleanFieldEditor logErrors = new BooleanFieldEditor(P_LOG_ERRORS,
+ Messages.JmcKubernetesPreferenceForm_LogErrorsLabel, getFieldEditorParent());
+ this.addDependantField(logErrors, logErrors.getDescriptionControl(getFieldEditorParent()));
+ this.addTextField(new StringFieldEditor(P_REQUIRE_LABEL, Messages.JmcKubernetesPreferenceForm_RequireLabel,
+ getFieldEditorParent()), Messages.JmcKubernetesPreferenceForm_LabelToolTip);
+ this.addTextField(new StringFieldEditor(P_JOLOKIA_PATH, Messages.JmcKubernetesPreferenceForm_PathLabel,
+ getFieldEditorParent()), Messages.JmcKubernetesPreferenceForm_PathTooltip);
+ this.addTextField(new StringFieldEditor(P_JOLOKIA_PORT, Messages.JmcKubernetesPreferenceForm_PortLabel,
+ getFieldEditorParent()), Messages.JmcKubernetesPreferenceForm_PortTooltip);
+ this.addTextField(new StringFieldEditor(P_JOLOKIA_PROTOCOL, Messages.JmcKubernetesPreferenceForm_ProtocolLabel,
+ getFieldEditorParent()), Messages.JmcKubernetesPreferenceForm_ProtocolTooltip);
+ createCredentialFields();
+ // set initial enablement
+ enableDependantFields(JmcKubernetesPlugin.getDefault().scanForInstances());
+
+ }
+
+ private void createCredentialFields() {
+ Label userLabel = new Label(getFieldEditorParent(), SWT.NONE);
+ userLabel.setText(Messages.JmcKubernetesPreferenceForm_UsernameLabel);
+ userLabel.setLayoutData(new GridData());
+ this.userField = new Text(getFieldEditorParent(), SWT.SINGLE | SWT.BORDER);
+ userField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ userField.setToolTipText(Messages.JmcKubernetesPreferenceForm_UsernameTooltip);
+ this.dependantControls.put(userField, null);
+
+ Label passLabel = new Label(getFieldEditorParent(), SWT.NONE);
+ passLabel.setText(Messages.JmcKubernetesPreferenceForm_PasswordLabel);
+ passLabel.setLayoutData(new GridData());
+ this.passwordField = new Text(getFieldEditorParent(), SWT.PASSWORD | SWT.SINGLE | SWT.BORDER);
+ passwordField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ this.dependantControls.put(passwordField, null);
+
+ JmcKubernetesPlugin plugin = JmcKubernetesPlugin.getDefault();
+
+ try {
+ userField.setText(plugin.username());
+ passwordField.setText(plugin.password());
+ } catch (CredentialsNotAvailableException ignore) {
+ // ignore if credentials are not stored
+ } catch (SecurityException e) {
+ plugin.getLogger().log(Level.WARNING, "Could not load kubernetes credentials", e); //$NON-NLS-1$
+ }
+
+ ModifyListener markCredentials = e -> credentialsDirty = true;
+ this.userField.addModifyListener(markCredentials);
+ this.passwordField.addModifyListener(markCredentials);
+ }
+
+ private void addTextField(StringFieldEditor field, String tooltip) {
+ Text textControl = field.getTextControl(getFieldEditorParent());
+ this.addDependantField(field, textControl);
+ textControl.setToolTipText(tooltip);
+ field.getLabelControl(getFieldEditorParent()).setToolTipText(tooltip);
+
+ }
+
+ private void addDependantField(FieldEditor field, Control control) {
+ this.dependantControls.put(control, null);
+ addField(field);
+ }
+
+ private void enableDependantFields(boolean enabled) {
+ for (Control field : this.dependantControls.keySet()) {
+ field.setEnabled(enabled);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+ */
+ public void init(IWorkbench workbench) {
+ }
+
+ @Override
+ public boolean performOk() {
+ updateCredentialsIfApplicable();
+ return super.performOk();
+ }
+
+ private void updateCredentialsIfApplicable() {
+ if (this.credentialsDirty) {
+ try {
+ JmcKubernetesPlugin.getDefault().storeCredentials(userField.getText(), passwordField.getText());
+ this.credentialsDirty = false;
+ } catch (SecurityException ex) {
+ JmcKubernetesPlugin.getDefault().getLogger().log(Level.WARNING,
+ "Could not store kubernetes credentials", ex); //$NON-NLS-1$
+ }
+ }
+ }
+
+}
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/KubernetesScanningParameters.java b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/KubernetesScanningParameters.java
new file mode 100644
index 0000000000..110f4ca881
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/KubernetesScanningParameters.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Kantega AS. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at http://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.kubernetes.preferences;
+
+import org.openjdk.jmc.common.security.ICredentials;
+import org.openjdk.jmc.common.security.SecurityException;
+
+public interface KubernetesScanningParameters {
+ boolean scanForInstances();
+
+ boolean scanAllContexts();
+
+ String jolokiaPort();
+
+ String username() throws SecurityException;
+
+ String password() throws SecurityException;
+
+ String jolokiaPath();
+
+ String jolokiaProtocol();
+
+ String requireLabel();
+
+ ICredentials storeCredentials(String username, String password) throws SecurityException;
+
+ void logError(String message, Throwable error);
+}
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/Messages.java b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/Messages.java
new file mode 100644
index 0000000000..78234e0af0
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/Messages.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Kantega AS. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at http://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.kubernetes.preferences;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.openjdk.jmc.kubernetes.preferences.messages"; //$NON-NLS-1$
+ public static String JmcKubernetesPreferenceForm_AllContexts;
+ public static String JmcKubernetesPreferenceForm_FormDescription;
+ public static String JmcKubernetesPreferenceForm_LabelToolTip;
+ public static String JmcKubernetesPreferenceForm_LogErrorsLabel;
+ public static String JmcKubernetesPreferenceForm_PasswordLabel;
+ public static String JmcKubernetesPreferenceForm_PasswordTooltip;
+ public static String JmcKubernetesPreferenceForm_PathLabel;
+ public static String JmcKubernetesPreferenceForm_PathTooltip;
+ public static String JmcKubernetesPreferenceForm_PortLabel;
+ public static String JmcKubernetesPreferenceForm_PortTooltip;
+ public static String JmcKubernetesPreferenceForm_ProtocolLabel;
+ public static String JmcKubernetesPreferenceForm_ProtocolTooltip;
+ public static String JmcKubernetesPreferenceForm_RequireLabel;
+ public static String JmcKubernetesPreferenceForm_ScanForPods;
+ public static String JmcKubernetesPreferenceForm_UsernameTooltip;
+ public static String JmcKubernetesPreferenceForm_UsernameLabel;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/PreferenceConstants.java b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/PreferenceConstants.java
new file mode 100644
index 0000000000..9485253abc
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/PreferenceConstants.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Kantega AS. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at http://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.kubernetes.preferences;
+
+/**
+ * Constant definitions for plug-in preferences
+ */
+public interface PreferenceConstants {
+
+ public static final String P_SCAN_FOR_INSTANCES = "scanForInstances"; //$NON-NLS-1$
+ public static final String P_SCAN_ALL_CONTEXTS = "scanAllContexts"; //$NON-NLS-1$
+ public static final String P_LOG_ERRORS = "logErrors"; //$NON-NLS-1$
+ public static final String P_REQUIRE_LABEL = "requireLabel"; //$NON-NLS-1$
+ public static final String P_JOLOKIA_PATH = "jolokiaPath"; //$NON-NLS-1$
+ public static final String P_JOLOKIA_PORT = "jolokiaPort"; //$NON-NLS-1$
+ public static final String P_JOLOKIA_PROTOCOL = "jolokiaProtocol"; //$NON-NLS-1$
+ public static final String P_CREDENTIALS_KEY = "kubernetes.scanning.credentials"; //$NON-NLS-1$
+}
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/PreferenceInitializer.java b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/PreferenceInitializer.java
new file mode 100644
index 0000000000..b1f653366e
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/PreferenceInitializer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Kantega AS. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at http://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.kubernetes.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.openjdk.jmc.kubernetes.JmcKubernetesPlugin;
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer implements PreferenceConstants {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#
+ * initializeDefaultPreferences()
+ */
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = JmcKubernetesPlugin.getDefault().getPreferenceStore();
+ store.setDefault(P_SCAN_FOR_INSTANCES, false);
+ store.setDefault(P_SCAN_ALL_CONTEXTS, false);
+ store.setDefault(P_REQUIRE_LABEL, "jolokia"); //$NON-NLS-1$
+ store.setDefault(P_JOLOKIA_PATH, "/jolokia/"); //$NON-NLS-1$
+ store.setDefault(P_JOLOKIA_PORT, "8778"); //$NON-NLS-1$
+ }
+
+}
diff --git a/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/messages.properties b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/messages.properties
new file mode 100644
index 0000000000..cb743096d3
--- /dev/null
+++ b/application/org.openjdk.jmc.kubernetes/src/main/java/org/openjdk/jmc/kubernetes/preferences/messages.properties
@@ -0,0 +1,18 @@
+JmcKubernetesPreferenceForm_AllContexts=Scan pods from all locally configured &contexts, if false: only scan the current contexts
+JmcKubernetesPreferenceForm_FormDescription=Options that allows you to scan kubernetes for JVMs running Jolokia\
+\n\nThe Kubernetes Proxy API will be used to attempt to access Jolokia like this (parenthesis denote optional components): \
+\n\n$kubernetesBaseUrl/api/v1/namespaces/podNamespace/pods/(jolokiaProtocol:)podname(:jolokiaPort)/proxy/jolokiaPath\n\n
+JmcKubernetesPreferenceForm_LabelToolTip=Only attempt to connect to pods with this label set, leave empty to try to scan all pods
+JmcKubernetesPreferenceForm_LogErrorsLabel=Log errors during scanning. Aids in troubleshooting but may generate some background noise.
+JmcKubernetesPreferenceForm_PasswordLabel=Require pass&word
+JmcKubernetesPreferenceForm_PasswordTooltip=Password , alternatively use ${kubernetes/secret/secretName/secretItem} where the secret is in the same namespace as the pod and the type is either kubernetes.io/basic-auth or Opaque with java.util.Properties compatible values
+JmcKubernetesPreferenceForm_PathLabel=Jolokia &path in pods
+JmcKubernetesPreferenceForm_PathTooltip=Use this path for jolokia, or specify ${kubernetes/annotation/annotationName} to be able to to get port name from pod metadata annotation of your choice
+JmcKubernetesPreferenceForm_PortLabel=Jolokia p&ort in pods
+JmcKubernetesPreferenceForm_PortTooltip=Port to use, leave empty to use default port of Kubernetes proxy, hardcode a port value, or alternatively ${kubernetes/annotation/annotationName} to get port name from pod metadata annotation of your choice
+JmcKubernetesPreferenceForm_ProtocolLabel=Jolokia pro&tocol in pods
+JmcKubernetesPreferenceForm_ProtocolTooltip=Protocol to use (optional), will infer http if not set, or hardcode to https, or alternatively ${kubernetes/annotation/annotationName} to get port name from pod metadata annotation of your choice
+JmcKubernetesPreferenceForm_RequireLabel=Require &label to scan pod
+JmcKubernetesPreferenceForm_ScanForPods=&Scan for kubernetes pods with Jolokia support
+JmcKubernetesPreferenceForm_UsernameTooltip=Username , alternatively use ${kubernetes/secret/secretName/secretItem} where the secret is in the same namespace as the pod and the type is either kubernetes.io/basic-auth or Opaque with java.util.Properties compatible values
+JmcKubernetesPreferenceForm_UsernameLabel=Require &username
diff --git a/application/pom.xml b/application/pom.xml
index fbd9cc8b2d..13f0c99be8 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -112,6 +112,7 @@
org.openjdk.jmc.updatesite.ide
org.openjdk.jmc.updatesite.rcp
org.openjdk.jmc.jolokia
+ org.openjdk.jmc.kubernetes
l10n
tests
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/pom.xml b/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
index bedcfa1fb1..96a395cf93 100644
--- a/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
+++ b/application/tests/org.openjdk.jmc.jolokia.test/pom.xml
@@ -46,7 +46,7 @@
${project.basedir}/../../../configuration
- 2.0.2
+ 2.2.2
diff --git a/application/tests/org.openjdk.jmc.jolokia.test/src/test/java/org/openjdk/jmc/jolokia/JolokiaTest.java b/application/tests/org.openjdk.jmc.jolokia.test/src/test/java/org/openjdk/jmc/jolokia/JolokiaTest.java
index bd1f2ceba2..c5d50622aa 100644
--- a/application/tests/org.openjdk.jmc.jolokia.test/src/test/java/org/openjdk/jmc/jolokia/JolokiaTest.java
+++ b/application/tests/org.openjdk.jmc.jolokia.test/src/test/java/org/openjdk/jmc/jolokia/JolokiaTest.java
@@ -209,7 +209,7 @@ public JolokiaContext getJolokiaContext() {
StaticConfiguration configuration = new StaticConfiguration(ConfigKey.AGENT_ID, "jolokiatest");
JolokiaServiceManager serviceManager = JolokiaServiceManagerFactory.createJolokiaServiceManager(configuration,
new StdoutLogHandler(true), new AllowAllRestrictor(),
- () -> new TreeSet(Arrays.asList(ServerDetector.FALLBACK)));
+ log -> new TreeSet<>(Arrays.asList(ServerDetector.FALLBACK)));
return serviceManager.start();
}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/META-INF/MANIFEST.MF b/application/uitests/org.openjdk.jmc.kubernetes.test/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..d028d9df45
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: RJMX Test
+Bundle-SymbolicName: org.openjdk.jmc.kubernetes.test;singleton:=true
+Bundle-Version: 10.0.0.qualifier
+Import-Package: io.fabric8.kubernetes.api.model
+Bundle-Vendor: Oracle Corporation
+Bundle-RequiredExecutionEnvironment: JavaSE-17
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.junit,
+ org.openjdk.jmc.jolokia,
+ org.eclipse.osgi;bundle-version="3.16.200",
+ org.eclipse.ui.workbench,
+ org.openjdk.jmc.rjmx;bundle-version="9.0.0",
+ org.eclipse.ui,
+ org.hamcrest;bundle-version="2.1",
+ org.openjdk.jmc.kubernetes;bundle-version="9.0.0",
+ com.github.tomakehurst.wiremock-standalone;bundle-version="2.27.2",
+ org.awaitility;bundle-version="4.0.0"
+Automatic-Module-Name: org.openjdk.jmc.jolokia.test
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/build.properties b/application/uitests/org.openjdk.jmc.kubernetes.test/build.properties
new file mode 100644
index 0000000000..3be66a2718
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/build.properties
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025, Kantega AS. All rights reserved.
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# The contents of this file are subject to the terms of either the Universal Permissive License
+# v 1.0 as shown at http://oss.oracle.com/licenses/upl
+#
+# or the following license:
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided with
+# the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+# endorse or promote products derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+source.. = src/test/java/,\
+ src/test/resources/
+output.. = target/test-classes/
+bin.includes = META-INF/,.
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/pom.xml b/application/uitests/org.openjdk.jmc.kubernetes.test/pom.xml
new file mode 100644
index 0000000000..61fe1bf30b
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/pom.xml
@@ -0,0 +1,58 @@
+
+
+
+ 4.0.0
+
+ org.openjdk.jmc
+ missioncontrol.application.uitests
+ ${revision}${changelist}
+
+ org.openjdk.jmc.kubernetes.test
+ eclipse-test-plugin
+
+
+ ${project.basedir}/../../../configuration
+
+
+
+
+ org.awaitility
+ awaitility
+ 4.0.0
+
+
+
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/java/org/openjdk/jmc/kubernetes/JmcKubernetesTest.java b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/java/org/openjdk/jmc/kubernetes/JmcKubernetesTest.java
new file mode 100644
index 0000000000..832483331d
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/java/org/openjdk/jmc/kubernetes/JmcKubernetesTest.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, Kantega AS. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * The contents of this file are subject to the terms of either the Universal Permissive License
+ * v 1.0 as shown at http://oss.oracle.com/licenses/upl
+ *
+ * or the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other materials provided with
+ * the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+ * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.openjdk.jmc.kubernetes;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.time.Duration;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanException;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXServiceURL;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClients;
+import org.awaitility.Awaitility;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.openjdk.jmc.common.IDescribable;
+import org.openjdk.jmc.common.jvm.JVMType;
+import org.openjdk.jmc.common.security.ICredentials;
+import org.openjdk.jmc.common.security.InMemoryCredentials;
+import org.openjdk.jmc.common.security.SecurityException;
+import org.openjdk.jmc.kubernetes.preferences.KubernetesScanningParameters;
+import org.openjdk.jmc.rjmx.common.IConnectionDescriptor;
+import org.openjdk.jmc.rjmx.common.IServerDescriptor;
+import org.openjdk.jmc.rjmx.descriptorprovider.IDescriptorListener;
+
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
+import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+
+/**
+ * Test that JMX connections done with JmcKubernetesJmxConnectionProvider are functional. In order
+ * to be able to test this in a contained environment, the kubernetes API is mocked with wiremock.
+ */
+@SuppressWarnings("restriction")
+public class JmcKubernetesTest {
+
+ static class TestParameters implements KubernetesScanningParameters {
+ public boolean scanForInstances, scanAllContexts;
+ public String jolokiaPort, jolokiaPath = "/jolokia/", jolokiaProtocol, requireLabel;
+ public InMemoryCredentials credentials;
+
+ @Override
+ public boolean scanForInstances() {
+ return this.scanForInstances;
+ }
+
+ @Override
+ public boolean scanAllContexts() {
+ return this.scanAllContexts;
+ }
+
+ @Override
+ public String jolokiaPort() {
+ return this.jolokiaPort;
+ }
+
+ @Override
+ public String username() throws SecurityException {
+ return this.credentials == null ? null : this.credentials.getUsername();
+ }
+
+ @Override
+ public String password() throws SecurityException {
+ return this.credentials == null ? null : this.credentials.getPassword();
+ }
+
+ @Override
+ public String jolokiaPath() {
+ return this.jolokiaPath;
+ }
+
+ @Override
+ public String jolokiaProtocol() {
+ return this.jolokiaProtocol;
+ }
+
+ @Override
+ public String requireLabel() {
+ return this.requireLabel;
+ }
+
+ @Override
+ public ICredentials storeCredentials(String username, String password) throws SecurityException {
+ return this.credentials = new InMemoryCredentials(username, password);
+ }
+
+ @Override
+ public void logError(String message, Throwable error) {
+ System.out.println(message);
+ error.printStackTrace(System.out);
+ }
+ }
+
+ @ClassRule
+ public static WireMockRule wiremock = new WireMockRule(
+ WireMockConfiguration.options().extensions(new ResponseTemplateTransformer(false)).port(0));
+
+ static final String jolokiaUrl = "service:jmx:kubernetes:///ns1/pod-abcdef/jolokia";
+
+ private static MBeanServerConnection jolokiaConnection;
+
+ @BeforeClass
+ public static void connect() throws Exception {
+ CloseableHttpResponse configResponse = HttpClients.createDefault()
+ .execute(new HttpGet(wiremock.baseUrl() + "/mock-kube-config.yml"));
+ Assert.assertEquals(configResponse.getStatusLine().getStatusCode(), 200);
+ File configFile = File.createTempFile("mock-kube-config", ".yml");
+ configResponse.getEntity().writeTo(new FileOutputStream(configFile));
+ // we set this so the KubernetesDiscoveryListener will work
+ //Setting taken from: https://github.com/fabric8io/kubernetes-client/blob/77a65f7d40f31a5dc37492cd9de3c317c2702fb4/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/Config.java#L120, unlikely to change
+ System.setProperty("kubeconfig", configFile.getAbsolutePath());
+ jolokiaConnection = getKubernetesMBeanConnector();
+ }
+
+ @Test
+ public void testExecuteOperation() throws InstanceNotFoundException, MalformedObjectNameException, MBeanException,
+ ReflectionException, MalformedURLException, IOException {
+ jolokiaConnection.invoke(new ObjectName("java.lang:type=Memory"), "gc", new Object[0], new String[0]);
+ }
+
+ @Test
+ public void testReadAttribute()
+ throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException,
+ MalformedObjectNameException, MBeanException, ReflectionException, MalformedURLException, IOException {
+ MBeanServerConnection jmxConnection = jolokiaConnection;
+ assertOneSingleAttribute(jmxConnection);
+
+ }
+
+ private void assertOneSingleAttribute(MBeanServerConnection jmxConnection) throws MalformedObjectNameException,
+ MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException {
+ ObjectName objectName = new ObjectName("java.lang:type=Memory");
+ String attribute = "Verbose";
+ Assert.assertEquals(false, jmxConnection.getAttribute(objectName, attribute));
+ }
+
+ @Before
+ public void reset() {
+ wiremock.resetAll();
+ wiremock.resetRequests();
+ }
+
+ private static MBeanServerConnection getKubernetesMBeanConnector() throws IOException, MalformedURLException {
+ JMXConnector connector = new JmcKubernetesJmxConnectionProvider().newJMXConnector(new JMXServiceURL(jolokiaUrl),
+ Collections.emptyMap());
+ connector.connect();
+ MBeanServerConnection connection = connector.getMBeanServerConnection();
+ return connection;
+ }
+
+ @Test
+ public void testDiscoverWithMostlyDefaultSettings() throws Exception {
+
+ TestParameters parameters = new TestParameters();
+ // Set config so that scanning takes place
+ parameters.scanForInstances = true;
+ testThatJvmIsFound(parameters);
+ }
+
+ @Test
+ public void testDiscoverWithPathFromAnnotation() throws Exception {
+ TestParameters parameters = new TestParameters();
+ parameters.scanForInstances = true;
+ parameters.jolokiaPath = "${kubernetes/annotation/jolokiaPath}";
+ testThatJvmIsFound(parameters);
+ }
+
+ @Test
+ public void testDiscoverWithPortFromAnnotation() throws Exception {
+ TestParameters parameters = new TestParameters();
+ parameters.scanForInstances = true;
+ parameters.jolokiaPort = "${kubernetes/annotation/jolokiaPort}";
+
+ testThatJvmIsFound(parameters);
+ }
+
+ @Test
+ public void testDiscoverWithBasicAuthFromSecret() throws Exception {
+ TestParameters parameters = new TestParameters();
+ parameters.scanForInstances = true;
+ parameters.credentials = new InMemoryCredentials("${kubernetes/secret/jolokia-auth/username}",
+ "${kubernetes/secret/jolokia-auth/password}");
+
+ testThatJvmIsFound(parameters);
+ // Verify that the expected authorization was picked up
+ WireMock.verify(WireMock
+ .postRequestedFor(WireMock.urlPathMatching("/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*"))
+ .withHeader("X-jolokia-authorization",
+ WireMock.equalTo("Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes()))));
+ }
+
+ @Test
+ public void testDiscoverWithAuthFromProperties() throws Exception {
+
+ TestParameters parameters = new TestParameters();
+ parameters.scanForInstances = true;
+ parameters.credentials = new InMemoryCredentials("${kubernetes/secret/jolokia-properties/user}",
+ "${kubernetes/secret/jolokia-properties/password}");
+
+ testThatJvmIsFound(parameters);
+ // Verify that the expected authorization was picked up
+ WireMock.verify(WireMock
+ .postRequestedFor(WireMock.urlPathMatching("/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*"))
+ .withHeader("X-jolokia-authorization",
+ WireMock.equalTo("Basic " + Base64.getEncoder().encodeToString("admin:secret".getBytes()))));
+ }
+
+ @Test
+ public void testDiscoverWithAuthDirectlyFromSettings() throws Exception {
+
+ TestParameters parameters = new TestParameters();
+ parameters.scanForInstances = true;
+ parameters.credentials = new InMemoryCredentials("user", "***");
+ testThatJvmIsFound(parameters);
+ // Verify that the expected authorization was picked up
+ WireMock.verify(WireMock
+ .postRequestedFor(WireMock.urlPathMatching("/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*"))
+ .withHeader("X-jolokia-authorization",
+ WireMock.equalTo("Basic " + Base64.getEncoder().encodeToString("user:***".getBytes()))));
+ }
+
+ private void testThatJvmIsFound(TestParameters parameters) throws Exception {
+
+ final KubernetesDiscoveryListener scanner = new KubernetesDiscoveryListener(parameters);
+ final Map foundVms = new HashMap<>();
+ IDescriptorListener descriptorListener = new IDescriptorListener() {
+ public void onDescriptorDetected(
+ IServerDescriptor serverDescriptor, String path, JMXServiceURL url,
+ IConnectionDescriptor connectionDescriptor, IDescribable provider) {
+ foundVms.put(serverDescriptor.getGUID(), serverDescriptor);
+ }
+
+ public void onDescriptorRemoved(String descriptorId) {
+ foundVms.remove(descriptorId);
+ }
+ };
+ scanner.addDescriptorListener(descriptorListener);
+
+ try {
+ // Test that at least one VM (the one running the test was discovered)
+
+ Awaitility.await().atMost(Duration.ofSeconds(5)).until(() -> !foundVms.isEmpty());
+ IServerDescriptor descriptor = foundVms.get("pod-abcdef");
+ Assert.assertNotNull(descriptor);
+ Assert.assertEquals(
+ "[JVMDescriptor] Java command: /Users/marska/Downloads/hawtio-app-2.9.1.jar --port 9090 PID: 88774",
+ descriptor.getJvmInfo().toString());
+ Assert.assertEquals(JVMType.HOTSPOT, descriptor.getJvmInfo().getJvmType());
+ Assert.assertEquals("18.0.1", descriptor.getJvmInfo().getJavaVersion());
+ Assert.assertTrue(descriptor instanceof IConnectionDescriptor);
+ IConnectionDescriptor connectDescriptor = (IConnectionDescriptor) descriptor;
+ JMXConnector connector = new JmcKubernetesJmxConnectionProvider()
+ .newJMXConnector(connectDescriptor.createJMXServiceURL(), connectDescriptor.getEnvironment());
+ connector.connect();
+ assertOneSingleAttribute(connector.getMBeanServerConnection());
+
+ } finally {
+ // Tell scanner thread to exit
+ scanner.shutdown();
+ }
+ }
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-attribute.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-attribute.json
new file mode 100644
index 0000000000..4230121a7e
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-attribute.json
@@ -0,0 +1,10 @@
+{
+ "request" : {
+ "attribute" : "Verbose",
+ "mbean" : "java.lang:type=Memory",
+ "type" : "read"
+ },
+ "status" : 200,
+ "timestamp" : 1658563869,
+ "value" : false
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-basic-auth-secret.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-basic-auth-secret.json
new file mode 100644
index 0000000000..b5bb351b7e
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-basic-auth-secret.json
@@ -0,0 +1,19 @@
+{
+ "apiVersion": "v1",
+ "data": {
+ "password": "YWRtaW4=",
+ "username": "YWRtaW4="
+ },
+ "kind": "Secret",
+ "metadata": {
+ "annotations": {
+ "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"jolokia-auth\",\"namespace\":\"jfr\"},\"stringData\":{\"password\":\"admin\",\"username\":\"admin\"},\"type\":\"kubernetes.io/basic-auth\"}\n"
+ },
+ "creationTimestamp": "2022-05-20T13:59:12Z",
+ "name": "jolokia-auth",
+ "namespace": "jfr",
+ "resourceVersion": "130",
+ "uid": "e1563217-ef08-481d-b2e3-233fa3040b56"
+ },
+ "type": "kubernetes.io/basic-auth"
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-exec.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-exec.json
new file mode 100644
index 0000000000..5bd35a69f2
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-exec.json
@@ -0,0 +1,10 @@
+{
+ "request" : {
+ "mbean" : "java.lang:type=Memory",
+ "operation" : "gc()",
+ "type" : "exec"
+ },
+ "status" : 200,
+ "timestamp" : 1658567003,
+ "value" : null
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-properties-secret.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-properties-secret.json
new file mode 100644
index 0000000000..e12bbd16c1
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-properties-secret.json
@@ -0,0 +1,15 @@
+{
+ "apiVersion": "v1",
+ "data": {
+ "jolokia.properties": "aG9zdD0wLjAuMC4wCnBhc3N3b3JkPXNlY3JldAp1c2VyPWFkbWluCnBvcnQ9ODc3OApkaXNjb3ZlcnlFbmFibGVkPXRydWUKZGlzY292ZXJ5QWdlbnRVcmw9aHR0cDovLyR7aG9zdH06ODc3OC9qb2xva2lhLwpwb2xpY3lMb2NhdGlvbj1jbGFzc3BhdGg6L0JPT1QtSU5GL2NsYXNzZXMvam9sb2tpYS1hY2Nlc3MueG1s"
+ },
+ "kind": "Secret",
+ "metadata": {
+ "creationTimestamp": "2022-05-20T13:59:12Z",
+ "name": "jolokia-properties",
+ "namespace": "jfr",
+ "resourceVersion": "147",
+ "uid": "025bf17a-cff5-46e6-8499-dd9d6de43fa9"
+ },
+ "type": "Opaque"
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-version.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-version.json
new file mode 100644
index 0000000000..6299d0407a
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/jolokia-version.json
@@ -0,0 +1,41 @@
+{
+ "request": {
+ "type": "version"
+ },
+ "value": {
+ "agent": "1.7.1",
+ "protocol": "7.2",
+ "config": {
+ "listenForHttpService": "true",
+ "authIgnoreCerts": "false",
+ "agentId": "192.168.1.104-28660-5bd82fed-servlet",
+ "debug": "false",
+ "agentType": "servlet",
+ "policyLocation": "classpath:\/jolokia-access.xml",
+ "agentContext": "\/jolokia",
+ "serializeException": "false",
+ "mimeType": "text\/plain",
+ "dispatcherClasses": "org.jolokia.http.Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher",
+ "authMode": "basic",
+ "authMatch": "any",
+ "streaming": "true",
+ "canonicalNaming": "true",
+ "historyMaxEntries": "10",
+ "allowErrorDetails": "false",
+ "allowDnsReverseLookup": "true",
+ "realm": "jolokia",
+ "includeStackTrace": "false",
+ "restrictorClass": "io.hawt.system.RBACRestrictor",
+ "mbeanQualifier": "qualifier=hawtio",
+ "useRestrictorService": "false",
+ "debugMaxEntries": "100"
+ },
+ "info": {
+ "product": "jetty",
+ "vendor": "Eclipse",
+ "version": "9.4.z-SNAPSHOT"
+ }
+ },
+ "timestamp": 1658556959,
+ "status": 200
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/memory-list.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/memory-list.json
new file mode 100644
index 0000000000..46d117f2e4
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/memory-list.json
@@ -0,0 +1,46 @@
+{
+ "request" : {
+ "path" : "java.lang/type=Memory",
+ "type" : "list"
+ },
+ "status" : 200,
+ "timestamp" : 1658566168,
+ "value" : {
+ "attr" : {
+ "HeapMemoryUsage" : {
+ "desc" : "HeapMemoryUsage",
+ "rw" : false,
+ "type" : "javax.management.openmbean.CompositeData"
+ },
+ "NonHeapMemoryUsage" : {
+ "desc" : "NonHeapMemoryUsage",
+ "rw" : false,
+ "type" : "javax.management.openmbean.CompositeData"
+ },
+ "ObjectName" : {
+ "desc" : "ObjectName",
+ "rw" : false,
+ "type" : "javax.management.ObjectName"
+ },
+ "ObjectPendingFinalizationCount" : {
+ "desc" : "ObjectPendingFinalizationCount",
+ "rw" : false,
+ "type" : "int"
+ },
+ "Verbose" : {
+ "desc" : "Verbose",
+ "rw" : true,
+ "type" : "boolean"
+ }
+ },
+ "class" : "sun.management.MemoryImpl",
+ "desc" : "Information on the management interface of the MBean",
+ "op" : {
+ "gc" : {
+ "args" : [],
+ "desc" : "gc",
+ "ret" : "void"
+ }
+ }
+ }
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/mock-kube-config.yml b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/mock-kube-config.yml
new file mode 100644
index 0000000000..f222f471a7
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/mock-kube-config.yml
@@ -0,0 +1,17 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: {{request.baseUrl}}/
+ name: test
+contexts:
+- context:
+ cluster: test
+ user: test
+ name: test
+current-context: test
+kind: Config
+preferences: {}
+users:
+- name: test
+ user:
+ token: foobar
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/pod.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/pod.json
new file mode 100644
index 0000000000..77a61a3e32
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/pod.json
@@ -0,0 +1,11 @@
+{
+ "metadata": {
+ "clusterName": "test",
+ "labels": {
+ "jolokia": true
+ },
+ "name": "pod-abcdef",
+ "namespace": "ns1",
+ "selfLink": "/api/v1/namespaces/ns1/pods/pod-abcdef"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/pods.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/pods.json
new file mode 100644
index 0000000000..114edd3640
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/pods.json
@@ -0,0 +1,19 @@
+{
+ "items": [
+ {
+ "metadata": {
+ "clusterName": "test",
+ "labels": {
+ "jolokia": true
+ },
+ "annotations": {
+ "jolokiaPort": 8778,
+ "jolokiaPath": "jolokia"
+ },
+ "name": "pod-abcdef",
+ "namespace": "ns1",
+ "selfLink": "/api/v1/namespaces/ns1/pods/pod-abcdef"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/runtime-list.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/runtime-list.json
new file mode 100644
index 0000000000..c096d78c52
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/runtime-list.json
@@ -0,0 +1,104 @@
+{
+ "request" : {
+ "path" : "java.lang/type=Runtime",
+ "type" : "list"
+ },
+ "status" : 200,
+ "timestamp" : 1658564737,
+ "value" : {
+ "attr" : {
+ "BootClassPath" : {
+ "desc" : "BootClassPath",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "BootClassPathSupported" : {
+ "desc" : "BootClassPathSupported",
+ "rw" : false,
+ "type" : "boolean"
+ },
+ "ClassPath" : {
+ "desc" : "ClassPath",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "InputArguments" : {
+ "desc" : "InputArguments",
+ "rw" : false,
+ "type" : "[Ljava.lang.String;"
+ },
+ "LibraryPath" : {
+ "desc" : "LibraryPath",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "ManagementSpecVersion" : {
+ "desc" : "ManagementSpecVersion",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "Name" : {
+ "desc" : "Name",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "ObjectName" : {
+ "desc" : "ObjectName",
+ "rw" : false,
+ "type" : "javax.management.ObjectName"
+ },
+ "Pid" : {
+ "desc" : "Pid",
+ "rw" : false,
+ "type" : "long"
+ },
+ "SpecName" : {
+ "desc" : "SpecName",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "SpecVendor" : {
+ "desc" : "SpecVendor",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "SpecVersion" : {
+ "desc" : "SpecVersion",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "StartTime" : {
+ "desc" : "StartTime",
+ "rw" : false,
+ "type" : "long"
+ },
+ "SystemProperties" : {
+ "desc" : "SystemProperties",
+ "rw" : false,
+ "type" : "javax.management.openmbean.TabularData"
+ },
+ "Uptime" : {
+ "desc" : "Uptime",
+ "rw" : false,
+ "type" : "long"
+ },
+ "VmName" : {
+ "desc" : "VmName",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "VmVendor" : {
+ "desc" : "VmVendor",
+ "rw" : false,
+ "type" : "java.lang.String"
+ },
+ "VmVersion" : {
+ "desc" : "VmVersion",
+ "rw" : false,
+ "type" : "java.lang.String"
+ }
+ },
+ "class" : "sun.management.RuntimeImpl",
+ "desc" : "Information on the management interface of the MBean"
+ }
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/secrets.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/secrets.json
new file mode 100644
index 0000000000..ac68f94b51
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/secrets.json
@@ -0,0 +1,43 @@
+{
+ "apiVersion": "v1",
+ "items": [
+ {
+ "apiVersion": "v1",
+ "data": {
+ "password": "YWRtaW4=",
+ "username": "YWRtaW4="
+ },
+ "kind": "Secret",
+ "metadata": {
+ "annotations": {
+ "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{},\"name\":\"jolokia-auth\",\"namespace\":\"ns1\"},\"stringData\":{\"password\":\"admin\",\"username\":\"admin\"},\"type\":\"kubernetes.io/basic-auth\"}\n"
+ },
+ "creationTimestamp": "2022-05-20T13:59:12Z",
+ "name": "jolokia-auth",
+ "namespace": "ns1",
+ "resourceVersion": "130",
+ "uid": "e1563217-ef08-481d-b2e3-233fa3040b56"
+ },
+ "type": "kubernetes.io/basic-auth"
+ },
+ {
+ "apiVersion": "v1",
+ "data": {
+ "jolokia.properties": "aG9zdD0wLjAuMC4wCnBhc3N3b3JkPXNlY3JldAp1c2VyPWFkbWluCnBvcnQ9ODc3OApkaXNjb3ZlcnlFbmFibGVkPXRydWUKZGlzY292ZXJ5QWdlbnRVcmw9aHR0cDovLyR7aG9zdH06ODc3OC9qb2xva2lhLwpwb2xpY3lMb2NhdGlvbj1jbGFzc3BhdGg6L0JPT1QtSU5GL2NsYXNzZXMvam9sb2tpYS1hY2Nlc3MueG1s"
+ },
+ "kind": "Secret",
+ "metadata": {
+ "creationTimestamp": "2022-05-20T13:59:12Z",
+ "name": "jolokia-properties",
+ "namespace": "ns1",
+ "resourceVersion": "147",
+ "uid": "025bf17a-cff5-46e6-8499-dd9d6de43fa9"
+ },
+ "type": "Opaque"
+ }
+ ],
+ "kind": "List",
+ "metadata": {
+ "resourceVersion": ""
+ }
+}
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/system-attributes.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/system-attributes.json
new file mode 100644
index 0000000000..dc2ff55433
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/__files/system-attributes.json
@@ -0,0 +1,101 @@
+[
+ {
+ "request" : {
+ "attribute" : "Pid",
+ "mbean" : "java.lang:type=Runtime",
+ "type" : "read"
+ },
+ "status" : 200,
+ "timestamp" : 1658586915,
+ "value" : 88774
+ },
+ {
+ "request" : {
+ "attribute" : "Name",
+ "mbean" : "java.lang:type=Runtime",
+ "type" : "read"
+ },
+ "status" : 200,
+ "timestamp" : 1658586915,
+ "value" : "88774@Martins-MacBook-Pro-2.local"
+ },
+ {
+ "request" : {
+ "attribute" : "InputArguments",
+ "mbean" : "java.lang:type=Runtime",
+ "type" : "read"
+ },
+ "status" : 200,
+ "timestamp" : 1658586915,
+ "value" : []
+ },
+ {
+ "request" : {
+ "attribute" : "SystemProperties",
+ "mbean" : "java.lang:type=Runtime",
+ "type" : "read"
+ },
+ "status" : 200,
+ "timestamp" : 1658586915,
+ "value" : {
+ "apple.awt.application.name" : "App",
+ "file.encoding" : "UTF-8",
+ "file.separator" : "/",
+ "ftp.nonProxyHosts" : "local|*.local|169.254/16|*.169.254/16",
+ "hawtio.authenticationEnabled" : "false",
+ "hawtio.redirect.scheme" : "http",
+ "hawtio.url" : "http://localhost:9090/hawtio",
+ "http.nonProxyHosts" : "local|*.local|169.254/16|*.169.254/16",
+ "java.class.path" : "/Users/marska/Downloads/hawtio-app-2.9.1.jar",
+ "java.class.version" : "62.0",
+ "java.home" : "/Library/Java/JavaVirtualMachines/temurin-18.jdk/Contents/Home",
+ "java.io.tmpdir" : "/var/folders/1f/cdm0073x1mj1swnhtw181_4m0000gn/T/",
+ "java.library.path" : "/Users/marska/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.",
+ "java.runtime.name" : "OpenJDK Runtime Environment",
+ "java.runtime.version" : "18.0.1+10",
+ "java.specification.name" : "Java Platform API Specification",
+ "java.specification.vendor" : "Oracle Corporation",
+ "java.specification.version" : "18",
+ "java.vendor" : "Eclipse Adoptium",
+ "java.vendor.url" : "https://adoptium.net/",
+ "java.vendor.url.bug" : "https://github.com/adoptium/adoptium-support/issues",
+ "java.vendor.version" : "Temurin-18.0.1+10",
+ "java.version" : "18.0.1",
+ "java.version.date" : "2022-04-19",
+ "java.vm.compressedOopsMode" : "Zero based",
+ "java.vm.info" : "mixed mode, sharing",
+ "java.vm.name" : "OpenJDK 64-Bit Server VM",
+ "java.vm.specification.name" : "Java Virtual Machine Specification",
+ "java.vm.specification.vendor" : "Oracle Corporation",
+ "java.vm.specification.version" : "18",
+ "java.vm.vendor" : "Eclipse Adoptium",
+ "java.vm.version" : "18.0.1+10",
+ "jdk.debug" : "release",
+ "line.separator" : "\n",
+ "native.encoding" : "UTF-8",
+ "org.eclipse.jetty.util.log.class" : "org.eclipse.jetty.util.log.Slf4jLog",
+ "os.arch" : "x86_64",
+ "os.name" : "Mac OS X",
+ "os.version" : "11.6.6",
+ "path.separator" : ":",
+ "socksNonProxyHosts" : "local|*.local|169.254/16|*.169.254/16",
+ "sun.arch.data.model" : "64",
+ "sun.awt.enableExtraMouseButtons" : "true",
+ "sun.boot.library.path" : "/Library/Java/JavaVirtualMachines/temurin-18.jdk/Contents/Home/lib",
+ "sun.cpu.endian" : "little",
+ "sun.io.unicode.encoding" : "UnicodeBig",
+ "sun.java.command" : "/Users/marska/Downloads/hawtio-app-2.9.1.jar --port 9090",
+ "sun.java.launcher" : "SUN_STANDARD",
+ "sun.jnu.encoding" : "UTF-8",
+ "sun.management.compiler" : "HotSpot 64-Bit Tiered Compilers",
+ "sun.stderr.encoding" : "UTF-8",
+ "sun.stdout.encoding" : "UTF-8",
+ "user.country" : "NO",
+ "user.dir" : "/Users/marska/Documents/dev/jmc/jmc8/releng/third-party",
+ "user.home" : "/Users/marska",
+ "user.language" : "nb",
+ "user.name" : "marska",
+ "user.timezone" : "Asia/Taipei"
+ }
+ }
+]
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-exec.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-exec.json
new file mode 100644
index 0000000000..6bb03ececf
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-exec.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPath": "/api/v1/namespaces/ns1/pods/pod-abcdef/proxy/jolokia",
+ "bodyPatterns": [
+ {
+ "equalToJson": "{\"operation\":\"gc()\",\"mbean\":\"java.lang:type=Memory\",\"type\":\"EXEC\"}"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "jolokia-exec.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-list-memory.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-list-memory.json
new file mode 100644
index 0000000000..e4170948cb
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-list-memory.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPathPattern": "/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*",
+ "bodyPatterns": [
+ {
+ "equalToJson": "{\"path\":\"java.lang/type=Memory\",\"type\":\"LIST\"}"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "memory-list.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-list-runtime.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-list-runtime.json
new file mode 100644
index 0000000000..f936e7eb0f
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-list-runtime.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPathPattern": "/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*",
+ "bodyPatterns": [
+ {
+ "equalToJson": "{\"path\":\"java.lang/type=Runtime\",\"type\":\"LIST\"}"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "runtime-list.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-probe.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-probe.json
new file mode 100644
index 0000000000..5b26da423d
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-probe.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPathPattern": "/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*",
+ "bodyPatterns": [
+ {
+ "equalToJson": "{\"type\":\"version\"}"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "jolokia-version.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-probe2.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-probe2.json
new file mode 100644
index 0000000000..98670016fd
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-probe2.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPathPattern": "/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*",
+ "bodyPatterns": [
+ {
+ "equalToJson": "{\"type\":\"VERSION\"}"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "jolokia-version.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-read-attribute.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-read-attribute.json
new file mode 100644
index 0000000000..1584e3b4a3
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jolokia-read-attribute.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPathPattern": "/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*",
+ "bodyPatterns": [
+ {
+ "equalToJson": "{\"attribute\":\"Verbose\",\"mbean\":\"java.lang:type=Memory\",\"type\":\"READ\"}"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "jolokia-attribute.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jvm-properties.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jvm-properties.json
new file mode 100644
index 0000000000..5b26da423d
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/jvm-properties.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPathPattern": "/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*",
+ "bodyPatterns": [
+ {
+ "equalToJson": "{\"type\":\"version\"}"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "jolokia-version.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/kube-config.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/kube-config.json
new file mode 100644
index 0000000000..418a887637
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/kube-config.json
@@ -0,0 +1,13 @@
+{
+ "request": {
+ "method": "GET",
+ "url": "/mock-kube-config.yml"
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "mock-kube-config.yml",
+ "transformers": [
+ "response-template"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/pod.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/pod.json
new file mode 100644
index 0000000000..ebcbd7c5e3
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/pod.json
@@ -0,0 +1,10 @@
+{
+ "request": {
+ "method": "GET",
+ "url": "/api/v1/namespaces/ns1/pods/pod-abcdef"
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "pod.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/pods.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/pods.json
new file mode 100644
index 0000000000..061fb0f53b
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/pods.json
@@ -0,0 +1,10 @@
+{
+ "request": {
+ "method": "GET",
+ "urlPath": "/api/v1/pods"
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "pods.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/secrets.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/secrets.json
new file mode 100644
index 0000000000..113bb91e1f
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/secrets.json
@@ -0,0 +1,10 @@
+{
+ "request": {
+ "method": "GET",
+ "url": "/api/v1/namespaces/ns1/secrets"
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "secrets.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/system-attributes.json b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/system-attributes.json
new file mode 100644
index 0000000000..e3d1147b2f
--- /dev/null
+++ b/application/uitests/org.openjdk.jmc.kubernetes.test/src/test/resources/mappings/system-attributes.json
@@ -0,0 +1,15 @@
+{
+ "request": {
+ "method": "POST",
+ "urlPathPattern": "/api/v1/namespaces/ns1/pods/pod-abcdef.*/proxy/jolokia.*",
+ "bodyPatterns": [
+ {
+ "equalToJson": "[{\"attribute\":\"Pid\",\"mbean\":\"java.lang:type=Runtime\",\"type\":\"READ\"},{\"attribute\":\"Name\",\"mbean\":\"java.lang:type=Runtime\",\"type\":\"READ\"},{\"attribute\":\"InputArguments\",\"mbean\":\"java.lang:type=Runtime\",\"type\":\"READ\"},{\"attribute\":\"SystemProperties\",\"mbean\":\"java.lang:type=Runtime\",\"type\":\"READ\"}]"
+ }
+ ]
+ },
+ "response": {
+ "status": 200,
+ "bodyFileName": "system-attributes.json"
+ }
+}
\ No newline at end of file
diff --git a/application/uitests/pom.xml b/application/uitests/pom.xml
index b0015a87ac..d49179b6d1 100644
--- a/application/uitests/pom.xml
+++ b/application/uitests/pom.xml
@@ -58,6 +58,7 @@
org.openjdk.jmc.flightrecorder.uitest
org.openjdk.jmc.rcp.application.uitest
org.openjdk.jmc.test.jemmy
+ org.openjdk.jmc.kubernetes.test
diff --git a/releng/platform-definitions/platform-definition-2024-06/platform-definition-2024-06.target b/releng/platform-definitions/platform-definition-2024-06/platform-definition-2024-06.target
index 727a31350e..a32e9b73ef 100644
--- a/releng/platform-definitions/platform-definition-2024-06/platform-definition-2024-06.target
+++ b/releng/platform-definitions/platform-definition-2024-06/platform-definition-2024-06.target
@@ -45,9 +45,10 @@
-
-
-
+
+
+
+
diff --git a/releng/platform-definitions/platform-definition-2024-09/platform-definition-2024-09.target b/releng/platform-definitions/platform-definition-2024-09/platform-definition-2024-09.target
index 09b3673dad..75708de824 100644
--- a/releng/platform-definitions/platform-definition-2024-09/platform-definition-2024-09.target
+++ b/releng/platform-definitions/platform-definition-2024-09/platform-definition-2024-09.target
@@ -45,9 +45,10 @@
-
-
-
+
+
+
+
diff --git a/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target b/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target
index 892bf86362..98d50bf518 100644
--- a/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target
+++ b/releng/platform-definitions/platform-definition-2024-12/platform-definition-2024-12.target
@@ -45,9 +45,10 @@
-
-
-
+
+
+
+
diff --git a/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target b/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target
index 6cb9735a7a..4959312ec1 100644
--- a/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target
+++ b/releng/platform-definitions/platform-definition-2025-03/platform-definition-2025-03.target
@@ -45,9 +45,10 @@
-
-
-
+
+
+
+
diff --git a/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target b/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target
index c0b1bd6ab4..ecbcae5797 100644
--- a/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target
+++ b/releng/platform-definitions/platform-definition-2025-06/platform-definition-2025-06.target
@@ -45,9 +45,10 @@
-
-
-
+
+
+
+
diff --git a/releng/third-party/pom.xml b/releng/third-party/pom.xml
index a5357f08cc..51b24b210d 100644
--- a/releng/third-party/pom.xml
+++ b/releng/third-party/pom.xml
@@ -61,7 +61,7 @@
2.0.0
12.0.21
1.3.7
- 2.0.2
+ 2.2.9
2.27.2
0.0.1-rc.9
7.5.0
@@ -177,6 +177,13 @@
org.osgi:org.osgi.service.servlet:2.0.0
+
+ org.jolokia:jolokia-client-kubernetes:jar:standalone:${jolokia.version}
+ false
+
+
+ org.awaitility:awaitility:4.0.0
+
com.github.tomakehurst:wiremock-standalone:${wiremock.version}
false