ARTEMIS-3042 simple properties based, extensible broker image

This commit is contained in:
Gary Tully 2022-06-30 16:09:00 +01:00
parent 0c8adee37a
commit 587ffb223c
20 changed files with 766 additions and 11 deletions

View File

@ -115,14 +115,15 @@ public class Artemis {
public static void verifyManagementDTO(File etc) {
if (etc != null) {
File management = new File(etc, "management.xml");
try {
ManagementContextDTO managementContextDTO = XmlUtil.decode(ManagementContextDTO.class, management);
if (managementContextDTO != null && managementContextDTO.getAuthorisation() != null) {
System.setProperty("javax.management.builder.initial", "org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerBuilder");
if (management.exists()) {
try {
ManagementContextDTO managementContextDTO = XmlUtil.decode(ManagementContextDTO.class, management);
if (managementContextDTO != null && managementContextDTO.getAuthorisation() != null) {
System.setProperty("javax.management.builder.initial", "org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerBuilder");
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -37,6 +37,7 @@ import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@ -2145,7 +2146,7 @@ public class ArtemisTest extends CliTestBase {
// verify error
Object ret = Artemis.internalExecute("run", "--properties", "https://www.apache.org");
assertTrue(ret instanceof IllegalStateException);
assertTrue(ret instanceof FileNotFoundException);
}
@Test

57
artemis-image/README.md Normal file
View File

@ -0,0 +1,57 @@
###What is in the image
An _empty_, _open_, _default_ broker with an acceptor on port 61616
- by empty: has no addresses or queues but will auto create on demand
- by open: has no security; authentication or authorization, users or roles
- by default: has no configuration, it is dependent on the hard coded defaults of the embedded broker service
###How will the image behave
1) the image will use or create `/app/data` for persistence of data
2) the image will use any [.properties files](https://activemq.apache.org/components/artemis/documentation/latest/configuration-index.html#broker_properties) from `/app/etc` to augment broker configuration
3) the image will use `/app/etc/broker.xml` if present, to bootstrap configuration, the 'bring your own config' use case
###Build and Use
First build an OCI image tar file from this artemis project using mvn.
The image wraps a plain java application based on a jre image. You should note the default `fromImage` property in the pom.xml and potentially override using `-DfromImage=<image url>` with your choice, as it may be out of date.
To build the image, use:
 `$> mvn compile jib:buildTar@now`
An OCI image is created as a tar file.
> *Note that any OCI compatible container runtime and registry can be used for the next steps, eg: docker, podman... I have used podman.*
To load the image tar into the local container registry, use:
 `$> podman image load --input target/jib-image.tar`
To run the image detached* and rootless with port 61616 exposed to localhost by podman, use:
 `$> podman run --name=artemis -dp 61616:61616 localhost/target/activemq-artemis-image:<version>`
The `:<version>` part of the image name is the maven ${project.version} from the pom.xml. You can use tab completion to have podman help you pick that exact container.
> **Note that you can later stop the detached container with: `$> podman stop artemis`*
Execute the artemis producer/consumer command line tools to interact with the broker.
 `$> ./bin/artemis producer --url tcp://localhost:61616`
 `$> ./bin/artemis consumer --url tcp://localhost:61616`
###Intent
The intent is that this image is useful as is. If one can trust users and is happy with configuration defaults, having no access control or limits can work fine.
If more control is necessary then this image can be configured by mounting an `/app/etc` directory with property files that augment default broker configuration.
This image could also be the base for a derived jib image, by simply adding more property files to the `src/main/jib/config` directory.
see examples/README.md for some more detail.

7
artemis-image/TODO.md Normal file
View File

@ -0,0 +1,7 @@
TODO:
- replace @classpath_file with cp from libs/*.jar directory - more extensible for folks that want extra jars/plugins in derived images
- or figure out a mount point for extra jars
- currently running as root!
- maybe we need a base image with an 'app' or 'java' user preconfigured with rw permissions on /app
- or do that in a launch.sh
- this is a known and reasonable limitation of jib https://github.com/GoogleContainerTools/jib/issues/1029

View File

@ -0,0 +1,55 @@
###Examples
This directory contains examples of customising the image for particular use cases
####amqp_sasl_scram_test__etc
In this example, you can run the image with configuration that locks the broker down to a single user on a single predefined
queue called `TEST`. The necessary configuration overrides:
- restricting the acceptor to AMQP/SASL-SCRAM
- providing RBAC for queue TEST
are in:`./amqp_sasl_scram_test__etc/amqp_sasl_scram.properties`
To exercise this example, you need to choose a password for the pre-configured user 'A'.
With SASL_SCRAM the broker retains a salted representation of that value, but not the plain text value.
Register your chosen password by creating `./amqp_sasl_scram_test__etc/user` using mvn as follows:
 `$> mvn exec:exec -Dexample.pwd=<some value>`
To see the result, cat the generated user file to see the stored representation:
 `$> cat ./amqp_sasl_scram_test__etc/user`
You can then mount the `./amqp_sasl_scram_test__etc directory` as `/app/etc` for the container and initialize JAAS
via the `java.security.auth.login.config` system property, which is passed to the JVM via the ENV `JDK_JAVA_OPTIONS` as follows:
 `$> podman run --name=artemis-amqp -dp 61616:61616 --env JDK_JAVA_OPTIONS=-Djava.security.auth.login.config=/app/etc/login.config --privileged -v ./amqp_sasl_scram_test__etc:/app/etc localhost/target/activemq-artemis-image:<version>`
Execute the artemis producer/consumer command line tools to validate secure access to the TEST queue using AMQP
SASL-SCRAM with your chosen password via:
 `$> ./bin/artemis producer --protocol amqp --url amqp://localhost:61616 --user A --password <some value>`
 `$> ./bin/artemis consumer --protocol amqp --url amqp://localhost:61616 --user A --password <some value>`
####byoc__etc
This is an example of "Bring Your Own Config" or BYOC. The image will look for `/app/etc/broker.xml`. If that file exists
it will be treated as the broker xml configuration for the embedded broker. If your existing configuration is nicely
locked down or if you want to provide some custom defaults for your image, referencing an existing broker.xml makes sense.
Property files can still be used to augment the defaults or be used solely for more dynamic parts of configuration.
To exercise the example, `./byoc__etc directory` as `/app/etc` for the container as follows:
 `$> podman run --name=artemis-byoc -dp 61616:61616 --privileged -v ./byoc__etc:/app/etc localhost/target/activemq-artemis-image:<version>`
Peek at the broker logs to note the broker name 'byoc' configured from the broker.xml file
`$> podman logs artemis-byoc
Execute the artemis producer/consumer command line tools to validate, it behaves like the bare image:
 `$> ./bin/artemis producer --url tcp://localhost:61616`
 `$> ./bin/artemis consumer --url tcp://localhost:61616`

View File

@ -0,0 +1,44 @@
## ---------------------------------------------------------------------------
## 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.
## ---------------------------------------------------------------------------
## reset to default
securityEnabled=true
## reference user role files with login.config, -Djava.security.auth.login.config=jaas/login.config
## the broker JAAS domain in login.config
acceptorConfigurations.tcp.params.securityDomain=broker
## lock down broker acceptor
## to SCRAM AMQP
acceptorConfigurations.tcp.params.saslMechanisms=SCRAM-SHA-512
acceptorConfigurations.tcp.params.protocols=AMQP
acceptorConfigurations.tcp.params.saslLoginConfigScope=amqp-sasl-scram
## if over TLS, configure acceptor key and trust store
# acceptorConfigurations.tcp.params.sslEnabled=true
# acceptorConfigurations.tcp.params.keyStorePath=/app/etc/<keystore>.keystore
# acceptorConfigurations.tcp.params.keyStorePassword=<password>
## create TEST address and ANYCAST queue b/c we won't have createX permissions
## TEST is the default queue for ./bin/artemis producer
addressConfigurations.TEST.queueConfigs.TEST.routingType=ANYCAST
## grant users role read/write
securityRoles.TEST.users.send=true
securityRoles.TEST.users.consume=true

View File

@ -0,0 +1,26 @@
/*
* 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.
*/
amqp-sasl-scram {
org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule required
;
};
broker {
org.apache.activemq.artemis.spi.core.security.jaas.SCRAMLoginModule required
;
};

View File

@ -0,0 +1,18 @@
## ---------------------------------------------------------------------------
## 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.
## ---------------------------------------------------------------------------
users=A

View File

@ -0,0 +1,46 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:activemq"
xsi:schemaLocation="urn:activemq:core schema/artemis-configuration.xsd">
<core xmlns="urn:activemq:core">
<!--
Configure an image in the traditional way.
Providing boilerplate xml can form the well known configuration for an organisational base image that can be further extended with properties
-->
<!-- set an example specific name, it appears in the started/stopped logging messages -->
<name>byoc</name>
<security-enabled>false</security-enabled>
<!-- broker properties in the image are still in play so there will be an acceptor
configured from src/main/resources/acceptors.properties -->
<addresses>
<address name="TEST">
<anycast>
<queue name="TEST"/>
</anycast>
</address>
</addresses>
</core>
</configuration>

View File

@ -0,0 +1,77 @@
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-pom</artifactId>
<version>2.29.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>artemis-image-examples</artifactId>
<name>Apache ActiveMQ Artemis Image Examples</name>
<packaging>pom</packaging>
<properties>
<!-- for checkstyle plugin -->
<activemq.basedir>${project.basedir}/../..</activemq.basedir>
<!-- for the locked down example user A is referenced in the amqp_sasl_scram_test__etc/role file,
so don't just change it here! -->
<example.user>A</example.user>
<!-- a password must be provided to generate the user credential data.
use: mvn exec:exec -Dexample.pwd=xyz on the command line to register your value in the example.user.file -->
<example.pwd></example.pwd>
<example.user.file>amqp_sasl_scram_test__etc/user</example.user.file>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-server</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- to easily create a single salted credential for our ${example.user.file}-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-plugin.version}</version>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<classpath/>
<argument>org.apache.activemq.artemis.spi.core.security.jaas.SCRAMPropertiesLoginModule</argument>
<argument>${example.user}</argument>
<argument>${example.pwd}</argument>
</arguments>
<outputFile>${example.user.file}</outputFile>
</configuration>
</plugin>
</plugins>
</build>
</project>

105
artemis-image/pom.xml Normal file
View File

@ -0,0 +1,105 @@
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-pom</artifactId>
<version>2.29.0-SNAPSHOT</version>
</parent>
<artifactId>artemis-image</artifactId>
<name>Apache ActiveMQ Artemis Image</name>
<properties>
<!-- base jre image, reproducible build and single pull with @sha reference -->
<fromImage>eclipse-temurin:20-jre@sha256:5340605ada8bee017109147c838a96a24ecec037bedac5f157b26817ab633e02</fromImage>
<!-- for checkstyle plugin -->
<activemq.basedir>${project.basedir}/..</activemq.basedir>
<!-- none of the surefire project defaults are relevant to the tests here -->
<activemq-surefire-argline></activemq-surefire-argline>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>apache-artemis</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- The johnzon-core and json-api contents are repackaged in -commons,
However maven can still need them during tests that don't see the shaded bits during build -->
<dependency>
<groupId>org.apache.johnzon</groupId>
<artifactId>johnzon-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<configuration>
<from>
<image>${fromImage}</image>
</from>
<to>
<image>target/activemq-artemis-image:${project.version}</image>
</to>
<container>
<mainClass>org.apache.activemq.artemis.core.server.embedded.Main</mainClass>
<ports>
<port>61616</port>
</ports>
<format>OCI</format>
</container>
</configuration>
<executions>
<execution>
<id>now</id>
<!-- build from command line with: mvn jib:buildTar@now -->
<phase>none</phase>
<goals>
<goal>buildTar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,21 @@
# 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.
acceptorConfigurations.tcp.factoryClassName=org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory
acceptorConfigurations.tcp.params.host=0.0.0.0
acceptorConfigurations.tcp.params.port=61616
# free for all with all protocols - good for demos
securityEnabled=false

View File

@ -0,0 +1,20 @@
# 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.
appender.stdout.name = STDOUT
appender.stdout.type = Console
# default config in log4j is error, we want info by default
rootLogger = info, STDOUT

View File

@ -0,0 +1,87 @@
/*
* 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.
*/
package org.apache.activemq.artemis;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
import org.apache.activemq.artemis.core.server.embedded.Main;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.activemq.artemis.core.server.embedded.Main.configureDataDirectory;
public class ActiveMQImageExamplesTest {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Test
public void testSamlScram_etc() throws Exception {
ConfigurationImpl configuration = new ConfigurationImpl();
String dataDir = "./target/data";
configureDataDirectory(configuration, dataDir);
EmbeddedActiveMQ server = new EmbeddedActiveMQ();
// look for properties files to augment configuration
server.setPropertiesResourcePath("./src/main/resources/,./examples/amqp_sasl_scram_test__etc/");
server.setConfiguration(configuration);
server.start();
server.stop();
}
@Test
public void testBYOC_etc() throws Exception {
final CountDownLatch done = new CountDownLatch(1);
Thread thread = new Thread(() -> {
try {
// contents byoc__etc copied to ./target/ to satisfy etc/broker.xml
Main.main(new String[] {"./target"});
done.countDown();
} catch (Exception e) {
logger.info("unexpected", e);
}
});
thread.start();
// shut it down after it starts!
do {
if (Main.getEmbeddedServer() != null) {
if (Main.getEmbeddedServer().getActiveMQServer() != null) {
if (Main.getEmbeddedServer().getActiveMQServer().getState() == ActiveMQServer.SERVER_STATE.STARTED) {
logger.trace("stopping server, state={}", Main.getEmbeddedServer().getActiveMQServer().getState());
Main.getEmbeddedServer().stop();
}
}
}
}
while (!done.await(200, TimeUnit.MILLISECONDS));
}
}

View File

@ -105,7 +105,7 @@ public class EmbeddedJMS extends EmbeddedActiveMQ {
@Override
public EmbeddedJMS start() throws Exception {
super.initStart();
super.createActiveMQServer();
if (jmsConfiguration != null) {
serverManager = new JMSServerManagerImpl(activeMQServer, jmsConfiguration);
} else {

View File

@ -130,12 +130,15 @@ public class EmbeddedActiveMQ {
}
public EmbeddedActiveMQ start() throws Exception {
initStart();
createActiveMQServer();
activeMQServer.start();
return this;
}
protected void initStart() throws Exception {
public void createActiveMQServer() throws Exception {
if (activeMQServer != null) {
return;
}
if (configuration == null) {
if (configResourcePath == null)
configResourcePath = "broker.xml";

View File

@ -0,0 +1,148 @@
/*
* 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.
*/
package org.apache.activemq.artemis.core.server.embedded;
import java.io.File;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.CountDownLatch;
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
import org.apache.activemq.artemis.core.config.impl.LegacyJMSConfiguration;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static String workDir = "/app";
private static volatile EmbeddedActiveMQ embeddedServer;
public static void main(String[] args) throws Exception {
if (args.length == 1) {
workDir = args[0];
logger.debug("User supplied work dir {}", workDir);
}
String propertiesConfigPath = "/config/," + workDir + "/etc/";
if (args.length == 2) {
propertiesConfigPath = args[1];
logger.debug("User supplied properties config path {}", propertiesConfigPath);
}
FileConfiguration configuration = new FileConfiguration();
String dataDir = workDir + "/data";
configureDataDirectory(configuration, dataDir);
File bringYourOwnXml = new File(workDir + "/etc/broker.xml");
if (bringYourOwnXml.exists()) {
logger.debug("byo config found {}", bringYourOwnXml);
configuration = loadFromXmlFile(bringYourOwnXml, configuration);
}
embeddedServer = new EmbeddedActiveMQ();
// look for properties files to augment configuration
embeddedServer.setPropertiesResourcePath(propertiesConfigPath);
embeddedServer.setConfiguration(configuration);
embeddedServer.createActiveMQServer();
final ActiveMQServer activeMQServer = embeddedServer.getActiveMQServer();
final CountDownLatch serverStopped = new CountDownLatch(1);
registerCallbackToTriggerLatchOnStopped(activeMQServer, serverStopped);
exitWithErrorOnStartFailure(activeMQServer);
addShutdownHookForServerStop(embeddedServer);
logger.debug("starting server");
embeddedServer.start();
logger.debug("await server stop");
serverStopped.await();
embeddedServer = null;
}
private static void exitWithErrorOnStartFailure(ActiveMQServer activeMQServer) {
activeMQServer.registerActivationFailureListener(exception -> {
logger.error("server failed to start {}, exit(1) in thread", exception);
new Thread("exit(1)-on-start-failure") {
@Override
public void run() {
logger.error("exit(1)");
Runtime.getRuntime().exit(1);
}
}.start();
});
}
private static void registerCallbackToTriggerLatchOnStopped(ActiveMQServer activeMQServer, CountDownLatch serverStopped) {
activeMQServer.registerActivateCallback(new ActivateCallback() {
@Override
public void stop(ActiveMQServer server) {
logger.trace("server stop, state {}", server.getState());
serverStopped.countDown();
}
@Override
public void shutdown(ActiveMQServer server) {
logger.trace("server shutdown, state {}", server.getState());
serverStopped.countDown();
}
});
}
private static void addShutdownHookForServerStop(final EmbeddedActiveMQ server) {
Runtime.getRuntime().addShutdownHook(new Thread("shutdown-hook") {
@Override
public void run() {
try {
logger.trace("stop via shutdown hook");
server.stop();
} catch (Exception ignored) {
// we want to exit fast and silently
logger.trace("Error on stop {}", ignored);
}
}
});
}
public static FileConfiguration loadFromXmlFile(File bringYourOwnXml, FileConfiguration base) throws Exception {
FileDeploymentManager deploymentManager = new FileDeploymentManager(bringYourOwnXml.toURI().toASCIIString());
LegacyJMSConfiguration legacyJMSConfiguration = new LegacyJMSConfiguration(base);
deploymentManager.addDeployable(base).addDeployable(legacyJMSConfiguration);
deploymentManager.readConfiguration();
return base;
}
public static void configureDataDirectory(ConfigurationImpl configuration, String dataDir) {
// any provided value via xml config or properties will override
configuration.setJournalDirectory(dataDir);
// setting these gives a better log message, not necessary otherwise
configuration.setBindingsDirectory(dataDir + "/bindings");
configuration.setLargeMessagesDirectory(dataDir + "/largemessages");
configuration.setPagingDirectory(dataDir + "/paging");
}
public static EmbeddedActiveMQ getEmbeddedServer() {
return embeddedServer;
}
}

View File

@ -608,6 +608,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
internalStart();
} catch (Throwable t) {
ActiveMQServerLogger.LOGGER.failedToStartServer(t);
throw t;
} finally {
if (originalState == SERVER_STATE.STOPPED) {
reloadNetworkHealthCheck();

View File

@ -0,0 +1,30 @@
/*
* 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.
*/
package org.apache.activemq.artemis.core.server.embedded;
import java.io.IOException;
import org.junit.Test;
public class MainTest {
@Test(expected = IOException.class)
public void testNull() throws Exception {
Main.main(new String[]{});
}
}

View File

@ -68,6 +68,8 @@
<module>artemis-features</module>
<module>artemis-quorum-api</module>
<module>artemis-quorum-ri</module>
<module>artemis-image</module>
<module>artemis-image/examples</module>
</modules>
<name>ActiveMQ Artemis Parent</name>
@ -105,6 +107,7 @@
<errorprone.version>2.10.0</errorprone.version>
<maven.bundle.plugin.version>5.1.9</maven.bundle.plugin.version>
<maven.checkstyle.plugin.version>3.1.2</maven.checkstyle.plugin.version>
<jib.maven.plugin.version>3.3.2</jib.maven.plugin.version>
<sevntu.checks.version>1.39.0</sevntu.checks.version>
<checkstyle.version>9.2.1</checkstyle.version>
<mockito.version>5.2.0</mockito.version>
@ -1892,6 +1895,11 @@
</artifactItems>
</configuration>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>${jib.maven.plugin.version}</version>
</plugin>
</plugins>
</build>