From 2ab6dab41f675e0abec9816c0f792b0b91a00327 Mon Sep 17 00:00:00 2001 From: Silvio Giebl Date: Tue, 5 Nov 2024 14:55:37 +0100 Subject: [PATCH 1/2] Improve the "temp-extensions" workaround: - Copy extensions to the temp dir only if required. It is required when removing prepackaged extensions. - Custom copyToContainer calls that specify /opt/hivemq/extensions/... as container path automatically apply the temp dir workaround if required. --- .../hivemq/HiveMQContainer.java | 68 +++++++++++-------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 241d5b18c9e..96787d2e818 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -10,6 +10,7 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; @@ -76,6 +77,8 @@ public class HiveMQContainer extends GenericContainer { @NotNull private final WaitAllStrategy waitStrategy = new WaitAllStrategy(); + private boolean isStarted = false; + public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_HIVEMQ_CE_IMAGE_NAME, DEFAULT_HIVEMQ_EE_IMAGE_NAME); @@ -115,10 +118,10 @@ public HiveMQContainer(final @NotNull DockerImageName dockerImageName) { @Override protected void configure() { - final String removeCommand; - withCreateContainerCmdModifier(it -> it.withEntrypoint("/bin/sh")); + if (removePrepackagedExtensions()) { + withCreateContainerCmdModifier(it -> it.withEntrypoint("/bin/sh")); - if (removeAllPrepackagedExtensions || !prepackagedExtensionsToRemove.isEmpty()) { + final String removeCommand; if (removeAllPrepackagedExtensions) { removeCommand = "rm -rf /opt/hivemq/extensions/** &&"; } else { @@ -128,19 +131,38 @@ protected void configure() { .map(extensionId -> "rm -rf /opt/hivemq/extensions/" + extensionId + "&&") .collect(Collectors.joining()); } - } else { - removeCommand = ""; + setCommand( + "-c", + removeCommand + + "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ ; " + + "chmod -R 777 /opt/hivemq/extensions ; " + + "/opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" + ); } - setCommand( - "-c", - removeCommand + - "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ ; " + - "chmod -R 777 /opt/hivemq/extensions ; " + - "/opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" - ); + } + + private boolean removePrepackagedExtensions() { + return removeAllPrepackagedExtensions || !prepackagedExtensionsToRemove.isEmpty(); + } + + @Override + public void copyFileToContainer(final @NotNull MountableFile mountableFile, @NotNull String containerPath) { + if (!isStarted && removePrepackagedExtensions() && containerPath.startsWith("/opt/hivemq/extensions/")) { + containerPath = "/opt/hivemq/temp-extensions/" + containerPath.substring("/opt/hivemq/extensions/".length()); + } + super.copyFileToContainer(mountableFile, containerPath); + } + + @Override + public void copyFileToContainer(final @NotNull Transferable transferable, @NotNull String containerPath) { + if (!isStarted && removePrepackagedExtensions() && containerPath.startsWith("/opt/hivemq/extensions/")) { + containerPath = "/opt/hivemq/temp-extensions/" + containerPath.substring("/opt/hivemq/extensions/".length()); + } + super.copyFileToContainer(transferable, containerPath); } protected void containerIsStarted(final @NotNull InspectContainerResponse containerInfo) { + isStarted = true; if (controlCenterEnabled) { LOGGER.info( "The HiveMQ Control Center is reachable under: http://{}:{}", @@ -208,11 +230,9 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai /** * Wraps the given class and all its subclasses into an extension - * and puts it into '/opt/hivemq/temp-extensions/{extension-id}' inside the container. + * and puts it into '/opt/hivemq/extensions/{extension-id}' inside the container. *

* Must be called before the container is started. - *

- * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. * * @param hiveMQExtension the {@link HiveMQExtension} of the extension * @return self @@ -221,7 +241,7 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai try { final File extension = hiveMQExtension.createExtension(hiveMQExtension); final MountableFile mountableExtension = MountableFile.forHostPath(extension.getPath(), MODE); - withCopyFileToContainer(mountableExtension, "/opt/hivemq/temp-extensions/" + hiveMQExtension.getId()); + withCopyFileToContainer(mountableExtension, "/opt/hivemq/extensions/" + hiveMQExtension.getId()); } catch (final Exception e) { throw new ContainerLaunchException(e.getMessage() == null ? "" : e.getMessage(), e); } @@ -229,13 +249,11 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai } /** - * Puts the given extension folder into '/opt/hivemq/temp-extensions/{directory-name}' inside the container. + * Puts the given extension folder into '/opt/hivemq/extensions/{directory-name}' inside the container. * It must at least contain a valid hivemq-extension.xml and a valid extension.jar in order to be executed. * The directory-name is taken from the id defined in the hivemq-extension.xml. *

* Must be called before the container is started. - *

- * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. * * @param mountableExtension the extension folder on the host machine * @return self @@ -256,7 +274,7 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai } try { final String extensionDirName = getExtensionDirectoryName(extensionDir); - final String containerPath = "/opt/hivemq/temp-extensions/" + extensionDirName; + final String containerPath = "/opt/hivemq/extensions/" + extensionDirName; withCopyFileToContainer(cloneWithFileMode(mountableExtension), containerPath); LOGGER.info("Putting extension '{}' into '{}'", extensionDirName, containerPath); } catch (final Exception e) { @@ -350,11 +368,9 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai } /** - * Puts the given file into the root of the extension's home '/opt/hivemq/temp-extensions/{extensionId}/'. + * Puts the given file into the root of the extension's home '/opt/hivemq/extensions/{extensionId}/'. *

* Must be called before the container is started. - *

- * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. * * @param file the file on the host machine * @param extensionId the extension @@ -368,11 +384,9 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai } /** - * Puts the given file into given subdirectory of the extensions's home '/opt/hivemq/temp-extensions/{id}/{pathInExtensionHome}/' + * Puts the given file into given subdirectory of the extensions's home '/opt/hivemq/extensions/{id}/{pathInExtensionHome}/' *

* Must be called before the container is started. - *

- * The contents of the '/opt/hivemq/temp-extensions/' directory are copied to '/opt/hivemq/extensions/' before the container is started. * * @param file the file on the host machine * @param extensionId the extension @@ -386,7 +400,7 @@ protected void containerIsStarted(final @NotNull InspectContainerResponse contai ) { return withFileInHomeFolder( file, - "/temp-extensions/" + extensionId + PathUtil.prepareAppendPath(pathInExtensionHome) + "/extensions/" + extensionId + PathUtil.prepareAppendPath(pathInExtensionHome) ); } From 0b1bbebcbb5600e0d5419522b85a6f2f78d24d2e Mon Sep 17 00:00:00 2001 From: Silvio Giebl Date: Tue, 5 Nov 2024 15:14:08 +0100 Subject: [PATCH 2/2] Improve the "temp-extensions" workaround: - Cleanup code --- .../testcontainers/hivemq/HiveMQContainer.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 96787d2e818..f0ae0e718f5 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -146,19 +146,20 @@ private boolean removePrepackagedExtensions() { } @Override - public void copyFileToContainer(final @NotNull MountableFile mountableFile, @NotNull String containerPath) { - if (!isStarted && removePrepackagedExtensions() && containerPath.startsWith("/opt/hivemq/extensions/")) { - containerPath = "/opt/hivemq/temp-extensions/" + containerPath.substring("/opt/hivemq/extensions/".length()); - } - super.copyFileToContainer(mountableFile, containerPath); + public void copyFileToContainer(final @NotNull MountableFile mountableFile, final @NotNull String containerPath) { + super.copyFileToContainer(mountableFile, mapContainerPathIfRequired(containerPath)); } @Override - public void copyFileToContainer(final @NotNull Transferable transferable, @NotNull String containerPath) { + public void copyFileToContainer(final @NotNull Transferable transferable, final @NotNull String containerPath) { + super.copyFileToContainer(transferable, mapContainerPathIfRequired(containerPath)); + } + + private @NotNull String mapContainerPathIfRequired(final @NotNull String containerPath) { if (!isStarted && removePrepackagedExtensions() && containerPath.startsWith("/opt/hivemq/extensions/")) { - containerPath = "/opt/hivemq/temp-extensions/" + containerPath.substring("/opt/hivemq/extensions/".length()); + return "/opt/hivemq/temp-extensions/" + containerPath.substring("/opt/hivemq/extensions/".length()); } - super.copyFileToContainer(transferable, containerPath); + return containerPath; } protected void containerIsStarted(final @NotNull InspectContainerResponse containerInfo) {