Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[minor] add Dockerfile healthchecks to some core services #370

Merged
merged 9 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions activemq/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ COPY --link rootfs /

RUN create-service-user.sh --name activemq && \
cleanup.sh

HEALTHCHECK CMD curl -s \
-u admin:"$(cat /var/run/s6/container_environment/ACTIVEMQ_WEB_ADMIN_PASSWORD)" \
-H origin:localhost \
"http://localhost:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost,service=Health/CurrentStatus" \
| jq .value | grep -q Good
54 changes: 54 additions & 0 deletions activemq/tests/ServiceHealthcheck/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import plugins.TestsPlugin.DockerComposeUp
import plugins.TestsPlugin.DockerComposeUp.Companion.pool
import java.lang.Thread.sleep
import java.time.Duration.ofSeconds
import java.util.concurrent.CompletableFuture.supplyAsync
import java.io.ByteArrayOutputStream

tasks.named<DockerComposeUp>("test") {
doFirst {
supplyAsync(
{
val maxAttempts = 10
val delayBetweenAttempts = 5000L // 5 seconds in milliseconds
var attempt = 0
var foundHealthyService = false

while (attempt < maxAttempts) {
attempt++
val outputStream = ByteArrayOutputStream()
project.exec {
commandLine = baseArguments + listOf("ps", "--all")
standardOutput = outputStream
workingDir = project.projectDir
}
val output = outputStream.toString()

val healthyServicePattern = """(?m)^.+\s+.+\s+Up \d+ seconds \(healthy\).*$""".toRegex()
foundHealthyService = output.lines().any { line ->
healthyServicePattern.matches(line)
}

if (foundHealthyService) {
project.exec {
commandLine = baseArguments + listOf("stop")
standardOutput = outputStream
workingDir = project.projectDir
}
break
}

if (attempt < maxAttempts) {
println("No healthy service found. Retrying in ${delayBetweenAttempts / 1000} seconds...")
sleep(delayBetweenAttempts)
}
}

// Throw an exception if no healthy service was found after all attempts
if (!foundHealthyService) {
throw GradleException("No service is marked as healthy in docker compose ps output after $maxAttempts attempts.")
}
}, pool
)
}
}
14 changes: 14 additions & 0 deletions activemq/tests/ServiceHealthcheck/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---

# Common to all services
x-common: &common
restart: "no"

services:
activemq:
<<: *common
image: ${ACTIVEMQ:-islandora/activemq:local}
volumes:
- ./test.sh:/test.sh # Test to run.
command:
- /test.sh # Run test and exit.
13 changes: 13 additions & 0 deletions activemq/tests/ServiceHealthcheck/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/command/with-contenv bash
# shellcheck shell=bash

on_terminate() {
echo "Termination signal received. Exiting..."
exit 0
}
trap 'on_terminate' SIGTERM

sleep 60

# The kotlin check should be stopping this container
exit 1
8 changes: 6 additions & 2 deletions cantaloupe/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ ENV \
CANTALOUPE_ENDPOINT_ADMIN_ENABLED="false" \
CANTALOUPE_ENDPOINT_ADMIN_SECRET= \
CANTALOUPE_ENDPOINT_ADMIN_USERNAME="admin" \
CANTALOUPE_ENDPOINT_API_ENABLED="false" \
CANTALOUPE_ENDPOINT_API_ENABLED="true" \
CANTALOUPE_ENDPOINT_API_SECRET= \
CANTALOUPE_ENDPOINT_API_USERNAME= \
CANTALOUPE_ENDPOINT_API_USERNAME=islandora \
CANTALOUPE_ENDPOINT_HEALTH_DEPENDENCY_CHECK="false" \
CANTALOUPE_ENDPOINT_IIIF_1_ENABLED="false" \
CANTALOUPE_ENDPOINT_IIIF_2_ENABLED="true" \
Expand Down Expand Up @@ -271,3 +271,7 @@ ENV \
CANTALOUPE_TEMP_PATHNAME=

COPY --link rootfs /

HEALTHCHECK CMD curl -s \
-u "${CANTALOUPE_ENDPOINT_API_USERNAME}:$(cat /var/run/s6/container_environment/CANTALOUPE_ENDPOINT_API_SECRET)" \
http://localhost:8182/health | jq .color | grep -q GREEN
6 changes: 3 additions & 3 deletions cantaloupe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ additional settings, volumes, ports, etc.
| CANTALOUPE_ENDPOINT_ADMIN_ENABLED | "false" |
| CANTALOUPE_ENDPOINT_ADMIN_SECRET | |
| CANTALOUPE_ENDPOINT_ADMIN_USERNAME | "admin" |
| CANTALOUPE_ENDPOINT_API_ENABLED | "false" |
| CANTALOUPE_ENDPOINT_API_SECRET | |
| CANTALOUPE_ENDPOINT_API_USERNAME | |
| CANTALOUPE_ENDPOINT_API_ENABLED | "true" |
| CANTALOUPE_ENDPOINT_API_SECRET | random 16 char string |
| CANTALOUPE_ENDPOINT_API_USERNAME | "islandora" |
| CANTALOUPE_ENDPOINT_HEALTH_DEPENDENCY_CHECK | "false" |
| CANTALOUPE_ENDPOINT_IIIF_1_ENABLED | "false" |
| CANTALOUPE_ENDPOINT_IIIF_2_ENABLED | "true" |
Expand Down
8 changes: 8 additions & 0 deletions cantaloupe/rootfs/etc/cont-init.d/01-set-api-secret.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/with-contenv bash
set -e

ENV_FILE="/var/run/s6/container_environment/CANTALOUPE_ENDPOINT_API_SECRET"
if [ ! -s "$ENV_FILE" ]; then
openssl rand -hex 16 > "$ENV_FILE"
echo "CANTALOUPE_ENDPOINT_API_SECRET was empty. Set to a new random value."
fi
54 changes: 54 additions & 0 deletions cantaloupe/tests/ServiceHealthcheck/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import plugins.TestsPlugin.DockerComposeUp
import plugins.TestsPlugin.DockerComposeUp.Companion.pool
import java.lang.Thread.sleep
import java.time.Duration.ofSeconds
import java.util.concurrent.CompletableFuture.supplyAsync
import java.io.ByteArrayOutputStream

tasks.named<DockerComposeUp>("test") {
doFirst {
supplyAsync(
{
val maxAttempts = 10
val delayBetweenAttempts = 5000L // 5 seconds in milliseconds
var attempt = 0
var foundHealthyService = false

while (attempt < maxAttempts) {
attempt++
val outputStream = ByteArrayOutputStream()
project.exec {
commandLine = baseArguments + listOf("ps", "--all")
standardOutput = outputStream
workingDir = project.projectDir
}
val output = outputStream.toString()

val healthyServicePattern = """(?m)^.+\s+.+\s+Up \d+ seconds \(healthy\).*$""".toRegex()
foundHealthyService = output.lines().any { line ->
healthyServicePattern.matches(line)
}

if (foundHealthyService) {
project.exec {
commandLine = baseArguments + listOf("stop")
standardOutput = outputStream
workingDir = project.projectDir
}
break
}

if (attempt < maxAttempts) {
println("No healthy service found. Retrying in ${delayBetweenAttempts / 1000} seconds...")
sleep(delayBetweenAttempts)
}
}

// Throw an exception if no healthy service was found after all attempts
if (!foundHealthyService) {
throw GradleException("No service is marked as healthy in docker compose ps output after $maxAttempts attempts.")
}
}, pool
)
}
}
14 changes: 14 additions & 0 deletions cantaloupe/tests/ServiceHealthcheck/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---

# Common to all services
x-common: &common
restart: "no"

services:
cantaloupe:
<<: *common
image: ${CANTALOUPE:-islandora/cantaloupe:local}
volumes:
- ./test.sh:/test.sh # Test to run.
command:
- /test.sh # Run test and exit.
13 changes: 13 additions & 0 deletions cantaloupe/tests/ServiceHealthcheck/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/command/with-contenv bash
# shellcheck shell=bash

on_terminate() {
echo "Termination signal received. Exiting..."
exit 0
}
trap 'on_terminate' SIGTERM

sleep 60

# The kotlin check should be stopping this container
exit 1
55 changes: 55 additions & 0 deletions ci/healthcheck.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import plugins.TestsPlugin.DockerComposeUp
import plugins.TestsPlugin.DockerComposeUp.Companion.pool
import java.lang.Thread.sleep
import java.time.Duration.ofSeconds
import java.util.concurrent.CompletableFuture.supplyAsync
import java.io.ByteArrayOutputStream

tasks.named<DockerComposeUp>("test") {
doFirst {
supplyAsync(
{
val maxAttempts = 10
val delayBetweenAttempts = 5000L // 5 seconds in milliseconds
var attempt = 0
var foundHealthyService = false

while (attempt < maxAttempts) {
attempt++
val outputStream = ByteArrayOutputStream()
project.exec {
commandLine = baseArguments + listOf("ps", "--all")
standardOutput = outputStream
workingDir = project.projectDir
}
val output = outputStream.toString()

val healthyServicePattern = """(?m)^.+\s+.+\s+Up \d+ seconds \(healthy\).*$""".toRegex()
foundHealthyService = output.lines().any { line ->
healthyServicePattern.matches(line)
}

if (foundHealthyService) {
println("Service is healthy. Exiting test...")
project.exec {
commandLine = baseArguments + listOf("stop")
standardOutput = outputStream
workingDir = project.projectDir
}
break
}

if (attempt < maxAttempts) {
println("No healthy service found. Retrying in ${delayBetweenAttempts / 1000} seconds...")
sleep(delayBetweenAttempts)
}
}

// Throw an exception if no healthy service was found after all attempts
if (!foundHealthyService) {
throw GradleException("No service is marked as healthy in docker compose ps output after $maxAttempts attempts.")
}
}, pool
)
}
}
2 changes: 2 additions & 0 deletions fcrepo6/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,5 @@ ENV \
COPY --link rootfs /

RUN chown -R tomcat:tomcat /opt/tomcat

HEALTHCHECK CMD curl -s http://localhost:8080/fcrepo/rest/fcr:systeminfo | jq -e .version
54 changes: 54 additions & 0 deletions fcrepo6/tests/ServiceHealthcheck/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import plugins.TestsPlugin.DockerComposeUp
import plugins.TestsPlugin.DockerComposeUp.Companion.pool
import java.lang.Thread.sleep
import java.time.Duration.ofSeconds
import java.util.concurrent.CompletableFuture.supplyAsync
import java.io.ByteArrayOutputStream

tasks.named<DockerComposeUp>("test") {
doFirst {
supplyAsync(
{
val maxAttempts = 10
val delayBetweenAttempts = 5000L // 5 seconds in milliseconds
var attempt = 0
var foundHealthyService = false

while (attempt < maxAttempts) {
attempt++
val outputStream = ByteArrayOutputStream()
project.exec {
commandLine = baseArguments + listOf("ps", "--all")
standardOutput = outputStream
workingDir = project.projectDir
}
val output = outputStream.toString()

val healthyServicePattern = """(?m)^.+\s+.+\s+Up \d+ seconds \(healthy\).*$""".toRegex()
foundHealthyService = output.lines().any { line ->
healthyServicePattern.matches(line)
}

if (foundHealthyService) {
project.exec {
commandLine = baseArguments + listOf("stop")
standardOutput = outputStream
workingDir = project.projectDir
}
break
}

if (attempt < maxAttempts) {
println("No healthy service found. Retrying in ${delayBetweenAttempts / 1000} seconds...")
sleep(delayBetweenAttempts)
}
}

// Throw an exception if no healthy service was found after all attempts
if (!foundHealthyService) {
throw GradleException("No service is marked as healthy in docker compose ps output after $maxAttempts attempts.")
}
}, pool
)
}
}
18 changes: 18 additions & 0 deletions fcrepo6/tests/ServiceHealthcheck/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---

# Common to all services
x-common: &common
restart: "no"

services:
activemq:
<<: *common
image: ${ACTIVEMQ:-islandora/activemq:local}
fcrepo6:
volumes:
- ./test.sh:/test.sh # Test to run.
command:
- /test.sh # Run test and exit.
image: ${FCREPO6:-islandora/fcrepo6:local}
depends_on:
- activemq
13 changes: 13 additions & 0 deletions fcrepo6/tests/ServiceHealthcheck/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/command/with-contenv bash
# shellcheck shell=bash

on_terminate() {
echo "Termination signal received. Exiting..."
exit 0
}
trap 'on_terminate' SIGTERM

sleep 60

# The kotlin check should be stopping this container
exit 1
2 changes: 2 additions & 0 deletions mariadb/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ ENV \
MYSQL_TRANSACTION_ISOLATION=READ-COMMITTED

COPY --link rootfs /

HEALTHCHECK CMD mysqladmin ping --socket=/var/run/mysqld/mysqld.sock | grep -q alive
1 change: 1 addition & 0 deletions mariadb/tests/ServiceHealthcheck/build.gradle.kts
14 changes: 14 additions & 0 deletions mariadb/tests/ServiceHealthcheck/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---

# Common to all services
x-common: &common
restart: "no"

services:
mariadb:
<<: *common
image: ${MARIADB:-islandora/mariadb:local}
volumes:
- ./test.sh:/test.sh # Test to run.
command:
- /test.sh # Run test and exit.
Loading
Loading