This is an automated email from the ASF dual-hosted git repository.
gtully pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/main by this push:
new 587ffb223c ARTEMIS-3042 simple properties based, extensible broker
image
587ffb223c is described below
commit 587ffb223cd2461a9da5c53e5ac189b9aa24640c
Author: Gary Tully <[email protected]>
AuthorDate: Thu Jun 30 16:09:00 2022 +0100
ARTEMIS-3042 simple properties based, extensible broker image
---
.../org/apache/activemq/artemis/cli/Artemis.java | 15 ++-
.../org/apache/activemq/cli/test/ArtemisTest.java | 3 +-
artemis-image/README.md | 57 ++++++++
artemis-image/TODO.md | 7 +
artemis-image/examples/README.md | 55 ++++++++
.../amqp_sasl_scram.properties | 44 ++++++
.../amqp_sasl_scram_test__etc/login.config | 26 ++++
.../examples/amqp_sasl_scram_test__etc/role | 18 +++
artemis-image/examples/byoc__etc/broker.xml | 46 +++++++
artemis-image/examples/pom.xml | 77 +++++++++++
artemis-image/pom.xml | 105 +++++++++++++++
.../src/main/jib/config/acceptor.properties | 21 +++
artemis-image/src/main/resources/log4j2.properties | 20 +++
.../artemis/ActiveMQImageExamplesTest.java | 87 ++++++++++++
.../artemis/jms/server/embedded/EmbeddedJMS.java | 2 +-
.../core/server/embedded/EmbeddedActiveMQ.java | 7 +-
.../artemis/core/server/embedded/Main.java | 148 +++++++++++++++++++++
.../core/server/impl/ActiveMQServerImpl.java | 1 +
.../artemis/core/server/embedded/MainTest.java | 30 +++++
pom.xml | 8 ++
20 files changed, 766 insertions(+), 11 deletions(-)
diff --git
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
index 31bd72ffd6..4242e75526 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
@@ -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();
}
}
}
diff --git
a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
index d534224b9c..6d1f994b12 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
@@ -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
diff --git a/artemis-image/README.md b/artemis-image/README.md
new file mode 100644
index 0000000000..cb959c6213
--- /dev/null
+++ b/artemis-image/README.md
@@ -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.
+
diff --git a/artemis-image/TODO.md b/artemis-image/TODO.md
new file mode 100644
index 0000000000..4a07a03643
--- /dev/null
+++ b/artemis-image/TODO.md
@@ -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
\ No newline at end of file
diff --git a/artemis-image/examples/README.md b/artemis-image/examples/README.md
new file mode 100644
index 0000000000..36e7078c45
--- /dev/null
+++ b/artemis-image/examples/README.md
@@ -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`
+
diff --git
a/artemis-image/examples/amqp_sasl_scram_test__etc/amqp_sasl_scram.properties
b/artemis-image/examples/amqp_sasl_scram_test__etc/amqp_sasl_scram.properties
new file mode 100644
index 0000000000..59fc7b5691
--- /dev/null
+++
b/artemis-image/examples/amqp_sasl_scram_test__etc/amqp_sasl_scram.properties
@@ -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
+
diff --git a/artemis-image/examples/amqp_sasl_scram_test__etc/login.config
b/artemis-image/examples/amqp_sasl_scram_test__etc/login.config
new file mode 100644
index 0000000000..536414f9f1
--- /dev/null
+++ b/artemis-image/examples/amqp_sasl_scram_test__etc/login.config
@@ -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
+ ;
+};
diff --git a/artemis-image/examples/amqp_sasl_scram_test__etc/role
b/artemis-image/examples/amqp_sasl_scram_test__etc/role
new file mode 100644
index 0000000000..bff70b03f7
--- /dev/null
+++ b/artemis-image/examples/amqp_sasl_scram_test__etc/role
@@ -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
diff --git a/artemis-image/examples/byoc__etc/broker.xml
b/artemis-image/examples/byoc__etc/broker.xml
new file mode 100644
index 0000000000..425624ed99
--- /dev/null
+++ b/artemis-image/examples/byoc__etc/broker.xml
@@ -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>
\ No newline at end of file
diff --git a/artemis-image/examples/pom.xml b/artemis-image/examples/pom.xml
new file mode 100644
index 0000000000..dee58330f8
--- /dev/null
+++ b/artemis-image/examples/pom.xml
@@ -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>
diff --git a/artemis-image/pom.xml b/artemis-image/pom.xml
new file mode 100644
index 0000000000..f580745127
--- /dev/null
+++ b/artemis-image/pom.xml
@@ -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>
diff --git a/artemis-image/src/main/jib/config/acceptor.properties
b/artemis-image/src/main/jib/config/acceptor.properties
new file mode 100644
index 0000000000..526af5e590
--- /dev/null
+++ b/artemis-image/src/main/jib/config/acceptor.properties
@@ -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
diff --git a/artemis-image/src/main/resources/log4j2.properties
b/artemis-image/src/main/resources/log4j2.properties
new file mode 100644
index 0000000000..a0296fb6b0
--- /dev/null
+++ b/artemis-image/src/main/resources/log4j2.properties
@@ -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
\ No newline at end of file
diff --git
a/artemis-image/src/test/java/org/apache/activemq/artemis/ActiveMQImageExamplesTest.java
b/artemis-image/src/test/java/org/apache/activemq/artemis/ActiveMQImageExamplesTest.java
new file mode 100644
index 0000000000..4a205845c1
--- /dev/null
+++
b/artemis-image/src/test/java/org/apache/activemq/artemis/ActiveMQImageExamplesTest.java
@@ -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));
+ }
+}
\ No newline at end of file
diff --git
a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
index 4904242c7b..150988317e 100644
---
a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
+++
b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/embedded/EmbeddedJMS.java
@@ -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 {
diff --git
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
index 197134dd04..26190d68d0 100644
---
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
+++
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/EmbeddedActiveMQ.java
@@ -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";
diff --git
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/Main.java
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/Main.java
new file mode 100644
index 0000000000..cf3517d308
--- /dev/null
+++
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/embedded/Main.java
@@ -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;
+ }
+}
diff --git
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
index b01a3ca759..425069f49c 100644
---
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
+++
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
@@ -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();
diff --git
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/embedded/MainTest.java
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/embedded/MainTest.java
new file mode 100644
index 0000000000..92e1d532ac
--- /dev/null
+++
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/server/embedded/MainTest.java
@@ -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[]{});
+ }
+}
diff --git a/pom.xml b/pom.xml
index dbaf2b603e..1d45a24f9a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -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>