From ca9398b5ebca517008d7f5c6f1c18b4e4c1cc751 Mon Sep 17 00:00:00 2001 From: Carsten Lohmann Date: Tue, 19 Sep 2023 07:45:14 +0200 Subject: [PATCH 1/4] Use random string instead of container ID in Kafka client id. Reliably getting the container ID is too expensive. Having the K8s pod name in the Kafka client id should be enough in most cases to associate a client id with the place where it is used. Signed-off-by: Carsten Lohmann --- .../kafka/AbstractKafkaConfigProperties.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/clients/kafka-common/src/main/java/org/eclipse/hono/client/kafka/AbstractKafkaConfigProperties.java b/clients/kafka-common/src/main/java/org/eclipse/hono/client/kafka/AbstractKafkaConfigProperties.java index c1fb70091d..a2a100bc8e 100644 --- a/clients/kafka-common/src/main/java/org/eclipse/hono/client/kafka/AbstractKafkaConfigProperties.java +++ b/clients/kafka-common/src/main/java/org/eclipse/hono/client/kafka/AbstractKafkaConfigProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -21,7 +21,6 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.kafka.clients.CommonClientConfigs; -import org.eclipse.hono.util.KubernetesContainerUtil; import org.eclipse.hono.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +32,8 @@ public abstract class AbstractKafkaConfigProperties { private static final AtomicInteger ID_COUNTER = new AtomicInteger(); + private static final String COMPONENT_UID_DEFAULT = getK8sComponentUId(); + /** * A logger to be shared with subclasses. */ @@ -50,15 +51,15 @@ public abstract class AbstractKafkaConfigProperties { * Creates a new instance. */ protected AbstractKafkaConfigProperties() { - this.componentUId = getComponentUIdFromEnv(); + this.componentUId = COMPONENT_UID_DEFAULT; } - private String getComponentUIdFromEnv() { - final String k8sContainerId = KubernetesContainerUtil.getContainerId(); - if (k8sContainerId != null && k8sContainerId.length() >= 12) { + private static String getK8sComponentUId() { + if (System.getenv("KUBERNETES_SERVICE_HOST") != null) { // running in Kubernetes: use HOSTNAME env var containing the pod name final String podName = System.getenv("HOSTNAME"); - return String.format("%s_%s", podName, k8sContainerId.substring(0, 12)); + final String random = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 12); + return String.format("%s_%s", podName, random); } return null; } @@ -88,7 +89,7 @@ protected final void setSpecificClientConfig(final Map specificC * Sets the component unique ID to be included in the client ID along with a counter value. *

* This overrides the unique ID determined automatically in case this application is running in Kubernetes - * (consisting of Pod/Container ID then). + * (containing the Pod name then). *

* Setting {@code null} here means that a UUID will be used in the client ID instead of component unique ID and * counter value. @@ -133,7 +134,7 @@ public String getBootstrapServers() { * has been applied. *

* It is ensured that the returned map contains a unique {@code client.id}. The client ID will be created from the - * given client name, followed by a unique ID (containing component identifiers if running in Kubernetes). + * given client name, followed by a unique ID (containing a component identifier if running in Kubernetes). * An already set {@code client.id} property value will be used as prefix for the client ID. * * @param clientName A name for the client to include in the added {@code client.id} property. From 4668baadf7252c5c9242de14fd89cf8396e81c66 Mon Sep 17 00:00:00 2001 From: Carsten Lohmann Date: Tue, 19 Sep 2023 07:46:41 +0200 Subject: [PATCH 2/4] Rename KubernetesContainerUtil to CgroupV1KubernetesContainerUtil. Signed-off-by: Carsten Lohmann --- ...java => CgroupV1KubernetesContainerUtil.java} | 16 ++++++++-------- .../org/eclipse/hono/util/CommandConstants.java | 2 +- ... => CgroupV1KubernetesContainerUtilTest.java} | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) rename core/src/main/java/org/eclipse/hono/util/{KubernetesContainerUtil.java => CgroupV1KubernetesContainerUtil.java} (86%) rename core/src/test/java/org/eclipse/hono/util/{KubernetesContainerUtilTest.java => CgroupV1KubernetesContainerUtilTest.java} (82%) diff --git a/core/src/main/java/org/eclipse/hono/util/KubernetesContainerUtil.java b/core/src/main/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtil.java similarity index 86% rename from core/src/main/java/org/eclipse/hono/util/KubernetesContainerUtil.java rename to core/src/main/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtil.java index ba64e32a7f..c4da400f05 100644 --- a/core/src/main/java/org/eclipse/hono/util/KubernetesContainerUtil.java +++ b/core/src/main/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtil.java @@ -31,14 +31,14 @@ * This class has been copied from org.apache.logging.log4j.kubernetes.ContainerUtil from the * log4j-kubernetes module of the Apache Log4j 2 * project (commit a50abb9). Adaptations have been done concerning the used logger and the Hono code style. - * Also a fix regarding cri-containerd container ids has been applied. + * Also, a fix regarding cri-containerd container ids has been applied. */ -public class KubernetesContainerUtil { +public class CgroupV1KubernetesContainerUtil { private static final int MAXLENGTH = 65; - private static final Logger LOGGER = LoggerFactory.getLogger(KubernetesContainerUtil.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CgroupV1KubernetesContainerUtil.class); - private KubernetesContainerUtil() { + private CgroupV1KubernetesContainerUtil() { } /** @@ -60,16 +60,16 @@ public static String getContainerId() { final File file = new File("/proc/self/cgroup"); if (file.exists()) { try (Stream lines = Files.lines(file.toPath())) { - final String id = lines.map(KubernetesContainerUtil::getContainerId).filter(Objects::nonNull) + final String id = lines.map(CgroupV1KubernetesContainerUtil::getContainerId).filter(Objects::nonNull) .findFirst().orElse(null); - LOGGER.debug("Found container id {}", id); + LOGGER.debug("Found container id via cgroup v1: {}", id); return id; } } else { - LOGGER.warn("Unable to access container information"); + LOGGER.warn("Unable to access '/proc/self/cgroup' to get container information"); } } catch (final IOException ioe) { - LOGGER.warn("Error obtaining container id: {}", ioe.getMessage()); + LOGGER.warn("Error obtaining container id via cgroup v1: {}", ioe.getMessage()); } return null; } diff --git a/core/src/main/java/org/eclipse/hono/util/CommandConstants.java b/core/src/main/java/org/eclipse/hono/util/CommandConstants.java index 907d2ec9aa..ff49843a06 100644 --- a/core/src/main/java/org/eclipse/hono/util/CommandConstants.java +++ b/core/src/main/java/org/eclipse/hono/util/CommandConstants.java @@ -161,7 +161,7 @@ public static boolean isNorthboundCommandResponseEndpoint(final String endpoint) * @return The new adapter instance identifier. */ public static String getNewAdapterInstanceId(final String adapterName, final int counter) { - final String k8sContainerId = KubernetesContainerUtil.getContainerId(); + final String k8sContainerId = CgroupV1KubernetesContainerUtil.getContainerId(); if (k8sContainerId == null || k8sContainerId.length() < 12) { return getNewAdapterInstanceIdForNonK8sEnv(adapterName); } else { diff --git a/core/src/test/java/org/eclipse/hono/util/KubernetesContainerUtilTest.java b/core/src/test/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtilTest.java similarity index 82% rename from core/src/test/java/org/eclipse/hono/util/KubernetesContainerUtilTest.java rename to core/src/test/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtilTest.java index ddf1931ec2..5ae253c2d6 100644 --- a/core/src/test/java/org/eclipse/hono/util/KubernetesContainerUtilTest.java +++ b/core/src/test/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtilTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021 Contributors to the Eclipse Foundation + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -18,9 +18,9 @@ import org.junit.jupiter.api.Test; /** - * Unit tests for {@code KubernetesContainerUtil}. + * Unit tests for {@link CgroupV1KubernetesContainerUtil}. */ -public class KubernetesContainerUtilTest { +public class CgroupV1KubernetesContainerUtilTest { /** * Tests extracting the container id from a container created by the containerd CRI plugin. @@ -30,7 +30,7 @@ public void testGetContainerIdForContainerdCriContainer() { final String containerId = "118cc69780e057ab94ed0526d2f05ad61cf208f1175bab24bba25c1d826aac82"; final String cgroupLine = "6:cpuset:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod65b4c0a2_51e8_4d62_a015_1c096724b473.slice/" + "cri-containerd-118cc69780e057ab94ed0526d2f05ad61cf208f1175bab24bba25c1d826aac82.scope"; - final String extractedContainerId = KubernetesContainerUtil.getContainerId(cgroupLine); + final String extractedContainerId = CgroupV1KubernetesContainerUtil.getContainerId(cgroupLine); assertThat(extractedContainerId).isEqualTo(containerId); } @@ -42,7 +42,7 @@ public void testGetContainerIdForDockerContainer() { final String containerId = "3dd988081e7149463c043b5d9c57d7309e079c5e9290f91feba1cc45a04d6a5b"; final String cgroupLine = "8:cpuset:/kubepods.slice/kubepods-pod9c26dfb6_b9c9_11e7_bfb9_02c6c1fc4861.slice/" + "docker-3dd988081e7149463c043b5d9c57d7309e079c5e9290f91feba1cc45a04d6a5b.scope"; - final String extractedContainerId = KubernetesContainerUtil.getContainerId(cgroupLine); + final String extractedContainerId = CgroupV1KubernetesContainerUtil.getContainerId(cgroupLine); assertThat(extractedContainerId).isEqualTo(containerId); } } From 4017ab89f7688b2f4b838e095bda793fcdc3d191 Mon Sep 17 00:00:00 2001 From: Carsten Lohmann Date: Tue, 19 Sep 2023 07:49:48 +0200 Subject: [PATCH 3/4] Move adapterInstanceId related methods into hono-client-command. Signed-off-by: Carsten Lohmann --- .../client/command/CommandRoutingUtil.java | 124 ++++++++++++++++++ ...ocolAdapterCommandConsumerFactoryImpl.java | 5 +- .../command/CommandRoutingUtilTest.java | 13 +- .../eclipse/hono/util/CommandConstants.java | 98 +------------- ...etesBasedAdapterInstanceStatusService.java | 6 +- ...BasedAdapterInstanceStatusServiceTest.java | 6 +- .../InternalKafkaTopicCleanupServiceTest.java | 6 +- 7 files changed, 143 insertions(+), 115 deletions(-) create mode 100644 clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java rename core/src/test/java/org/eclipse/hono/util/CommandConstantsTest.java => clients/command/src/test/java/org/eclipse/hono/client/command/CommandRoutingUtilTest.java (68%) diff --git a/clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java b/clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java new file mode 100644 index 0000000000..f75cbee051 --- /dev/null +++ b/clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +package org.eclipse.hono.client.command; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.hono.util.CgroupV1KubernetesContainerUtil; +import org.eclipse.hono.util.Pair; +import org.eclipse.hono.util.Strings; + +/** + * Utility methods used in connection with routing of Command and Control messages. + */ +public class CommandRoutingUtil { + + /** + * Pattern of the adapter instance identifier, used when routing a command message to a protocol + * adapter running in a Kubernetes cluster. + *

+ * The first matcher group contains the pod name, the second matcher group contains the first 12 characters of the + * docker container id of the adapter instance. + */ + private static final Pattern KUBERNETES_ADAPTER_INSTANCE_ID_PATTERN = Pattern.compile("^(.*)_([0-9a-f]{12})_\\d+$"); + + private CommandRoutingUtil() { + // prevent instantiation + } + + /** + * Creates a new adapter instance identifier, used for identifying the protocol adapter to route a command to. + *

+ * If this method is invoked from within a docker container in a Kubernetes cluster, the format is + * [prefix]_[docker_container_id]_[counter], with prefix being the name of the Kubernetes pod. + * See also {@link #getK8sPodNameAndContainerIdFromAdapterInstanceId(String)}. + *

+ * If not running in a Kubernetes cluster, a random id with the given adapter name as prefix is used. + * + * @param adapterName The adapter name. + * @param counter The counter value to use. + * @return The new adapter instance identifier. + */ + public static String getNewAdapterInstanceId(final String adapterName, final int counter) { + final String k8sContainerId = CgroupV1KubernetesContainerUtil.getContainerId(); + if (k8sContainerId == null || k8sContainerId.length() < 12) { + return getNewAdapterInstanceIdForNonK8sEnv(adapterName); + } else { + // running in Kubernetes: prefer HOSTNAME env var containing the pod name + String prefix = System.getenv("HOSTNAME"); + if (Strings.isNullOrEmpty(prefix)) { + prefix = adapterName; + } + return getNewAdapterInstanceIdForK8sEnv(prefix, k8sContainerId, counter); + } + } + + /** + * Creates a new adapter instance identifier for use in a non-Kubernetes environment. + *

+ * The format is [adapterName]_[uuid]. + * + * @param adapterName The adapter name to use. + * @return The new adapter instance identifier. + */ + public static String getNewAdapterInstanceIdForNonK8sEnv(final String adapterName) { + final String prefix = Strings.isNullOrEmpty(adapterName) ? "" + : adapterName.replaceAll("[^a-zA-Z0-9._-]", "") + "-"; + return prefix + UUID.randomUUID(); + } + + /** + * Creates a new adapter instance identifier for use in a Kubernetes environment. + *

+ * The format is [pod_name]_[docker_container_id]_[counter]. + * + * @param podName The pod name to use. + * @param containerId The container identifier to use. + * @param counter The counter value to use. + * @return The new adapter instance identifier. + * @throws NullPointerException If containerId is {@code null}. + */ + public static String getNewAdapterInstanceIdForK8sEnv(final String podName, final String containerId, final int counter) { + Objects.requireNonNull(containerId); + // replace special characters so that the id can be used in a Kafka topic name + final String podNameToUse = Optional.ofNullable(podName) + .map(p -> p.replaceAll("[^a-zA-Z0-9._-]", "")).orElse(""); + return String.format("%s_%s_%d", + podNameToUse, + containerId.substring(0, 12), + counter); + } + + /** + * Gets the pod name and container identifier from a given adapter instance identifier that was created via + * {@link #getNewAdapterInstanceIdForK8sEnv(String, String, int)}. + * + * @param adapterInstanceId The adapter instance identifier. + * @return The pod name and container identifier pair or {@code null} if the adapter instance identifier didn't + * match. + * @throws NullPointerException If adapterInstanceId is {@code null}. + */ + public static Pair getK8sPodNameAndContainerIdFromAdapterInstanceId(final String adapterInstanceId) { + Objects.requireNonNull(adapterInstanceId); + final Matcher matcher = KUBERNETES_ADAPTER_INSTANCE_ID_PATTERN.matcher(adapterInstanceId); + if (!matcher.matches()) { + return null; + } + return Pair.of(matcher.group(1), matcher.group(2)); + } +} diff --git a/clients/command/src/main/java/org/eclipse/hono/client/command/ProtocolAdapterCommandConsumerFactoryImpl.java b/clients/command/src/main/java/org/eclipse/hono/client/command/ProtocolAdapterCommandConsumerFactoryImpl.java index 7d73c764a4..c7db5077df 100644 --- a/clients/command/src/main/java/org/eclipse/hono/client/command/ProtocolAdapterCommandConsumerFactoryImpl.java +++ b/clients/command/src/main/java/org/eclipse/hono/client/command/ProtocolAdapterCommandConsumerFactoryImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2020, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -28,7 +28,6 @@ import org.eclipse.hono.client.ServiceInvocationException; import org.eclipse.hono.client.amqp.connection.ConnectionLifecycle; import org.eclipse.hono.client.util.ServiceClient; -import org.eclipse.hono.util.CommandConstants; import org.eclipse.hono.util.Lifecycle; import org.eclipse.hono.util.TenantConstants; import org.slf4j.Logger; @@ -75,7 +74,7 @@ public ProtocolAdapterCommandConsumerFactoryImpl(final CommandRouterClient comma this.commandRouterClient = Objects.requireNonNull(commandRouterClient); Objects.requireNonNull(adapterName); - this.adapterInstanceId = CommandConstants.getNewAdapterInstanceId(adapterName, + this.adapterInstanceId = CommandRoutingUtil.getNewAdapterInstanceId(adapterName, ADAPTER_INSTANCE_ID_COUNTER.getAndIncrement()); if (commandRouterClient instanceof ConnectionLifecycle) { ((ConnectionLifecycle) commandRouterClient).addReconnectListener(con -> reenableCommandRouting()); diff --git a/core/src/test/java/org/eclipse/hono/util/CommandConstantsTest.java b/clients/command/src/test/java/org/eclipse/hono/client/command/CommandRoutingUtilTest.java similarity index 68% rename from core/src/test/java/org/eclipse/hono/util/CommandConstantsTest.java rename to clients/command/src/test/java/org/eclipse/hono/client/command/CommandRoutingUtilTest.java index 39f2395eca..957a6b90da 100644 --- a/core/src/test/java/org/eclipse/hono/util/CommandConstantsTest.java +++ b/clients/command/src/test/java/org/eclipse/hono/client/command/CommandRoutingUtilTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -11,26 +11,27 @@ * SPDX-License-Identifier: EPL-2.0 */ -package org.eclipse.hono.util; +package org.eclipse.hono.client.command; import static com.google.common.truth.Truth.assertThat; +import org.eclipse.hono.util.Pair; import org.junit.jupiter.api.Test; /** - * Tests verifying behavior of {@link CommandConstants}. + * Tests verifying behavior of {@link CommandRoutingUtil}. * */ -public class CommandConstantsTest { +public class CommandRoutingUtilTest { @Test void testGetK8sPodNameAndContainerIdFromAdapterInstanceId() { final String podName = "myPodName"; final String containerId = "012345678901"; - final String newAdapterInstanceId = CommandConstants.getNewAdapterInstanceIdForK8sEnv(podName, containerId, 1); - final Pair podNameAndContainerId = CommandConstants.getK8sPodNameAndContainerIdFromAdapterInstanceId( + final String newAdapterInstanceId = CommandRoutingUtil.getNewAdapterInstanceIdForK8sEnv(podName, containerId, 1); + final Pair podNameAndContainerId = CommandRoutingUtil.getK8sPodNameAndContainerIdFromAdapterInstanceId( newAdapterInstanceId); assertThat(podNameAndContainerId).isNotNull(); assertThat(podNameAndContainerId.one()).isEqualTo(podName); diff --git a/core/src/main/java/org/eclipse/hono/util/CommandConstants.java b/core/src/main/java/org/eclipse/hono/util/CommandConstants.java index ff49843a06..4dd05d9dd9 100644 --- a/core/src/main/java/org/eclipse/hono/util/CommandConstants.java +++ b/core/src/main/java/org/eclipse/hono/util/CommandConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2016, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -13,12 +13,6 @@ package org.eclipse.hono.util; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Constants & utility methods used throughout the Command and Control API. */ @@ -114,15 +108,6 @@ public class CommandConstants { */ public static final int TOPIC_POSITION_RESPONSE_REQ_ID = 4; - /** - * Pattern of the adapter instance identifier, used when routing a command message to a protocol - * adapter running in a Kubernetes cluster. - *

- * The first matcher group contains the pod name, the second matcher group contains the first 12 characters of the - * docker container id of the adapter instance. - */ - private static final Pattern KUBERNETES_ADAPTER_INSTANCE_ID_PATTERN = Pattern.compile("^(.*)_([0-9a-f]{12})_\\d+$"); - private CommandConstants() { // prevent instantiation } @@ -146,85 +131,4 @@ public static boolean isCommandEndpoint(final String endpoint) { public static boolean isNorthboundCommandResponseEndpoint(final String endpoint) { return CommandConstants.NORTHBOUND_COMMAND_RESPONSE_ENDPOINT.equals(endpoint); } - - /** - * Creates a new adapter instance identifier. - *

- * If this method is invoked from within a docker container in a Kubernetes cluster, the format is - * [prefix]_[docker_container_id]_[counter], with prefix being the name of the Kubernetes pod. - * See also {@link #getK8sPodNameAndContainerIdFromAdapterInstanceId(String)}. - *

- * If not running in a Kubernetes cluster, a random id with the given adapter name as prefix is used. - * - * @param adapterName The adapter name. - * @param counter The counter value to use. - * @return The new adapter instance identifier. - */ - public static String getNewAdapterInstanceId(final String adapterName, final int counter) { - final String k8sContainerId = CgroupV1KubernetesContainerUtil.getContainerId(); - if (k8sContainerId == null || k8sContainerId.length() < 12) { - return getNewAdapterInstanceIdForNonK8sEnv(adapterName); - } else { - // running in Kubernetes: prefer HOSTNAME env var containing the pod name - String prefix = System.getenv("HOSTNAME"); - if (Strings.isNullOrEmpty(prefix)) { - prefix = adapterName; - } - return getNewAdapterInstanceIdForK8sEnv(prefix, k8sContainerId, counter); - } - } - - /** - * Creates a new adapter instance identifier for use in a non-Kubernetes environment. - *

- * The format is [adapterName]_[uuid]. - * - * @param adapterName The adapter name to use. - * @return The new adapter instance identifier. - */ - public static String getNewAdapterInstanceIdForNonK8sEnv(final String adapterName) { - final String prefix = Strings.isNullOrEmpty(adapterName) ? "" - : adapterName.replaceAll("[^a-zA-Z0-9._-]", "") + "-"; - return prefix + UUID.randomUUID(); - } - - /** - * Creates a new adapter instance identifier for use in a Kubernetes environment. - *

- * The format is [pod_name]_[docker_container_id]_[counter]. - * - * @param podName The pod name to use. - * @param containerId The container identifier to use. - * @param counter The counter value to use. - * @return The new adapter instance identifier. - * @throws NullPointerException If containerId is {@code null}. - */ - public static String getNewAdapterInstanceIdForK8sEnv(final String podName, final String containerId, final int counter) { - Objects.requireNonNull(containerId); - // replace special characters so that the id can be used in a Kafka topic name - final String podNameToUse = Optional.ofNullable(podName) - .map(p -> p.replaceAll("[^a-zA-Z0-9._-]", "")).orElse(""); - return String.format("%s_%s_%d", - podNameToUse, - containerId.substring(0, 12), - counter); - } - - /** - * Gets the pod name and container identifier from a given adapter instance identifier that was created via - * {@link #getNewAdapterInstanceIdForK8sEnv(String, String, int)}. - * - * @param adapterInstanceId The adapter instance identifier. - * @return The pod name and container identifier pair or {@code null} if the adapter instance identifier didn't - * match. - * @throws NullPointerException If adapterInstanceId is {@code null}. - */ - public static Pair getK8sPodNameAndContainerIdFromAdapterInstanceId(final String adapterInstanceId) { - Objects.requireNonNull(adapterInstanceId); - final Matcher matcher = KUBERNETES_ADAPTER_INSTANCE_ID_PATTERN.matcher(adapterInstanceId); - if (!matcher.matches()) { - return null; - } - return Pair.of(matcher.group(1), matcher.group(2)); - } } diff --git a/services/command-router/src/main/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusService.java b/services/command-router/src/main/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusService.java index 5648290b17..80b72bd2c6 100644 --- a/services/command-router/src/main/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusService.java +++ b/services/command-router/src/main/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -31,9 +31,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import org.eclipse.hono.client.command.CommandRoutingUtil; import org.eclipse.hono.commandrouter.AdapterInstanceStatusService; import org.eclipse.hono.util.AdapterInstanceStatus; -import org.eclipse.hono.util.CommandConstants; import org.eclipse.hono.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -357,7 +357,7 @@ public AdapterInstanceStatus getStatus(final String adapterInstanceId) { LOG.debug("no status info available for adapter instance id [{}]; service not active", adapterInstanceId); return AdapterInstanceStatus.UNKNOWN; } - final Pair matchedPodNameAndContainerIdPair = CommandConstants + final Pair matchedPodNameAndContainerIdPair = CommandRoutingUtil .getK8sPodNameAndContainerIdFromAdapterInstanceId(adapterInstanceId); if (matchedPodNameAndContainerIdPair == null) { return AdapterInstanceStatus.UNKNOWN; diff --git a/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusServiceTest.java b/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusServiceTest.java index 7e86caa48c..703f7e6a7b 100644 --- a/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusServiceTest.java +++ b/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/KubernetesBasedAdapterInstanceStatusServiceTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -24,8 +24,8 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import org.eclipse.hono.client.command.CommandRoutingUtil; import org.eclipse.hono.util.AdapterInstanceStatus; -import org.eclipse.hono.util.CommandConstants; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -174,7 +174,7 @@ protected void onAdapterContainerAdded(final String podName, final String contai public void testServiceReportsStateOfUnknownAdapterInstanceAsDeadAfterDelay() { final String nonExistingInstanceId = "old-adapter-pod_000000000000_0"; - assertThat(CommandConstants.getK8sPodNameAndContainerIdFromAdapterInstanceId(nonExistingInstanceId)) + assertThat(CommandRoutingUtil.getK8sPodNameAndContainerIdFromAdapterInstanceId(nonExistingInstanceId)) .isNotNull(); final Pod pod0 = createAdapterPodWithRunningContainer("adapterTestPod0"); diff --git a/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/kafka/InternalKafkaTopicCleanupServiceTest.java b/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/kafka/InternalKafkaTopicCleanupServiceTest.java index 35479a2460..1309c1695c 100644 --- a/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/kafka/InternalKafkaTopicCleanupServiceTest.java +++ b/services/command-router/src/test/java/org/eclipse/hono/commandrouter/impl/kafka/InternalKafkaTopicCleanupServiceTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2021, 2022 Contributors to the Eclipse Foundation + * Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -29,10 +29,10 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import org.eclipse.hono.client.command.CommandRoutingUtil; import org.eclipse.hono.client.kafka.HonoTopic; import org.eclipse.hono.commandrouter.AdapterInstanceStatusService; import org.eclipse.hono.test.VertxMockSupport; -import org.eclipse.hono.util.CommandConstants; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -123,7 +123,7 @@ void testPerformCleanup() { } private String getCmdInternalTopic(final String podName, final String containerId, final int counter) { - final String adapterInstanceId = CommandConstants.getNewAdapterInstanceIdForK8sEnv( + final String adapterInstanceId = CommandRoutingUtil.getNewAdapterInstanceIdForK8sEnv( podName, containerId, counter); return new HonoTopic(HonoTopic.Type.COMMAND_INTERNAL, adapterInstanceId).toString(); } From f6e531cafcfef7f5815e4c23934053dc7a15a059 Mon Sep 17 00:00:00 2001 From: Carsten Lohmann Date: Tue, 19 Sep 2023 07:50:45 +0200 Subject: [PATCH 4/4] Move CgroupV1KubernetesContainerUtil into hono-client-command. Signed-off-by: Carsten Lohmann --- .../hono/client/command}/CgroupV1KubernetesContainerUtil.java | 2 +- .../org/eclipse/hono/client/command/CommandRoutingUtil.java | 1 - .../client/command}/CgroupV1KubernetesContainerUtilTest.java | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) rename {core/src/main/java/org/eclipse/hono/util => clients/command/src/main/java/org/eclipse/hono/client/command}/CgroupV1KubernetesContainerUtil.java (99%) rename {core/src/test/java/org/eclipse/hono/util => clients/command/src/test/java/org/eclipse/hono/client/command}/CgroupV1KubernetesContainerUtilTest.java (98%) diff --git a/core/src/main/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtil.java b/clients/command/src/main/java/org/eclipse/hono/client/command/CgroupV1KubernetesContainerUtil.java similarity index 99% rename from core/src/main/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtil.java rename to clients/command/src/main/java/org/eclipse/hono/client/command/CgroupV1KubernetesContainerUtil.java index c4da400f05..1fa9540018 100644 --- a/core/src/main/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtil.java +++ b/clients/command/src/main/java/org/eclipse/hono/client/command/CgroupV1KubernetesContainerUtil.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.eclipse.hono.util; +package org.eclipse.hono.client.command; import java.io.File; import java.io.IOException; diff --git a/clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java b/clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java index f75cbee051..eb2edb3725 100644 --- a/clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java +++ b/clients/command/src/main/java/org/eclipse/hono/client/command/CommandRoutingUtil.java @@ -19,7 +19,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.eclipse.hono.util.CgroupV1KubernetesContainerUtil; import org.eclipse.hono.util.Pair; import org.eclipse.hono.util.Strings; diff --git a/core/src/test/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtilTest.java b/clients/command/src/test/java/org/eclipse/hono/client/command/CgroupV1KubernetesContainerUtilTest.java similarity index 98% rename from core/src/test/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtilTest.java rename to clients/command/src/test/java/org/eclipse/hono/client/command/CgroupV1KubernetesContainerUtilTest.java index 5ae253c2d6..4e0b1c9c32 100644 --- a/core/src/test/java/org/eclipse/hono/util/CgroupV1KubernetesContainerUtilTest.java +++ b/clients/command/src/test/java/org/eclipse/hono/client/command/CgroupV1KubernetesContainerUtilTest.java @@ -11,7 +11,7 @@ * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ -package org.eclipse.hono.util; +package org.eclipse.hono.client.command; import static com.google.common.truth.Truth.assertThat;