Skip to content

Commit 2a6bd31

Browse files
authored
Merge pull request #22 from eclipse-ee4j/ondromih-change-passwords
Custom init.sh script, master/admin passwords via ENV vars
2 parents 062a858 + 8812308 commit 2a6bd31

File tree

12 files changed

+488
-71
lines changed

12 files changed

+488
-71
lines changed

pom.xml

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55

66
<groupId>org.glassfish.main.distributions</groupId>
@@ -30,7 +30,7 @@
3030
<dependency>
3131
<groupId>org.junit.jupiter</groupId>
3232
<artifactId>junit-jupiter-engine</artifactId>
33-
<version>5.11.3</version>
33+
<version>5.11.4</version>
3434
<scope>test</scope>
3535
</dependency>
3636
<dependency>
@@ -42,13 +42,14 @@
4242
<dependency>
4343
<groupId>org.testcontainers</groupId>
4444
<artifactId>testcontainers</artifactId>
45-
<version>1.20.3</version>
45+
<version>1.20.4</version>
4646
<scope>test</scope>
4747
</dependency>
4848
<dependency>
4949
<groupId>org.testcontainers</groupId>
5050
<artifactId>junit-jupiter</artifactId>
51-
<version>1.20.3</version>
51+
<version>1.20.4</version>
52+
<scope>test</scope>
5253
</dependency>
5354
</dependencies>
5455

src/main/resources/Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ RUN true \
5757
&& echo "Generating password file at ${AS_PASSWORD_FILE} ..." \
5858
&& set +x \
5959
&& echo "AS_ADMIN_PASSWORD=${AS_ADMIN_PASSWORD}" > "${AS_PASSWORD_FILE}" \
60+
&& chown glassfish:glassfish "${AS_PASSWORD_FILE}" \
6061
&& echo "AS_ADMIN_PASSWORD=" > "${PATH_GF_PASSWORD_FILE_FOR_CHANGE}" \
6162
&& echo "AS_ADMIN_NEWPASSWORD=${AS_ADMIN_PASSWORD}" >> "${PATH_GF_PASSWORD_FILE_FOR_CHANGE}" \
6263
&& echo "" >> "${PATH_GF_PASSWORD_FILE_FOR_CHANGE}" \

src/main/resources/docker-entrypoint.sh

+35
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,41 @@
11
#!/bin/bash
22
set -e;
33

4+
change_passwords () {
5+
local PWD_FILE=/tmp/passwordfile
6+
local COMMAND=
7+
rm -rf $PWD_FILE
8+
9+
if [ x"${AS_ADMIN_PASSWORD}" != x ]; then
10+
echo -e "AS_ADMIN_PASSWORD=admin\nAS_ADMIN_NEWPASSWORD=${AS_ADMIN_PASSWORD}" >> $PWD_FILE
11+
COMMAND="change-admin-password --passwordfile=${PWD_FILE}"
12+
echo "AS_ADMIN_PASSWORD=${AS_ADMIN_PASSWORD}" > "${AS_PASSWORD_FILE}"
13+
fi
14+
15+
if [ x"${AS_ADMIN_MASTERPASSWORD}" != x ]; then
16+
echo -e "AS_ADMIN_MASTERPASSWORD=changeit\nAS_ADMIN_NEWMASTERPASSWORD=${AS_ADMIN_MASTERPASSWORD}" >> ${PWD_FILE}
17+
COMMAND="${COMMAND}
18+
change-master-password --passwordfile=${PWD_FILE} --savemasterpassword=true"
19+
fi
20+
21+
if [ x"${COMMAND}" != x ]; then
22+
printf "${COMMAND}" | asadmin --interactive=false
23+
fi
24+
25+
rm -rf ${PWD_FILE}
26+
}
27+
28+
change_passwords
29+
30+
if [ -f custom/init.sh ]; then
31+
/bin/bash custom/init.sh
32+
fi
33+
34+
if [ -f custom/init.asadmin ]; then
35+
asadmin --interactive=false multimode -f custom/init.asadmin
36+
fi
37+
38+
439
if [ "$1" != 'asadmin' -a "$1" != 'startserv' -a "$1" != 'runembedded' ]; then
540
exec "$@"
641
fi

src/main/resources/docs/content.md

+110-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ To deploy an application, copy the application into the Docker image or mount th
6363
docker run -p 8080:8080 @docker.glassfish.repository@ runembedded myapp.war
6464
```
6565

66-
6766
## Run an application with GlassFish in Docker
6867

6968
You can run an application located in your filesystem with GlassFIsh in a Docker container.
@@ -100,6 +99,116 @@ If you need suspend GlassFish startup until you connect the debugger, use the `-
10099
docker run -p 9009:9009 -p 8080:8080 -p 4848:4848 @docker.glassfish.repository@ startserv --suspend
101100
```
102101

102+
## Environment variables
103+
104+
The following environment variables can be set to configure GlassFish Server:
105+
106+
* `AS_ADMIN_MASTERPASSWORD` - to change the default master password
107+
* `AS_ADMIN_PASSWORD` - to change the default admin password
108+
109+
The following environment variables are read-only and can be used in derived Docker images or scripts:
110+
111+
* `AS_PASSWORD_FILE` - path to the password file with the admin password. It's applied by default to any asadmin command
112+
* `AS_ADMIN_USER` - name of the admin user. It's applied by default to any asadmin command
113+
* `PATH_GF_HOME` - directory of the GlassFish installation. Also the default working directory
114+
* `PATH_GF_SERVER_LOG` - path to the server log file
115+
116+
## Additional configuration
117+
118+
It's possible to specify custom commands to run in the Docker container before GlassFish server starts. The following methods are supported:
119+
120+
* `${PATH_GF_HOME}/custom/init.sh` - Execute any `bash` script, which can execute admin commands via the `asadmin` command line tool
121+
* `${PATH_GF_HOME}/custom/init.asadmin` - Execute asadmin commands directly
122+
123+
If both of the above scripts are present, they are executed in this order:
124+
125+
1. `init.sh`
126+
2. `init.asadmin`
127+
128+
However, always consider to executing any asadmin configuration commands during build, because configuring the server at container startup will prolong the startup time.
129+
130+
### Execute asadmin commands before server startup
131+
132+
Just create a file `${PATH_GF_HOME}/custom/init.asadmin` (`/opt/glassfish7/custom/init.asadmin`), the commands will be executed before GlassFish server starts.
133+
134+
Within the `init.asadmin` file, you can specify any asadmin command. Most of the commands require that the server is running, so you'll need to start the server first, run the configuration commands, and then stop the server.
135+
136+
For example, to start GlassFish, increase the maximum amount of threads, and then stop it, the `init.asadmin` file can contain:
137+
138+
```
139+
start-domain
140+
set configs.config.server-config.thread-pools.thread-pool.http-thread-pool.max-thread-pool-size=1000
141+
stop-domain
142+
```
143+
144+
You can provide the file by mounting its directory to the `/opt/glassfish7/custom` directory in the container when running the container:
145+
146+
```
147+
docker run -v ./custom:/opt/glassfish7/custom -p 8080:8080 -ti @docker.glassfish.repository@
148+
```
149+
150+
### Execute a `bash` script before server startup
151+
152+
Just create a Bash script `${PATH_GF_HOME}/custom/init.sh` (`/opt/glassfish7/custom/init.sh`), it will be executed before GlassFish server starts.
153+
154+
Within the `init.sh` script, you can run any asadmin command, with `asadmin --interactive=false multimode COMMAND`. Most of the commands require that the server is running, so you'll need to start the server first, run the configuration commands, and then stop the server. If you need to run multiple commands, we recomment running asadmin commands in a single "multimode" asadmin execution to run them faster, with commands provided either on standard input or in a separate file via the `asadmin --interactive=false multimode -f` option.
155+
156+
----
157+
158+
**NOTE:** If you only need to execute `asadmin` commands before server startup, it's easier to use the init.asadmin script to execute them directly, without a `bash` script.
159+
160+
----
161+
162+
For example, to start GlassFish, increase the maximum amount of threads, and then stop it, the `init.sh` script can contain:
163+
164+
```
165+
echo "start-domain
166+
set configs.config.server-config.thread-pools.thread-pool.http-thread-pool.max-thread-pool-size=1000
167+
stop-domain" | asadmin --interactive=false
168+
```
169+
170+
You can provide the script by mounting its directory to the `/opt/glassfish7/custom` directory in the container when running the container:
171+
172+
```
173+
docker run -v ./custom:/opt/glassfish7/custom -p 8080:8080 -ti @docker.glassfish.repository@
174+
```
175+
176+
### Execute `asadmin` commands during Docker image build
177+
178+
Applying the configuration can be a lengthy operation. If you can configure the server during build time, it's recommended running asadmin configuration commands in a custom Docker image. This moves the configuration step to the image build time instead of runtime.
179+
180+
To do it, simply add `RUN instructions that run `asadmin` script with the usual arguments. For example, to move the example configuration from the `init.sh` script above to Dockerfile:
181+
182+
File `Dockerfile`:
183+
184+
```
185+
FROM @docker.glassfish.repository@
186+
187+
RUN printf "start-domain \n \
188+
set configs.config.server-config.thread-pools.thread-pool.http-thread-pool.max-thread-pool-size=1000 \n \
189+
stop-domain" | asadmin --interactive=false
190+
```
191+
192+
Or you can put the asadmin commands into a separate file and run it using `asadmin --interactive=false multimode -f`. For example:
193+
194+
File `commands.asadmin`:
195+
196+
```
197+
start-domain
198+
set configs.config.server-config.thread-pools.thread-pool.http-thread-pool.max-thread-pool-size=1000
199+
stop-domain
200+
```
201+
202+
File `Dockerfile`:
203+
204+
```
205+
FROM @docker.glassfish.repository@
206+
207+
COPY commands.asadmin commands.asadmin
208+
209+
RUN asadmin --interactive=false multimode -f commands.asadmin
210+
```
211+
103212
## Examples of advanced usage
104213

105214
Let's try something more complicated.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Contributors to the Eclipse Foundation.
2+
* Copyright (c) 2024,2025 Contributors to the Eclipse Foundation.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -13,14 +13,9 @@
1313
*
1414
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
*/
16-
1716
package org.glassfish.main.distributions.docker;
1817

19-
import java.io.InputStream;
20-
import java.net.HttpURLConnection;
21-
import java.net.URI;
22-
import java.net.URL;
23-
import java.nio.charset.StandardCharsets;
18+
import java.net.http.HttpResponse;
2419

2520
import org.junit.jupiter.api.Test;
2621
import org.testcontainers.containers.GenericContainer;
@@ -30,6 +25,7 @@
3025
import static org.hamcrest.MatcherAssert.assertThat;
3126
import static org.hamcrest.Matchers.stringContainsInOrder;
3227
import static org.junit.jupiter.api.Assertions.assertEquals;
28+
import static org.glassfish.main.distributions.docker.HttpUtilities.getServerDefaultRoot;
3329

3430
/**
3531
*
@@ -40,23 +36,13 @@ public class AsadminIT {
4036
@SuppressWarnings({"rawtypes", "resource"})
4137
@Container
4238
private final GenericContainer server = new GenericContainer<>(System.getProperty("docker.glassfish.image"))
43-
.withCommand("asadmin start-domain").withExposedPorts(8080)
44-
.withLogConsumer(o -> System.err.print("GF: " + o.getUtf8String()));
39+
.withCommand("asadmin start-domain").withExposedPorts(8080)
40+
.withLogConsumer(o -> System.err.print("GF: " + o.getUtf8String()));
4541

4642
@Test
47-
void getRoot() throws Exception {
48-
URL url = URI.create("http://localhost:" + server.getMappedPort(8080) + "/").toURL();
49-
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
50-
String content;
51-
try {
52-
connection.setRequestMethod("GET");
53-
assertEquals(200, connection.getResponseCode(), "Response code");
54-
try (InputStream in = connection.getInputStream()) {
55-
content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
56-
}
57-
} finally {
58-
connection.disconnect();
59-
}
60-
assertThat(content, stringContainsInOrder("Eclipse GlassFish", "index.html", "production-quality"));
43+
void rootResourceGivesOkWithDefaultResponse() throws Exception {
44+
final HttpResponse<String> defaultRootResponse = getServerDefaultRoot(server);
45+
assertEquals(200, defaultRootResponse.statusCode(), "Response status code");
46+
assertThat(defaultRootResponse.body(), stringContainsInOrder("Eclipse GlassFish", "index.html", "production-quality"));
6147
}
6248
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
package org.glassfish.main.distributions.docker;
17+
18+
import java.net.http.HttpResponse;
19+
20+
import org.junit.jupiter.api.Test;
21+
import org.testcontainers.containers.GenericContainer;
22+
import org.testcontainers.junit.jupiter.Container;
23+
import org.testcontainers.junit.jupiter.Testcontainers;
24+
25+
import static org.glassfish.main.distributions.docker.HttpUtilities.getServerDefaultRoot;
26+
import static org.hamcrest.MatcherAssert.assertThat;
27+
import static org.hamcrest.Matchers.stringContainsInOrder;
28+
import static org.junit.jupiter.api.Assertions.assertEquals;
29+
import static org.glassfish.main.distributions.docker.HttpUtilities.getAdminResource;
30+
31+
/**
32+
*
33+
* @author Ondro Mihalyi
34+
*/
35+
@Testcontainers
36+
public class ChangePasswordsIT {
37+
38+
@SuppressWarnings({"rawtypes", "resource"})
39+
@Container
40+
private final GenericContainer server = new GenericContainer<>(System.getProperty("docker.glassfish.image"))
41+
.withExposedPorts(8080, 4848)
42+
.withEnv("AS_ADMIN_MASTERPASSWORD", "mymasterpassword")
43+
.withEnv("AS_ADMIN_PASSWORD", "myadminpassword")
44+
.withLogConsumer(o -> System.err.print("GF: " + o.getUtf8String()));
45+
46+
@Test
47+
void rootResourceGivesOkWithDefaultResponse() throws Exception {
48+
final HttpResponse<String> defaultRootResponse = getServerDefaultRoot(server);
49+
assertEquals(200, defaultRootResponse.statusCode(), "Response status code");
50+
assertThat(defaultRootResponse.body(), stringContainsInOrder("Eclipse GlassFish", "index.html", "production-quality"));
51+
}
52+
53+
@Test
54+
void customAdminPassword() throws Exception {
55+
final HttpResponse<String> adminResourceResponse = getAdminResource(server, "/management/domain.json",
56+
new UserPassword("admin", "myadminpassword"));
57+
assertEquals(200, adminResourceResponse.statusCode(), "Response status code");
58+
}
59+
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the
10+
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11+
* version 2 with the GNU Classpath Exception, which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
*/
16+
17+
package org.glassfish.main.distributions.docker;
18+
19+
import java.net.http.HttpResponse;
20+
21+
import org.junit.jupiter.api.Test;
22+
import org.testcontainers.containers.GenericContainer;
23+
import org.testcontainers.junit.jupiter.Container;
24+
import org.testcontainers.junit.jupiter.Testcontainers;
25+
26+
import static org.glassfish.main.distributions.docker.HttpUtilities.getServerDefaultRoot;
27+
import static org.hamcrest.MatcherAssert.assertThat;
28+
import static org.hamcrest.Matchers.stringContainsInOrder;
29+
import static org.junit.jupiter.api.Assertions.assertEquals;
30+
31+
@Testcontainers
32+
public class DefaultIT {
33+
34+
@SuppressWarnings({"rawtypes", "resource"})
35+
@Container
36+
private final GenericContainer server = new GenericContainer<>(System.getProperty("docker.glassfish.image"))
37+
.withExposedPorts(8080)
38+
.withLogConsumer(o -> System.err.print("GF: " + o.getUtf8String()));
39+
40+
@Test
41+
void rootResourceGivesOkWithDefaultResponse() throws Exception {
42+
final HttpResponse<String> defaultRootResponse = getServerDefaultRoot(server);
43+
assertEquals(200, defaultRootResponse.statusCode(), "Response status code");
44+
assertThat(defaultRootResponse.body(), stringContainsInOrder("Eclipse GlassFish", "index.html", "production-quality"));
45+
}
46+
}

0 commit comments

Comments
 (0)