Skip to content

Commit

Permalink
Add ArtemisMQ and Horreum containers.
Browse files Browse the repository at this point in the history
  • Loading branch information
whitingjr authored and johnaohara committed Sep 17, 2024
1 parent 165eb78 commit 62de080
Show file tree
Hide file tree
Showing 4 changed files with 322 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ public class Const {
public static final String HORREUM_DEV_DB_PASSWORD = "horreum.db.password";
public static final String HORREUM_DEV_DB_DATABASE = "horreum.db.database";

public static final String HORREUM_DEV_HORREUM_HORREUM_IMAGE = "horreum.dev-services.horreum.horreum.image";
public static final String HORREUM_DEV_HORREUM_NETWORK_ALIAS = "horreum.dev-services.horreum.network-alias";
public static final String HORREUM_DEV_HORREUM_CONTAINER_PORT = "horreum.dev-services.horreum.container-port";

public static final String HORREUM_DEV_AMQP_ENABLED = "horreum.dev-services.amqp.enabled";
public static final String HORREUM_DEV_AMQP_IMAGE = "horreum.dev-services.amqp.image";
public static final String HORREUM_DEV_AMQP_NETWORK_ALIAS = "horreum.dev-services.amqp.network-alias";
public static final String HORREUM_DEV_AMQP_MAPPED_PORT = "horreum.dev-services.amqp.mapped.port";
public static final String HORREUM_DEV_AMQP_MAPPED_HOST = "horreum.dev-services.amqp.mapped.host";

public static final String DEFAULT_DB_USERNAME = "dbadmin";
public static final String DEFAULT_DB_PASSWORD = "secret";
public static final String DEFAULT_DBDATABASE = "horreum";
Expand All @@ -38,5 +48,8 @@ public class Const {
public static final String DEFAULT_POSTGRES_NETWORK_ALIAS = "horreum-dev-postgres";

public static final String DEFAULT_KEYCLOAK_NETWORK_ALIAS = "horreum-dev-keycloak";

public static final String DEFAULT_AMQP_NETWORK_ALIAS = "horreum-dev-amqp";
public static final String DEFAULT_HORREUM_NETWORK_ALIAS = "horreum-dev-horreum";
public static final String DEFAULT_AMQP_USERNAME = "horreum";
public static final String DEFAULT_AMQP_PASSWORD = "secret";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.hyperfoil.tools.horreum.infra.common.resources;

import static io.hyperfoil.tools.horreum.infra.common.Const.*;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.utility.MountableFile;

import io.hyperfoil.tools.horreum.infra.common.Const;
import io.hyperfoil.tools.horreum.infra.common.ResourceLifecycleManager;

public class ArtemisMQResource implements ResourceLifecycleManager {
private GenericContainer<?> amqpContainer;
private boolean inContainer = false;
private String networkAlias = "";

@Override
public void init(Map<String, String> initArgs) {
if (initArgs.containsKey(HORREUM_DEV_AMQP_ENABLED) && initArgs.get(HORREUM_DEV_AMQP_ENABLED).equals("true")) {
if (!initArgs.containsKey(HORREUM_DEV_AMQP_IMAGE)) {
throw new RuntimeException("Arguments did not contain AMQP image.");
}
final String AMQP_IMAGE = initArgs.get(Const.HORREUM_DEV_AMQP_IMAGE);
inContainer = initArgs.containsKey("inContainer") && initArgs.get("inContainer").equals("true");
networkAlias = initArgs.get(HORREUM_DEV_AMQP_NETWORK_ALIAS);

amqpContainer = new GenericContainer<>(AMQP_IMAGE);
amqpContainer.withEnv("ARTEMIS_USER", initArgs.get("amqp-username"))
.withEnv("ARTEMIS_PASSWORD", initArgs.get("amqp-password"))
.withEnv("AMQ_ROLE", "admin")
.withEnv("EXTRA_ARGS",
" --role admin --name broker --allow-anonymous --force --no-autotune --mapped --no-fsync --relax-jolokia ")
.withExposedPorts(5672)
.withCopyFileToContainer(MountableFile.forClasspathResource("broker.xml"),
"/var/lib/artemis-instance/etc-override/broker.xml");
}
}

@Override
public Map<String, String> start(Optional<Network> network) {
if (amqpContainer == null) {
return Collections.emptyMap();
}
if (network.isPresent()) {
amqpContainer.withNetwork(network.get());
amqpContainer.withNetworkAliases(networkAlias);
}
amqpContainer.start();
String mappedPort = amqpContainer.getMappedPort(5672).toString();
String host = inContainer ? networkAlias : "localhost";

return Map.of(HORREUM_DEV_AMQP_MAPPED_PORT, mappedPort,
HORREUM_DEV_AMQP_MAPPED_HOST, host);
}

@Override
public void stop() {
if (amqpContainer != null) {
amqpContainer.stop();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.hyperfoil.tools.horreum.infra.common.resources;

import static io.hyperfoil.tools.horreum.infra.common.Const.*;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;

import org.testcontainers.containers.FixedHostPortGenericContainer;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;

import io.hyperfoil.tools.horreum.infra.common.HorreumResources;
import io.hyperfoil.tools.horreum.infra.common.ResourceLifecycleManager;

public class HorreumResource implements ResourceLifecycleManager {

private static GenericContainer<?> horreumContainer;
private StringBuilder javaOptions = new StringBuilder();

private String networkAlias = "";

public void init(Map<String, String> initArgs) {
if (!initArgs.containsKey(HORREUM_DEV_HORREUM_HORREUM_IMAGE)) {
throw new RuntimeException("Horreum dev image argument not configured");
}

final String HORREUM_IMAGE = initArgs.get(HORREUM_DEV_HORREUM_HORREUM_IMAGE);

networkAlias = initArgs.get(HORREUM_DEV_HORREUM_NETWORK_ALIAS);
Network network = HorreumResources.getNetwork();

horreumContainer = (initArgs.containsKey(HORREUM_DEV_HORREUM_CONTAINER_PORT))
? new FixedHostPortGenericContainer<>(HORREUM_IMAGE)
.withFixedExposedPort(Integer.parseInt(initArgs.get(HORREUM_DEV_HORREUM_CONTAINER_PORT)), 8080)
: new GenericContainer<>(HORREUM_IMAGE).withExposedPorts(8080);
String keycloakHost = initArgs.get("keycloak.host");

keycloakHost = keycloakHost.replace("localhost", networkAlias);
String keycloakUrl = String.format("%s/realms/horreum", keycloakHost);
String horreumUrl = "http://" + networkAlias + ":8081";
String jdbcUrl = initArgs.get("quarkus.datasource.jdbc.url");
jdbcUrl = jdbcUrl.replace("localhost", networkAlias);

horreumContainer
.withEnv("horreum.keycloak.url", keycloakHost)
.withEnv("quarkus.oidc.auth-server-url", keycloakUrl)
.withEnv("quarkus.keycloak.admin-client.server-url", keycloakHost)
.withEnv("quarkus.keycloak.admin-client.client-id", "horreum")
.withEnv("quarkus.keycloak.admin-client.realm", "horreum")
.withEnv("quarkus.keycloak.admin-client.client-secret", "**********")
.withEnv("quarkus.keycloak.admin-client.grant-type", "CLIENT_CREDENTIALS")
.withEnv("quarkus.oidc.token.issuer", "https://server.example.com ")
.withEnv("smallrye.jwt.sign.key.location", "/privateKey.jwk")
.withEnv("horreum.url", horreumUrl)
.withEnv("horreum.test-mode", "true")
.withEnv("horreum.privacy", "/path/to/privacy/statement/link")
.withEnv("quarkus.datasource.migration.devservices.enabled", "false")
.withEnv("quarkus.datasource.jdbc.url", jdbcUrl)
.withEnv("quarkus.datasource.migration.jdbc.url", jdbcUrl)
.withEnv("quarkus.datasource.jdbc.additional-jdbc-properties.sslmode", "require")
.withEnv("amqp-host", initArgs.get("amqp.host"))
.withEnv("amqp-port", initArgs.get("amqp.mapped.port"))
.withEnv("amqp-username", initArgs.get("amqp-username"))
.withEnv("amqp-password", initArgs.get("amqp-password"))
.withEnv("amqp-reconnect-attempts", "100")
.withEnv("amqp-reconnect-interval", "1000")
.withEnv("quarkus.profile", "test")
.withEnv("quarkus.test.profile", "test")
.withEnv("horreum.bootstrap.password", "secret")
.withEnv("horreum.roles.provider", "database")
.withNetwork(network)
.withNetworkAliases(networkAlias)
.withCommand("/deployments/horreum.sh ");
}

@Override
public Map<String, String> start(Optional<Network> network) {
if (horreumContainer == null) {
return Collections.emptyMap();
}
if (!network.isPresent()) {
horreumContainer.withNetwork(network.get());
horreumContainer.withNetworkAliases(networkAlias);
}

horreumContainer.start();
String horreumContainerName = horreumContainer.getContainerName().replaceAll("/", "");
Integer port = horreumContainer.getMappedPort(8080);

return Map.of("horreum.container.name", horreumContainerName,
"horreum.container.port", port.toString());
}

@Override
public void stop() {
if (horreumContainer != null) {
horreumContainer.stop();
}
}
}
141 changes: 141 additions & 0 deletions infra/horreum-infra-common/src/main/resources/broker.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?xml version='1.0'?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

<configuration xmlns="urn:activemq"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="http://www.w3.org/2001/XInclude"
xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">

<core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:activemq:core ">

<name>broker</name>


<persistence-enabled>true</persistence-enabled>

<max-redelivery-records>1</max-redelivery-records>

<journal-type>MAPPED</journal-type>

<paging-directory>data/paging</paging-directory>

<bindings-directory>data/bindings</bindings-directory>

<journal-directory>data/journal</journal-directory>

<large-messages-directory>data/large-messages</large-messages-directory>

<journal-datasync>false</journal-datasync>

<journal-min-files>2</journal-min-files>

<journal-pool-files>10</journal-pool-files>

<journal-device-block-size>4096</journal-device-block-size>

<journal-file-size>10M</journal-file-size>

<disk-scan-period>5000</disk-scan-period>

<max-disk-usage>90</max-disk-usage>

<critical-analyzer>true</critical-analyzer>

<critical-analyzer-timeout>120000</critical-analyzer-timeout>

<critical-analyzer-check-period>60000</critical-analyzer-check-period>

<critical-analyzer-policy>HALT</critical-analyzer-policy>

<global-max-messages>-1</global-max-messages>

<acceptors>
<!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic.-->
<acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpMinLargeMessageSize=102400;amqpDuplicateDetection=true</acceptor>
</acceptors>


<security-settings>
<security-setting match="#">
<permission type="createNonDurableQueue" roles="admin"/>
<permission type="deleteNonDurableQueue" roles="admin"/>
<permission type="createDurableQueue" roles="admin"/>
<permission type="deleteDurableQueue" roles="admin"/>
<permission type="createAddress" roles="admin"/>
<permission type="deleteAddress" roles="admin"/>
<permission type="consume" roles="admin"/>
<permission type="browse" roles="admin"/>
<permission type="send" roles="admin"/>
<permission type="manage" roles="admin"/>
</security-setting>
</security-settings>

<address-settings>
<address-setting match="activemq.management#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-size-bytes>-1</max-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
</address-setting>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>

<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-delete-queues>false</auto-delete-queues>
<auto-delete-addresses>false</auto-delete-addresses>

<page-size-bytes>10M</page-size-bytes>

<max-size-bytes>-1</max-size-bytes>
<max-size-messages>-1</max-size-messages>

<max-read-page-messages>-1</max-read-page-messages>
<max-read-page-bytes>20M</max-read-page-bytes>

<page-limit-bytes>-1</page-limit-bytes>
<page-limit-messages>-1</page-limit-messages>
</address-setting>
</address-settings>

<addresses>
<address name="DLQ">
<anycast>
<queue name="DLQ" />
</anycast>
</address>
<address name="ExpiryQueue">
<anycast>
<queue name="ExpiryQueue" />
</anycast>
</address>
</addresses>
</core>
</configuration>

0 comments on commit 62de080

Please sign in to comment.