Skip to content

Commit 1619595

Browse files
committed
wip
1 parent 5a82aac commit 1619595

File tree

5 files changed

+446
-0
lines changed

5 files changed

+446
-0
lines changed

jmx-scrapper/build.gradle.kts

+24
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,22 @@ dependencies {
1919
implementation("io.opentelemetry:opentelemetry-sdk-testing")
2020

2121
implementation("io.opentelemetry.instrumentation:opentelemetry-jmx-metrics")
22+
23+
}
24+
25+
testing {
26+
suites {
27+
val integrationTest by registering(JvmTestSuite::class) {
28+
dependencies {
29+
implementation("org.testcontainers:junit-jupiter")
30+
implementation("org.slf4j:slf4j-simple")
31+
}
32+
}
33+
}
2234
}
2335

2436
tasks {
37+
2538
shadowJar {
2639
mergeServiceFiles()
2740

@@ -38,7 +51,9 @@ tasks {
3851

3952
withType<Test>().configureEach {
4053
dependsOn(shadowJar)
54+
dependsOn(named("appJar"))
4155
systemProperty("shadow.jar.path", shadowJar.get().archiveFile.get().asFile.absolutePath)
56+
systemProperty("app.jar.path", named<Jar>("appJar").get().archiveFile.get().asFile.absolutePath)
4257
systemProperty("gradle.project.version", "${project.version}")
4358
}
4459

@@ -50,6 +65,15 @@ tasks {
5065
}
5166
}
5267

68+
tasks.register<Jar>("appJar") {
69+
from(sourceSets.get("integrationTest").output)
70+
archiveClassifier.set("app")
71+
manifest {
72+
attributes["Main-Class"] = "io.opentelemetry.contrib.jmxscraper.TestApp"
73+
}
74+
}
75+
76+
5377
// Don't publish non-shadowed jar (shadowJar is in shadowRuntimeElements)
5478
with(components["java"] as AdhocComponentWithVariants) {
5579
configurations.forEach {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package io.opentelemetry.contrib.jmxscraper;
2+
3+
import java.io.IOException;
4+
import java.net.MalformedURLException;
5+
import java.security.Provider;
6+
import java.security.Security;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
import javax.management.remote.JMXConnector;
10+
import javax.management.remote.JMXConnectorFactory;
11+
import javax.management.remote.JMXServiceURL;
12+
import javax.security.auth.callback.Callback;
13+
import javax.security.auth.callback.CallbackHandler;
14+
import javax.security.auth.callback.NameCallback;
15+
import javax.security.auth.callback.PasswordCallback;
16+
import javax.security.auth.callback.UnsupportedCallbackException;
17+
import javax.security.sasl.RealmCallback;
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
20+
21+
public class JmxRemoteClient {
22+
23+
private static final Logger logger = LoggerFactory.getLogger(JmxRemoteClient.class);
24+
25+
private final String host;
26+
private final int port;
27+
private String userName;
28+
private String password;
29+
private String profile;
30+
private String realm;
31+
private boolean sslRegistry;
32+
33+
private JmxRemoteClient(String host, int port) {
34+
this.host = host;
35+
this.port = port;
36+
}
37+
38+
public static JmxRemoteClient createNew(String host, int port) {
39+
return new JmxRemoteClient(host, port);
40+
}
41+
42+
public JmxRemoteClient userCredentials(String userName, String password) {
43+
this.userName = userName;
44+
this.password = password;
45+
return this;
46+
}
47+
48+
public JmxRemoteClient withRemoteProfile(String profile) {
49+
this.profile = profile;
50+
return this;
51+
}
52+
53+
public JmxRemoteClient withRealm(String realm) {
54+
this.realm = realm;
55+
return this;
56+
}
57+
58+
public JmxRemoteClient withSSLRegistry() {
59+
this.sslRegistry = true;
60+
return this;
61+
}
62+
63+
public JMXConnector connect() throws IOException {
64+
Map<String, Object> env = new HashMap<>();
65+
if (userName != null && password != null) {
66+
env.put(JMXConnector.CREDENTIALS, new String[] {userName, password});
67+
}
68+
69+
if (profile != null) {
70+
env.put("jmx.remote.profile", profile);
71+
}
72+
73+
try {
74+
// Not all supported versions of Java contain this Provider
75+
Class<?> klass = Class.forName("com.sun.security.sasl.Provider");
76+
Provider provider = (Provider) klass.getDeclaredConstructor().newInstance();
77+
Security.addProvider(provider);
78+
79+
env.put(
80+
"jmx.remote.sasl.callback.handler",
81+
(CallbackHandler) callbacks -> {
82+
for (Callback callback : callbacks) {
83+
if (callback instanceof NameCallback) {
84+
((NameCallback) callback).setName(userName);
85+
} else if (callback instanceof PasswordCallback) {
86+
char[] pwd = password == null ? null : password.toCharArray();
87+
((PasswordCallback) callback).setPassword(pwd);
88+
} else if (callback instanceof RealmCallback) {
89+
((RealmCallback) callback).setText(realm);
90+
} else {
91+
throw new UnsupportedCallbackException(callback);
92+
}
93+
}
94+
});
95+
} catch (final ReflectiveOperationException e) {
96+
logger.warn("SASL unsupported in current environment: " + e.getMessage(), e);
97+
}
98+
99+
JMXServiceURL url = buildUrl(host, port);
100+
try {
101+
if (sslRegistry) {
102+
return connectSSLRegistry(url, env);
103+
} else {
104+
return JMXConnectorFactory.connect(url, env);
105+
}
106+
} catch (IOException e) {
107+
throw new IOException("Unable to connect to " + url.getHost() + ":" + url.getPort(), e);
108+
}
109+
}
110+
111+
public JMXConnector connectSSLRegistry(JMXServiceURL url, Map<String, Object> env) {
112+
throw new IllegalStateException("TODO");
113+
}
114+
115+
private static JMXServiceURL buildUrl(String host, int port) {
116+
StringBuilder sb = new StringBuilder("service:jmx:rmi:///jndi/rmi://");
117+
if (host != null) {
118+
sb.append(host);
119+
}
120+
sb.append(":")
121+
.append(port)
122+
.append("/jmxrmi");
123+
124+
try {
125+
return new JMXServiceURL(sb.toString());
126+
} catch (MalformedURLException e) {
127+
throw new IllegalArgumentException("invalid url", e);
128+
}
129+
}
130+
131+
}

0 commit comments

Comments
 (0)