From 891254d8425034f1c1d92bf34e704ce5a921f024 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 19:27:12 -0400 Subject: [PATCH] chore(discovery): remove kubeenv discovery plugin (#1475) (#1476) * chore(discovery): remove kubeenv discovery plugin * fixup! chore(discovery): remove kubeenv discovery plugin * update README (cherry picked from commit 7b83be5d1e333d1e55e777df214ebb989a52e8cc) Co-authored-by: Andrew Azores --- README.md | 36 ++- .../platform/discovery/AbstractNode.java | 4 +- .../internal/KubeEnvPlatformClient.java | 153 ----------- .../internal/KubeEnvPlatformStrategy.java | 105 -------- .../internal/PlatformStrategyModule.java | 1 - .../internal/KubeEnvPlatformClientTest.java | 239 ------------------ 6 files changed, 18 insertions(+), 520 deletions(-) delete mode 100644 src/main/java/io/cryostat/platform/internal/KubeEnvPlatformClient.java delete mode 100644 src/main/java/io/cryostat/platform/internal/KubeEnvPlatformStrategy.java delete mode 100644 src/test/java/io/cryostat/platform/internal/KubeEnvPlatformClientTest.java diff --git a/README.md b/README.md index e0ff73b2d4..3be7912fa2 100644 --- a/README.md +++ b/README.md @@ -128,12 +128,12 @@ Cryostat can be configured via the following environment variables: * `CRYOSTAT_CORS_ORIGIN`: the origin for CORS to load a different cryostat-web instance. Defaults to the empty string, which disables CORS. * `CRYOSTAT_MAX_WS_CONNECTIONS`: the maximum number of websocket client connections allowed (minimum 1, maximum `Integer.MAX_VALUE`, default `Integer.MAX_VALUE`) * `CRYOSTAT_AUTH_MANAGER`: the authentication/authorization manager used for validating user accesses. See the `USER AUTHENTICATION / AUTHORIZATION` section for more details. Set to the fully-qualified class name of the auth manager implementation to use, ex. `io.cryostat.net.BasicAuthManager`. Defaults to an AuthManager corresponding to the selected deployment platform, whether explicit or automatic (see below). -* `CRYOSTAT_PLATFORM`: the platform clients used for performing platform-specific actions, such as listing available target JVMs. If `CRYOSTAT_AUTH_MANAGER` is not specified then a default auth manager will also be selected corresponding to the highest priority platform, whether those platforms are specified by the user or automatically detected. Set to the fully-qualified names of the platform detection strategy implementations to use, ex. `io.cryostat.platform.internal.KubeEnvPlatformStrategy,io.cryostat.platform.internal.PodmanPlatformStrategy`. +* `CRYOSTAT_PLATFORM`: the platform clients used for performing platform-specific actions, such as listing available target JVMs. If `CRYOSTAT_AUTH_MANAGER` is not specified then a default auth manager will also be selected corresponding to the highest priority platform, whether those platforms are specified by the user or automatically detected. Set to the fully-qualified names of the platform detection strategy implementations to use, ex. `io.cryostat.platform.internal.KubeApiPlatformStrategy,io.cryostat.platform.internal.PodmanPlatformStrategy`. * `CRYOSTAT_ENABLE_JDP_BROADCAST`: enable the Cryostat JVM to broadcast itself via JDP (Java Discovery Protocol). Defaults to `true`. * `CRYOSTAT_JDP_ADDRESS`: the JDP multicast address to send discovery packets. Defaults to `224.0.23.178`. * `CRYOSTAT_JDP_PORT`: the JDP multicast port to send discovery packets. Defaults to `7095`. * `CRYOSTAT_CONFIG_PATH`: the filesystem path for the configuration directory. Defaults to `/opt/cryostat.d/conf.d`. -* `CRYOSTAT_DISABLE_BUILTIN_DISCOVERY`: set to `true` to disable built-in target discovery mechanisms (see `CRYOSTAT_PLATFORM`). Custom Target "discovery" remains available, but discovery via JDP, Kubernetes API, or Kubernetes environment variable is disabled and ignored. This will still allow platform detection to automatically select an `AuthManager`. This is intended for use when Cryostat Discovery Plugins are the only desired mechanism for locating target applications. See #936 and [cryostat-agent](https://github.com/cryostatio/cryostat-agent). Defaults to `false`. +* `CRYOSTAT_DISABLE_BUILTIN_DISCOVERY`: set to `true` to disable built-in target discovery mechanisms (see `CRYOSTAT_PLATFORM`). Custom Target "discovery" remains available, but discovery via JDP, Kubernetes API, or Podman API is disabled and ignored. This will still allow platform detection to automatically select an `AuthManager`. This is intended for use when Cryostat Discovery Plugins are the only desired mechanism for locating target applications. See #936 and [cryostat-agent](https://github.com/cryostatio/cryostat-agent). Defaults to `false`. * `CRYOSTAT_K8S_NAMESPACES`: set to a comma-separated list of Namespaces that Cryostat should query to discover target JVM applications with its built-in discovey mechanism. #### Configuration for Automated Analysis Reports @@ -181,36 +181,34 @@ overridden with `1`. ## MONITORING APPLICATIONS In order for `cryostat` to be able to monitor JVM application targets the -targets must have RJMX enabled. `cryostat` has several strategies for -automatic discovery of potential targets. Each strategy will be tested in order -until a working strategy is found. +targets must have RJMX enabled or have the Cryostat Agent installed and +configured. `cryostat` has several strategies for automatic discovery of +potential targets. -The primary target discovery mechanism uses the OpenShift/Kubernetes API to list +The first target discovery mechanism uses the OpenShift/Kubernetes API to list service endpoints and expose all discovered services as potential targets. This is runtime dynamic, allowing `cryostat` to discover new services which come online after `cryostat`, or to detect when known services disappear later. This requires the `cryostat` pod to have authorization to list services within its own namespace. -The secondary target discovery mechanism is based on Kubernetes environment -variable service discovery. In this mode, environment variables available to -`cryostat` (note: environment variables are set once at process creation - -this implies that this method of service discovery is *static* after startup) -are examined for the form `FOO_PORT_1234_TCP_ADDR=127.0.0.1`. Such an -environment variable will cause the discovery of a target at address -`127.0.0.1`, aliased as `foo`, listening on port `1234`. - -Finally, if no supported platform is detected, then `cryostat` will fall -back to the JDP (Java Discovery Protocol) mechanism. This relies on target JVMs -being configured with the JVM flags to enable JDP and requires the targets to -be reachable and in the same subnet as `cryostat`. JDP can be enabled by -passing the flag `"-Dcom.sun.management.jmxremote.autodiscovery=true"` when +The second discovery mechanism is JDP (Java Discovery Protocol). This relies on +target JVMs being configured with the JVM flags to enable JDP and requires the +targets to be reachable and in the same subnet as `cryostat`. JDP can be enabled +by passing the flag `"-Dcom.sun.management.jmxremote.autodiscovery=true"` when starting target JVMs; for more configuration options, see [this document](https://docs.oracle.com/javase/10/management/java-discovery-protocol.htm) . Once the targets are properly configured, `cryostat` will automatically discover their JMX Service URLs, which includes the RJMX port number for that specific target. +The third discovery mechanism is the Podman API. If the Podman API socket is +available at its default filesystem location then Cryostat will query the +`libpod/containers` endpoint to determine what target applications may be +available. Containers must have the Podman label `io.cryostat.connectUrl` +applied, and the value should be the remote JMX or Cryostat Agent HTTP +connection URL that Cryostat can use to communicate with the target. + To enable RJMX on port 9091, the following JVM flag should be passed at target startup: diff --git a/src/main/java/io/cryostat/platform/discovery/AbstractNode.java b/src/main/java/io/cryostat/platform/discovery/AbstractNode.java index 9d966c7fad..4eee3baf23 100644 --- a/src/main/java/io/cryostat/platform/discovery/AbstractNode.java +++ b/src/main/java/io/cryostat/platform/discovery/AbstractNode.java @@ -44,7 +44,6 @@ import io.cryostat.platform.internal.CustomTargetPlatformClient; import io.cryostat.platform.internal.DefaultPlatformClient; import io.cryostat.platform.internal.KubeApiPlatformClient; -import io.cryostat.platform.internal.KubeEnvPlatformClient; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; @@ -101,8 +100,7 @@ public RealmOrder getRealmOrder() { if (nodeType.getKind().equals(BaseNodeType.REALM.getKind())) { if (name.equalsIgnoreCase(DefaultPlatformClient.REALM)) { return RealmOrder.JDP; - } else if (name.equalsIgnoreCase(KubeApiPlatformClient.REALM) - || name.equalsIgnoreCase(KubeEnvPlatformClient.REALM)) { + } else if (name.equalsIgnoreCase(KubeApiPlatformClient.REALM)) { return RealmOrder.KUBE; } else if (name.equalsIgnoreCase(CustomTargetPlatformClient.REALM)) { return RealmOrder.CUSTOM; diff --git a/src/main/java/io/cryostat/platform/internal/KubeEnvPlatformClient.java b/src/main/java/io/cryostat/platform/internal/KubeEnvPlatformClient.java deleted file mode 100644 index fcf7450ff1..0000000000 --- a/src/main/java/io/cryostat/platform/internal/KubeEnvPlatformClient.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright The Cryostat Authors - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or data - * (collectively the "Software"), free of charge and under any and all copyright - * rights in the Software, and any and all patent rights owned or freely - * licensable by each licensor hereunder covering either (i) the unmodified - * Software as contributed to or provided by such licensor, or (ii) the Larger - * Works (as defined below), to deal in both - * - * (a) the Software, and - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software (each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * The above copyright notice and either this complete permission notice or at - * a minimum a reference to the UPL must be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package io.cryostat.platform.internal; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import io.cryostat.core.log.Logger; -import io.cryostat.core.net.JFRConnectionToolkit; -import io.cryostat.core.sys.Environment; -import io.cryostat.platform.AbstractPlatformClient; -import io.cryostat.platform.ServiceRef; -import io.cryostat.platform.ServiceRef.AnnotationKey; -import io.cryostat.platform.discovery.BaseNodeType; -import io.cryostat.platform.discovery.EnvironmentNode; -import io.cryostat.platform.discovery.NodeType; -import io.cryostat.platform.discovery.TargetNode; -import io.cryostat.util.URIUtil; - -import dagger.Lazy; - -public class KubeEnvPlatformClient extends AbstractPlatformClient { - - public static final String REALM = "KubernetesEnv"; - private static final Pattern SERVICE_ENV_PATTERN = - Pattern.compile("([\\S]+)_PORT_([\\d]+)_TCP_ADDR"); - private final String namespace; - private final Lazy connectionToolkit; - private final Environment env; - private final Logger logger; - - KubeEnvPlatformClient( - String namespace, - Lazy connectionToolkit, - Environment env, - Logger logger) { - this.namespace = namespace; - this.connectionToolkit = connectionToolkit; - this.env = env; - this.logger = logger; - } - - @Override - public void start() throws IOException {} - - @Override - public List listDiscoverableServices() { - return env.getEnv().entrySet().stream() - .map(this::envToServiceRef) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - @Override - public EnvironmentNode getDiscoveryTree() { - List targets = - listDiscoverableServices().stream() - .map(sr -> new TargetNode(KubernetesNodeType.SERVICE, sr)) - .toList(); - return new EnvironmentNode(REALM, BaseNodeType.REALM, Collections.emptyMap(), targets); - } - - private ServiceRef envToServiceRef(Map.Entry entry) { - Matcher matcher = SERVICE_ENV_PATTERN.matcher(entry.getKey()); - if (!matcher.matches()) { - return null; - } - String alias = matcher.group(1).toLowerCase(); - int port = Integer.parseInt(matcher.group(2)); - try { - ServiceRef sr = - new ServiceRef( - null, - URIUtil.convert( - connectionToolkit - .get() - .createServiceURL(entry.getValue(), port)), - alias); - sr.setCryostatAnnotations( - Map.of( - AnnotationKey.REALM, REALM, - AnnotationKey.NAMESPACE, namespace, - AnnotationKey.SERVICE_NAME, alias, - AnnotationKey.PORT, Integer.toString(port))); - return sr; - } catch (Exception e) { - logger.warn(e); - return null; - } - } - - public enum KubernetesNodeType implements NodeType { - SERVICE("Service"), - ; - - private final String kind; - - KubernetesNodeType(String kind) { - this.kind = kind; - } - - @Override - public String getKind() { - return kind; - } - - @Override - public String toString() { - return getKind(); - } - } -} diff --git a/src/main/java/io/cryostat/platform/internal/KubeEnvPlatformStrategy.java b/src/main/java/io/cryostat/platform/internal/KubeEnvPlatformStrategy.java deleted file mode 100644 index 32468bfe1c..0000000000 --- a/src/main/java/io/cryostat/platform/internal/KubeEnvPlatformStrategy.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright The Cryostat Authors - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or data - * (collectively the "Software"), free of charge and under any and all copyright - * rights in the Software, and any and all patent rights owned or freely - * licensable by each licensor hereunder covering either (i) the unmodified - * Software as contributed to or provided by such licensor, or (ii) the Larger - * Works (as defined below), to deal in both - * - * (a) the Software, and - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software (each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * The above copyright notice and either this complete permission notice or at - * a minimum a reference to the UPL must be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package io.cryostat.platform.internal; - -import java.io.IOException; -import java.nio.file.Paths; - -import io.cryostat.core.log.Logger; -import io.cryostat.core.net.JFRConnectionToolkit; -import io.cryostat.core.sys.Environment; -import io.cryostat.core.sys.FileSystem; -import io.cryostat.net.AuthManager; - -import dagger.Lazy; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.fabric8.kubernetes.client.Config; - -class KubeEnvPlatformStrategy implements PlatformDetectionStrategy { - - private final Lazy connectionToolkit; - private final Logger logger; - private final FileSystem fs; - private final Lazy authMgr; - private final Environment env; - - KubeEnvPlatformStrategy( - Logger logger, - FileSystem fs, - Lazy authMgr, - Lazy connectionToolkit, - Environment env) { - this.logger = logger; - this.fs = fs; - this.authMgr = authMgr; - this.connectionToolkit = connectionToolkit; - this.env = env; - } - - @Override - public int getPriority() { - return PRIORITY_PLATFORM; - } - - @Override - public boolean isAvailable() { - logger.trace("Testing KubeEnv Platform Availability"); - return env.getEnv().keySet().stream().anyMatch(s -> s.equals("KUBERNETES_SERVICE_HOST")); - } - - @Override - public KubeEnvPlatformClient getPlatformClient() { - logger.info("Selected KubeEnv Platform Strategy"); - return new KubeEnvPlatformClient(getNamespace(), connectionToolkit, env, logger); - } - - @Override - public AuthManager getAuthManager() { - return authMgr.get(); - } - - @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME") - private String getNamespace() { - try { - return fs.readString(Paths.get(Config.KUBERNETES_NAMESPACE_PATH)); - } catch (IOException e) { - logger.trace(e); - return null; - } - } -} diff --git a/src/main/java/io/cryostat/platform/internal/PlatformStrategyModule.java b/src/main/java/io/cryostat/platform/internal/PlatformStrategyModule.java index 5507084250..1271116d20 100644 --- a/src/main/java/io/cryostat/platform/internal/PlatformStrategyModule.java +++ b/src/main/java/io/cryostat/platform/internal/PlatformStrategyModule.java @@ -74,7 +74,6 @@ static Set> providePlatformDetectionStrategies( new OpenShiftPlatformStrategy( logger, openShiftAuthManager, connectionToolkit, env, fs), new KubeApiPlatformStrategy(logger, noopAuthManager, connectionToolkit, env, fs), - new KubeEnvPlatformStrategy(logger, fs, noopAuthManager, connectionToolkit, env), new PodmanPlatformStrategy(logger, noopAuthManager, vertx, gson, fs), new DefaultPlatformStrategy( logger, noopAuthManager, () -> new JvmDiscoveryClient(logger))); diff --git a/src/test/java/io/cryostat/platform/internal/KubeEnvPlatformClientTest.java b/src/test/java/io/cryostat/platform/internal/KubeEnvPlatformClientTest.java deleted file mode 100644 index e177d0c553..0000000000 --- a/src/test/java/io/cryostat/platform/internal/KubeEnvPlatformClientTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright The Cryostat Authors - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or data - * (collectively the "Software"), free of charge and under any and all copyright - * rights in the Software, and any and all patent rights owned or freely - * licensable by each licensor hereunder covering either (i) the unmodified - * Software as contributed to or provided by such licensor, or (ii) the Larger - * Works (as defined below), to deal in both - * - * (a) the Software, and - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software (each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * The above copyright notice and either this complete permission notice or at - * a minimum a reference to the UPL must be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package io.cryostat.platform.internal; - -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import javax.management.remote.JMXServiceURL; - -import io.cryostat.core.log.Logger; -import io.cryostat.core.net.JFRConnectionToolkit; -import io.cryostat.core.sys.Environment; -import io.cryostat.platform.ServiceRef; -import io.cryostat.platform.ServiceRef.AnnotationKey; -import io.cryostat.platform.discovery.AbstractNode; -import io.cryostat.platform.discovery.BaseNodeType; -import io.cryostat.platform.discovery.EnvironmentNode; -import io.cryostat.recordings.JvmIdHelper.JvmIdGetException; -import io.cryostat.util.URIUtil; - -import org.hamcrest.Matcher; -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.stubbing.Answer; - -@ExtendWith(MockitoExtension.class) -class KubeEnvPlatformClientTest { - - KubeEnvPlatformClient client; - final String namespace = "mynamespace"; - @Mock JFRConnectionToolkit connectionToolkit; - @Mock Environment env; - @Mock Logger logger; - - @BeforeEach - void setup() { - client = new KubeEnvPlatformClient(namespace, () -> connectionToolkit, env, logger); - } - - @Nested - class DiscoverableServicesTests { - - @Test - void shouldDiscoverNoServicesIfEnvsEmpty() { - when(env.getEnv()).thenReturn(Collections.emptyMap()); - MatcherAssert.assertThat(client.listDiscoverableServices(), Matchers.empty()); - verifyNoMoreInteractions(env); - } - - @Test - void shouldDiscoverNoServicesIfEnvsNotRelevant() { - when(env.getEnv()).thenReturn(Collections.singletonMap("SOME_OTHER_ENV", "127.0.0.1")); - MatcherAssert.assertThat(client.listDiscoverableServices(), Matchers.empty()); - verifyNoMoreInteractions(env); - } - - @Test - void shouldDiscoverServicesByEnv() - throws MalformedURLException, URISyntaxException, JvmIdGetException { - when(env.getEnv()) - .thenReturn( - Map.of( - "FOO_PORT_1234_TCP_ADDR", "127.0.0.1", - "BAR_PORT_9999_TCP_ADDR", "1.2.3.4", - "BAZ_PORT_9876_UDP_ADDR", "5.6.7.8")); - - Mockito.when(connectionToolkit.createServiceURL(Mockito.anyString(), Mockito.anyInt())) - .thenAnswer( - new Answer<>() { - @Override - public JMXServiceURL answer(InvocationOnMock args) - throws Throwable { - String host = args.getArgument(0); - int port = args.getArgument(1); - return new JMXServiceURL( - "rmi", - "", - 0, - "/jndi/rmi://" + host + ":" + port + "/jmxrmi"); - } - }); - - ServiceRef serv1 = - new ServiceRef( - null, - URIUtil.convert(connectionToolkit.createServiceURL("127.0.0.1", 1234)), - "foo"); - serv1.setCryostatAnnotations( - Map.of( - AnnotationKey.REALM, "KubernetesEnv", - AnnotationKey.SERVICE_NAME, "foo", - AnnotationKey.NAMESPACE, namespace, - AnnotationKey.PORT, "1234")); - ServiceRef serv2 = - new ServiceRef( - null, - URIUtil.convert(connectionToolkit.createServiceURL("1.2.3.4", 9999)), - "bar"); - serv2.setCryostatAnnotations( - Map.of( - AnnotationKey.REALM, "KubernetesEnv", - AnnotationKey.SERVICE_NAME, "bar", - AnnotationKey.NAMESPACE, namespace, - AnnotationKey.PORT, "9999")); - - List services = client.listDiscoverableServices(); - - MatcherAssert.assertThat(services, Matchers.containsInAnyOrder(serv1, serv2)); - MatcherAssert.assertThat(services, Matchers.hasSize(2)); - verifyNoMoreInteractions(env); - } - - @Test - void shouldDiscoverServicesAsTree() - throws MalformedURLException, URISyntaxException, JvmIdGetException { - when(env.getEnv()) - .thenReturn( - Map.of( - "FOO_PORT_1234_TCP_ADDR", "127.0.0.1", - "BAR_PORT_9999_TCP_ADDR", "1.2.3.4", - "BAZ_PORT_9876_UDP_ADDR", "5.6.7.8")); - Mockito.when(connectionToolkit.createServiceURL(Mockito.anyString(), Mockito.anyInt())) - .thenAnswer( - new Answer<>() { - @Override - public JMXServiceURL answer(InvocationOnMock args) - throws Throwable { - String host = args.getArgument(0); - int port = args.getArgument(1); - return new JMXServiceURL( - "rmi", - "", - 0, - "/jndi/rmi://" + host + ":" + port + "/jmxrmi"); - } - }); - - ServiceRef serv1 = - new ServiceRef( - null, - URIUtil.convert(connectionToolkit.createServiceURL("127.0.0.1", 1234)), - "foo"); - serv1.setCryostatAnnotations( - Map.of( - AnnotationKey.REALM, "KubernetesEnv", - AnnotationKey.SERVICE_NAME, "foo", - AnnotationKey.NAMESPACE, namespace, - AnnotationKey.PORT, "1234")); - ServiceRef serv2 = - new ServiceRef( - null, - URIUtil.convert(connectionToolkit.createServiceURL("1.2.3.4", 9999)), - "bar"); - serv2.setCryostatAnnotations( - Map.of( - AnnotationKey.REALM, "KubernetesEnv", - AnnotationKey.SERVICE_NAME, "bar", - AnnotationKey.NAMESPACE, namespace, - AnnotationKey.PORT, "9999")); - - EnvironmentNode realmNode = client.getDiscoveryTree(); - - MatcherAssert.assertThat(realmNode.getName(), Matchers.equalTo("KubernetesEnv")); - MatcherAssert.assertThat(realmNode.getNodeType(), Matchers.equalTo(BaseNodeType.REALM)); - MatcherAssert.assertThat(realmNode.getLabels().size(), Matchers.equalTo(0)); - MatcherAssert.assertThat(realmNode.getChildren(), Matchers.hasSize(2)); - - Matcher sr1Matcher = - Matchers.allOf( - Matchers.hasProperty( - "name", Matchers.equalTo(serv1.getServiceUri().toString())), - Matchers.hasProperty( - "nodeType", - Matchers.equalTo( - KubeEnvPlatformClient.KubernetesNodeType.SERVICE)), - Matchers.hasProperty("target", Matchers.equalTo(serv1))); - Matcher sr2Matcher = - Matchers.allOf( - Matchers.hasProperty( - "name", Matchers.equalTo(serv2.getServiceUri().toString())), - Matchers.hasProperty( - "nodeType", - Matchers.equalTo( - KubeEnvPlatformClient.KubernetesNodeType.SERVICE)), - Matchers.hasProperty("target", Matchers.equalTo(serv2))); - MatcherAssert.assertThat( - realmNode.getChildren(), Matchers.hasItems(sr1Matcher, sr2Matcher)); - } - } -}