From c30e5217cb2cde9def8272727d0dfbd8d716fce6 Mon Sep 17 00:00:00 2001 From: Chris Burgess Date: Wed, 5 Feb 2025 12:54:03 +1300 Subject: [PATCH 1/4] Show link to Github project from image READMEs (#373) --- activemq/README.md | 2 ++ alpaca/README.md | 2 ++ base/README.md | 2 ++ blazegraph/README.md | 2 ++ cantaloupe/README.md | 2 ++ code-server/README.md | 2 ++ crayfish/README.md | 2 ++ crayfits/README.md | 2 ++ drupal/README.md | 2 ++ fcrepo6/README.md | 2 ++ fits/README.md | 2 ++ handle/README.md | 2 ++ homarus/README.md | 2 ++ houdini/README.md | 2 ++ hypercube/README.md | 2 ++ java/README.md | 2 ++ mariadb/README.md | 2 ++ matomo/README.md | 2 ++ milliner/README.md | 2 ++ nginx/README.md | 2 ++ postgresql/README.md | 2 ++ riprap/README.md | 2 ++ solr/README.md | 2 ++ test/README.md | 2 ++ tomcat/README.md | 2 ++ 25 files changed, 50 insertions(+) diff --git a/activemq/README.md b/activemq/README.md index d9dac121..0f602887 100644 --- a/activemq/README.md +++ b/activemq/README.md @@ -2,6 +2,8 @@ Docker image for [ActiveMQ] version 5.18.6. +Built from [Islandora-DevOps/isle-buildkit activemq](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/activemq) + Please refer to the [ActiveMQ Documentation] for more in-depth information. As a quick example this will bring up an instance of ActiveMQ, and allow you to diff --git a/alpaca/README.md b/alpaca/README.md index d5b369b6..6a43e36d 100644 --- a/alpaca/README.md +++ b/alpaca/README.md @@ -2,6 +2,8 @@ Docker image for [Alpaca] version 2.2.0. +Built from [Islandora-DevOps/isle-buildkit alpaca](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/alpaca) + Please refer to the [Alpaca Documentation] for more in-depth information. ## Dependencies diff --git a/base/README.md b/base/README.md index a2ce2040..68c34327 100644 --- a/base/README.md +++ b/base/README.md @@ -3,6 +3,8 @@ Base Docker image from which almost all others are derived. It is not meant to be run on its own. +Built from [Islandora-DevOps/isle-buildkit base](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/base) + It's based off off [Alpine Linux], and includes [s6 overlay] and [confd]. ## Dependencies diff --git a/blazegraph/README.md b/blazegraph/README.md index 778b1b5d..40c56a36 100644 --- a/blazegraph/README.md +++ b/blazegraph/README.md @@ -2,6 +2,8 @@ Docker image for [Blazegraph] version 2.1.5. +Built from [Islandora-DevOps/isle-buildkit blazegraph](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/blazegraph) + Please refer to the [Blazegraph Documentation] for more in-depth information. As a quick example this will bring up an instance of [Blazegraph], and allow you diff --git a/cantaloupe/README.md b/cantaloupe/README.md index ba9e30ac..ba265738 100644 --- a/cantaloupe/README.md +++ b/cantaloupe/README.md @@ -2,6 +2,8 @@ Docker image for [Cantaloupe] version 5.0.6. +Built from [Islandora-DevOps/isle-buildkit cantaloupe](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/cantaloupe) + Please refer to the [Cantaloupe Documentation] for more in-depth information. As a quick example this will bring up an instance of [Cantaloupe], and allow you diff --git a/code-server/README.md b/code-server/README.md index 0dff3373..6e44a403 100644 --- a/code-server/README.md +++ b/code-server/README.md @@ -2,6 +2,8 @@ Docker image for [code-server] 4.8.3. +Built from [Islandora-DevOps/isle-buildkit code-server](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/code-server) + Please refer to the [code-server Documentation] for more in-depth information. Allows for shared development environment hosted in the browser. diff --git a/crayfish/README.md b/crayfish/README.md index 80d53c17..f4ce85f5 100644 --- a/crayfish/README.md +++ b/crayfish/README.md @@ -2,6 +2,8 @@ Docker image for [Crayfish] (**unreleased version**). +Built from [Islandora-DevOps/isle-buildkit crayfish](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/crayfish) + Acts as base Docker image for Crayfish based micro-services. It is not meant to be run on its own it is only used to cache the download. diff --git a/crayfits/README.md b/crayfits/README.md index 79f99e24..48432998 100644 --- a/crayfits/README.md +++ b/crayfits/README.md @@ -2,6 +2,8 @@ Docker image for [CrayFits] (**unreleased version**). +Built from [Islandora-DevOps/isle-buildkit crayfits](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/crayfits) + Acts as base Docker image for CrayFits based micro-services. It is not meant to be run on its own. diff --git a/drupal/README.md b/drupal/README.md index 8677dbc4..032a9ebd 100644 --- a/drupal/README.md +++ b/drupal/README.md @@ -2,6 +2,8 @@ Docker image for [Drupal]. +Built from [Islandora-DevOps/isle-buildkit drupal](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/drupal) + Acts as base Docker image for Drupal based projects, it doesn't install Drupal as consumers of this image are expected to provide their own composer file. Instead it provides startup scripts that allow Drupal to be installed when the diff --git a/fcrepo6/README.md b/fcrepo6/README.md index 03d2d861..c26024f9 100644 --- a/fcrepo6/README.md +++ b/fcrepo6/README.md @@ -2,6 +2,8 @@ Docker image for [fcrepo] version 6.5.1. +Built from [Islandora-DevOps/isle-buildkit fcrepo6](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/fcrepo6) + Please refer to the [Fcrepo Documentation] for more in-depth information. As a quick example this will bring up an instance of [fcrepo], and allow you diff --git a/fits/README.md b/fits/README.md index f196b846..d1a8478a 100644 --- a/fits/README.md +++ b/fits/README.md @@ -2,6 +2,8 @@ Docker image for [Fits](https://projects.iq.harvard.edu/fits/home) version 1.6.0. +Built from [Islandora-DevOps/isle-buildkit fits](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/fits) + Please refer to the [Fits Documentation] for more in-depth information. As a quick example this will bring up an instance of [Fits](https://projects.iq.harvard.edu/fits/home), and allow you diff --git a/handle/README.md b/handle/README.md index a0f2a529..05c9e350 100644 --- a/handle/README.md +++ b/handle/README.md @@ -2,6 +2,8 @@ Docker image for [Handle] version 9.3.1. +Built from [Islandora-DevOps/isle-buildkit handle](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/handle) + Please refer to the [Handle Documentation] for more in-depth information. As a quick example this will bring up an instance of [Handle], and allow you diff --git a/homarus/README.md b/homarus/README.md index ea2c28a9..72da1e06 100644 --- a/homarus/README.md +++ b/homarus/README.md @@ -2,6 +2,8 @@ Docker image for [Homarus]. +Built from [Islandora-DevOps/isle-buildkit homarus](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/homarus) + ## Dependencies Requires `islandora/crayfish` docker image to build. Please refer to the diff --git a/houdini/README.md b/houdini/README.md index 59a69ff6..80885e02 100644 --- a/houdini/README.md +++ b/houdini/README.md @@ -2,6 +2,8 @@ Docker image for [Houdini]. +Built from [Islandora-DevOps/isle-buildkit houdini](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/houdini) + ## Dependencies Requires `islandora/crayfish` docker image to build. Please refer to the diff --git a/hypercube/README.md b/hypercube/README.md index bca6907a..d751facb 100644 --- a/hypercube/README.md +++ b/hypercube/README.md @@ -2,6 +2,8 @@ Docker image for [Hypercube]. +Built from [Islandora-DevOps/isle-buildkit hypercube](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/hypercube) + ## Dependencies Requires `islandora/crayfish` docker image to build. Please refer to the diff --git a/java/README.md b/java/README.md index 494da9e2..e504241d 100644 --- a/java/README.md +++ b/java/README.md @@ -2,6 +2,8 @@ Docker image for [Java] OpenJDK version 17. +Built from [Islandora-DevOps/isle-buildkit java](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/java) + Please refer to the [Java Documentation] for more in-depth information. Acts as base Docker image for all Java based services. diff --git a/mariadb/README.md b/mariadb/README.md index de2cbbe5..bc9ec2ea 100644 --- a/mariadb/README.md +++ b/mariadb/README.md @@ -2,6 +2,8 @@ Docker image for [MariaDB] version 10.11.6 +Built from [Islandora-DevOps/isle-buildkit mariadb](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/mariadb) + Please refer to the [MariaDB Documentation] for more in-depth information. As a quick example this will bring up an instance of MariaDB, and allow you to diff --git a/matomo/README.md b/matomo/README.md index 7d2be5c4..8c8940c8 100644 --- a/matomo/README.md +++ b/matomo/README.md @@ -2,6 +2,8 @@ Docker image for [Matomo] version 4.15.1 +Built from [Islandora-DevOps/isle-buildkit matomo](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/matomo) + Please refer to the [Matomo Documentation] for more in-depth information. ## Dependencies diff --git a/milliner/README.md b/milliner/README.md index 4a3c39c2..3af8083d 100644 --- a/milliner/README.md +++ b/milliner/README.md @@ -2,6 +2,8 @@ Docker image for [Milliner]. +Built from [Islandora-DevOps/isle-buildkit milliner](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/milliner) + ## Dependencies Requires `islandora/crayfish` docker image to build. Please refer to the diff --git a/nginx/README.md b/nginx/README.md index 44dc094a..fd24ff3e 100644 --- a/nginx/README.md +++ b/nginx/README.md @@ -2,6 +2,8 @@ Docker image for [Nginx] version 1.24.0 and [FPM] version 8.3.8. +Built from [Islandora-DevOps/isle-buildkit nginx](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/nginx) + Please refer to the [Nginx Documentation] and [FPM Documentation] for more in-depth information. diff --git a/postgresql/README.md b/postgresql/README.md index 766e9588..3f1e59e2 100644 --- a/postgresql/README.md +++ b/postgresql/README.md @@ -2,6 +2,8 @@ Docker image for [PostgreSQL] version 16.3 +Built from [Islandora-DevOps/isle-buildkit postgresql](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/postgresql) + Please refer to the [PostgreSQL Documentation] for more in-depth information. As a quick example this will bring up an instance of PostgreSQL, and allow you to diff --git a/riprap/README.md b/riprap/README.md index 87b6483d..ae7cd669 100644 --- a/riprap/README.md +++ b/riprap/README.md @@ -2,6 +2,8 @@ Docker image for [Riprap] (**unreleased version**) micro-service. +Built from [Islandora-DevOps/isle-buildkit riprap](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/riprap) + Please refer to the [Riprap Documentation] for more in-depth information. ## Dependencies diff --git a/solr/README.md b/solr/README.md index 584fb05e..2d00e886 100644 --- a/solr/README.md +++ b/solr/README.md @@ -2,6 +2,8 @@ Docker image for [solr] version 9.7.0. +Built from [Islandora-DevOps/isle-buildkit solr](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/solr) + Please refer to the [Solr Documentation] for more in-depth information. As a quick example this will bring up an instance of [solr], and allow you diff --git a/test/README.md b/test/README.md index 6225d4ed..21f731a3 100644 --- a/test/README.md +++ b/test/README.md @@ -3,6 +3,8 @@ This image is exclusively used for **manually testing** pull request to this repository and is not intended for use in production environments. +Built from [Islandora-DevOps/isle-buildkit test](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/test) + ## Dependencies Requires `islandora/drupal` docker image to build. Please refer to the diff --git a/tomcat/README.md b/tomcat/README.md index 7849efd2..52304378 100644 --- a/tomcat/README.md +++ b/tomcat/README.md @@ -2,6 +2,8 @@ Docker image for [Tomcat] version 9.0.98. +Built from [Islandora-DevOps/isle-buildkit tomcat](https://github.com/Islandora-DevOps/isle-buildkit/tree/main/tomcat) + Please refer to the [Tomcat Documentation] for more in-depth information. As a quick example this will bring up an instance of [Tomcat], and allow you From 6818439b7856faee7f0d98698de01ed5e87de815 Mon Sep 17 00:00:00 2001 From: Joe Corall Date: Thu, 6 Feb 2025 14:51:22 -0500 Subject: [PATCH 2/4] [minor] add Dockerfile healthchecks to some core services (#370) * Create HEALTHCHECK entries for core services * Ensure secret is set for cantaloupe API access * Add test to make sure healthcheck works Allow fpm status from ipv6 localhost * Add more tests * update README * Update README.md * Healthchecks review (#375) * Replace legacy cont-init.d for Cantaloupe service Changes the cantaloupe service init such that it respects service dependencies. This insures that the precedence for container environment follows what is outlined in the container-environment service. * Test compose projects require names. * Bump github action upload artifact * Add names to docker compose tests --------- Co-authored-by: Nigel Banks --- .github/workflows/grype.yml | 4 +- activemq/Dockerfile | 6 ++ .../tests/ServiceHealthcheck/build.gradle.kts | 54 ++++++++++++++++++ .../ServiceHealthcheck/docker-compose.yml | 15 +++++ activemq/tests/ServiceHealthcheck/test.sh | 13 +++++ cantaloupe/Dockerfile | 8 ++- cantaloupe/README.md | 6 +- .../dependencies.d/container-environment | 0 .../s6-rc.d/cantaloupe-defaults/type | 1 + .../s6-overlay/s6-rc.d/cantaloupe-defaults/up | 1 + .../dependencies.d/cantaloupe-defaults | 0 .../s6-overlay/scripts/cantaloupe-defaults.sh | 9 +++ .../tests/ServiceHealthcheck/build.gradle.kts | 54 ++++++++++++++++++ .../ServiceHealthcheck/docker-compose.yml | 15 +++++ cantaloupe/tests/ServiceHealthcheck/test.sh | 13 +++++ ci/healthcheck.gradle.kts | 55 +++++++++++++++++++ fcrepo6/Dockerfile | 2 + .../tests/ServiceHealthcheck/build.gradle.kts | 54 ++++++++++++++++++ .../ServiceHealthcheck/docker-compose.yml | 19 +++++++ fcrepo6/tests/ServiceHealthcheck/test.sh | 13 +++++ mariadb/Dockerfile | 2 + .../tests/ServiceHealthcheck/build.gradle.kts | 1 + .../ServiceHealthcheck/docker-compose.yml | 15 +++++ mariadb/tests/ServiceHealthcheck/test.sh | 13 +++++ nginx/Dockerfile | 2 + nginx/rootfs/etc/nginx/shared/fpm.conf | 1 + .../tests/ServiceHealthcheck/build.gradle.kts | 1 + .../ServiceHealthcheck/docker-compose.yml | 15 +++++ nginx/tests/ServiceHealthcheck/test.sh | 13 +++++ solr/Dockerfile | 2 + .../tests/ServiceHealthcheck/build.gradle.kts | 54 ++++++++++++++++++ .../ServiceHealthcheck/docker-compose.yml | 15 +++++ solr/tests/ServiceHealthcheck/test.sh | 13 +++++ 33 files changed, 482 insertions(+), 7 deletions(-) create mode 100644 activemq/tests/ServiceHealthcheck/build.gradle.kts create mode 100644 activemq/tests/ServiceHealthcheck/docker-compose.yml create mode 100755 activemq/tests/ServiceHealthcheck/test.sh create mode 100644 cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/dependencies.d/container-environment create mode 100644 cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/type create mode 100755 cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/up create mode 100644 cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/cantaloupe-defaults create mode 100755 cantaloupe/rootfs/etc/s6-overlay/scripts/cantaloupe-defaults.sh create mode 100644 cantaloupe/tests/ServiceHealthcheck/build.gradle.kts create mode 100644 cantaloupe/tests/ServiceHealthcheck/docker-compose.yml create mode 100755 cantaloupe/tests/ServiceHealthcheck/test.sh create mode 100644 ci/healthcheck.gradle.kts create mode 100644 fcrepo6/tests/ServiceHealthcheck/build.gradle.kts create mode 100644 fcrepo6/tests/ServiceHealthcheck/docker-compose.yml create mode 100755 fcrepo6/tests/ServiceHealthcheck/test.sh create mode 120000 mariadb/tests/ServiceHealthcheck/build.gradle.kts create mode 100644 mariadb/tests/ServiceHealthcheck/docker-compose.yml create mode 100755 mariadb/tests/ServiceHealthcheck/test.sh create mode 120000 nginx/tests/ServiceHealthcheck/build.gradle.kts create mode 100644 nginx/tests/ServiceHealthcheck/docker-compose.yml create mode 100755 nginx/tests/ServiceHealthcheck/test.sh create mode 100644 solr/tests/ServiceHealthcheck/build.gradle.kts create mode 100644 solr/tests/ServiceHealthcheck/docker-compose.yml create mode 100755 solr/tests/ServiceHealthcheck/test.sh diff --git a/.github/workflows/grype.yml b/.github/workflows/grype.yml index c0b643b8..6fe28452 100644 --- a/.github/workflows/grype.yml +++ b/.github/workflows/grype.yml @@ -33,8 +33,8 @@ jobs: with: cache-read-only: false arguments: ${{ inputs.image }}:grype ${{ inputs.digest }} --info - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: always() with: - name: Grype Reports + name: ${{ inputs.image }} Grype Reports path: build/**/*-grype.* diff --git a/activemq/Dockerfile b/activemq/Dockerfile index 3aa620ab..f3dd959b 100644 --- a/activemq/Dockerfile +++ b/activemq/Dockerfile @@ -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 diff --git a/activemq/tests/ServiceHealthcheck/build.gradle.kts b/activemq/tests/ServiceHealthcheck/build.gradle.kts new file mode 100644 index 00000000..5dd57e25 --- /dev/null +++ b/activemq/tests/ServiceHealthcheck/build.gradle.kts @@ -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("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 + ) + } +} diff --git a/activemq/tests/ServiceHealthcheck/docker-compose.yml b/activemq/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..c42ee3e7 --- /dev/null +++ b/activemq/tests/ServiceHealthcheck/docker-compose.yml @@ -0,0 +1,15 @@ +--- + +# Common to all services +x-common: &common + restart: "no" + +name: activemq-servicehealthcheck +services: + activemq: + <<: *common + image: ${ACTIVEMQ:-islandora/activemq:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/activemq/tests/ServiceHealthcheck/test.sh b/activemq/tests/ServiceHealthcheck/test.sh new file mode 100755 index 00000000..384fea74 --- /dev/null +++ b/activemq/tests/ServiceHealthcheck/test.sh @@ -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 diff --git a/cantaloupe/Dockerfile b/cantaloupe/Dockerfile index 6d001bc1..e3f23f53 100644 --- a/cantaloupe/Dockerfile +++ b/cantaloupe/Dockerfile @@ -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" \ @@ -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 diff --git a/cantaloupe/README.md b/cantaloupe/README.md index ba265738..04488ceb 100644 --- a/cantaloupe/README.md +++ b/cantaloupe/README.md @@ -67,9 +67,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" | diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/dependencies.d/container-environment b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/dependencies.d/container-environment new file mode 100644 index 00000000..e69de29b diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/type b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/type new file mode 100644 index 00000000..bdd22a18 --- /dev/null +++ b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/type @@ -0,0 +1 @@ +oneshot diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/up b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/up new file mode 100755 index 00000000..34bb7476 --- /dev/null +++ b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/cantaloupe-defaults/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/cantaloupe-defaults.sh diff --git a/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/cantaloupe-defaults b/cantaloupe/rootfs/etc/s6-overlay/s6-rc.d/confd-oneshot/dependencies.d/cantaloupe-defaults new file mode 100644 index 00000000..e69de29b diff --git a/cantaloupe/rootfs/etc/s6-overlay/scripts/cantaloupe-defaults.sh b/cantaloupe/rootfs/etc/s6-overlay/scripts/cantaloupe-defaults.sh new file mode 100755 index 00000000..caab0146 --- /dev/null +++ b/cantaloupe/rootfs/etc/s6-overlay/scripts/cantaloupe-defaults.sh @@ -0,0 +1,9 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +set -ex + +# Set the default value for CANTALOUPE_ENDPOINT_API_SECRET if none provided. +DEFAULT_SECRET=$(openssl rand -hex 16) +cat <("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 + ) + } +} diff --git a/cantaloupe/tests/ServiceHealthcheck/docker-compose.yml b/cantaloupe/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..528bf02c --- /dev/null +++ b/cantaloupe/tests/ServiceHealthcheck/docker-compose.yml @@ -0,0 +1,15 @@ +--- + +# Common to all services +x-common: &common + restart: "no" + +name: cantaloupe-servicehealthcheck +services: + cantaloupe: + <<: *common + image: ${CANTALOUPE:-islandora/cantaloupe:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/cantaloupe/tests/ServiceHealthcheck/test.sh b/cantaloupe/tests/ServiceHealthcheck/test.sh new file mode 100755 index 00000000..384fea74 --- /dev/null +++ b/cantaloupe/tests/ServiceHealthcheck/test.sh @@ -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 diff --git a/ci/healthcheck.gradle.kts b/ci/healthcheck.gradle.kts new file mode 100644 index 00000000..31013aec --- /dev/null +++ b/ci/healthcheck.gradle.kts @@ -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("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 + ) + } +} diff --git a/fcrepo6/Dockerfile b/fcrepo6/Dockerfile index 7cd24a15..587b5e5c 100644 --- a/fcrepo6/Dockerfile +++ b/fcrepo6/Dockerfile @@ -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 diff --git a/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts b/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts new file mode 100644 index 00000000..5dd57e25 --- /dev/null +++ b/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts @@ -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("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 + ) + } +} diff --git a/fcrepo6/tests/ServiceHealthcheck/docker-compose.yml b/fcrepo6/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..149cff1e --- /dev/null +++ b/fcrepo6/tests/ServiceHealthcheck/docker-compose.yml @@ -0,0 +1,19 @@ +--- + +# Common to all services +x-common: &common + restart: "no" + +name: fcrepo6-servicehealthcheck +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 \ No newline at end of file diff --git a/fcrepo6/tests/ServiceHealthcheck/test.sh b/fcrepo6/tests/ServiceHealthcheck/test.sh new file mode 100755 index 00000000..384fea74 --- /dev/null +++ b/fcrepo6/tests/ServiceHealthcheck/test.sh @@ -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 diff --git a/mariadb/Dockerfile b/mariadb/Dockerfile index 549d0ca5..b6072d60 100644 --- a/mariadb/Dockerfile +++ b/mariadb/Dockerfile @@ -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 diff --git a/mariadb/tests/ServiceHealthcheck/build.gradle.kts b/mariadb/tests/ServiceHealthcheck/build.gradle.kts new file mode 120000 index 00000000..118fb428 --- /dev/null +++ b/mariadb/tests/ServiceHealthcheck/build.gradle.kts @@ -0,0 +1 @@ +../../../ci/healthcheck.gradle.kts \ No newline at end of file diff --git a/mariadb/tests/ServiceHealthcheck/docker-compose.yml b/mariadb/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..ad6d5451 --- /dev/null +++ b/mariadb/tests/ServiceHealthcheck/docker-compose.yml @@ -0,0 +1,15 @@ +--- + +# Common to all services +x-common: &common + restart: "no" + +name: mariadb-servicehealthcheck +services: + mariadb: + <<: *common + image: ${MARIADB:-islandora/mariadb:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/mariadb/tests/ServiceHealthcheck/test.sh b/mariadb/tests/ServiceHealthcheck/test.sh new file mode 100755 index 00000000..384fea74 --- /dev/null +++ b/mariadb/tests/ServiceHealthcheck/test.sh @@ -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 diff --git a/nginx/Dockerfile b/nginx/Dockerfile index ea94c047..459c24fc 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -93,3 +93,5 @@ ENV \ SOLR_HOCR_PLUGIN_PATH=/opt/solr/server/solr/contrib/ocrhighlighting/lib COPY --link rootfs / + +HEALTHCHECK CMD curl -s http://localhost/status | grep -q pool diff --git a/nginx/rootfs/etc/nginx/shared/fpm.conf b/nginx/rootfs/etc/nginx/shared/fpm.conf index 5c1db4d5..0677826e 100644 --- a/nginx/rootfs/etc/nginx/shared/fpm.conf +++ b/nginx/rootfs/etc/nginx/shared/fpm.conf @@ -2,6 +2,7 @@ # Not accessible outside of the container. location ~ ^/(status|ping)$ { allow 127.0.0.1; + allow ::1; deny all; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; diff --git a/nginx/tests/ServiceHealthcheck/build.gradle.kts b/nginx/tests/ServiceHealthcheck/build.gradle.kts new file mode 120000 index 00000000..118fb428 --- /dev/null +++ b/nginx/tests/ServiceHealthcheck/build.gradle.kts @@ -0,0 +1 @@ +../../../ci/healthcheck.gradle.kts \ No newline at end of file diff --git a/nginx/tests/ServiceHealthcheck/docker-compose.yml b/nginx/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..e2880db8 --- /dev/null +++ b/nginx/tests/ServiceHealthcheck/docker-compose.yml @@ -0,0 +1,15 @@ +--- + +# Common to all services +x-common: &common + restart: "no" + +name: nginx-servicehealthcheck +services: + nginx: + <<: *common + image: ${NGINX:-islandora/nginx:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/nginx/tests/ServiceHealthcheck/test.sh b/nginx/tests/ServiceHealthcheck/test.sh new file mode 100755 index 00000000..384fea74 --- /dev/null +++ b/nginx/tests/ServiceHealthcheck/test.sh @@ -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 diff --git a/solr/Dockerfile b/solr/Dockerfile index c054c30e..e5df810f 100644 --- a/solr/Dockerfile +++ b/solr/Dockerfile @@ -50,3 +50,5 @@ ENV \ SOLR_MEMORY=512m COPY --link rootfs / + +HEALTHCHECK CMD curl -s http://localhost:8983/solr/admin/info/system?wt=json | jq -r .responseHeader.status | grep -q 0 diff --git a/solr/tests/ServiceHealthcheck/build.gradle.kts b/solr/tests/ServiceHealthcheck/build.gradle.kts new file mode 100644 index 00000000..5dd57e25 --- /dev/null +++ b/solr/tests/ServiceHealthcheck/build.gradle.kts @@ -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("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 + ) + } +} diff --git a/solr/tests/ServiceHealthcheck/docker-compose.yml b/solr/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..c3f15277 --- /dev/null +++ b/solr/tests/ServiceHealthcheck/docker-compose.yml @@ -0,0 +1,15 @@ +--- + +# Common to all services +x-common: &common + restart: "no" + +name: solr-servicehealthcheck +services: + solr: + <<: *common + image: ${SOLR:-islandora/solr:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/solr/tests/ServiceHealthcheck/test.sh b/solr/tests/ServiceHealthcheck/test.sh new file mode 100755 index 00000000..384fea74 --- /dev/null +++ b/solr/tests/ServiceHealthcheck/test.sh @@ -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 From 56baa8b59eb6ae1df32818adb04eb0e6a8357b6d Mon Sep 17 00:00:00 2001 From: Joe Corall Date: Thu, 6 Feb 2025 16:30:02 -0500 Subject: [PATCH 3/4] Pin GHA dependencies --- .github/workflows/build.yml | 14 +++++++++----- .github/workflows/cleanup.yml | 4 ++-- .github/workflows/description.yml | 4 ++-- .github/workflows/grype.yml | 5 +++-- .github/workflows/release.yml | 4 ++-- .github/workflows/tags.yml | 2 +- .github/workflows/test.yml | 8 +++++--- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ff0c2bbd..7afc5773 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,27 +28,31 @@ on: required: true jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 outputs: digest: ${{ steps.build.outputs.digest }} context: ${{ steps.build.outputs.context }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4 + - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3 + - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3 with: driver-opts: | image=moby/buildkit:v0.11.1 network=host + - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 with: username: ${{ secrets.registry_user }} password: ${{ secrets.registry_password }} + - id: build name: Build and push run: | diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml index a1c3f485..141e2108 100644 --- a/.github/workflows/cleanup.yml +++ b/.github/workflows/cleanup.yml @@ -4,10 +4,10 @@ on: - cron: "0 13 * * 0" # Every Sunday at 1PM UTC (9AM EST) jobs: clean: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4 - uses: actions/setup-java@v3 with: distribution: temurin diff --git a/.github/workflows/description.yml b/.github/workflows/description.yml index 7831bc73..70d807c1 100644 --- a/.github/workflows/description.yml +++ b/.github/workflows/description.yml @@ -9,10 +9,10 @@ on: - ".github/workflows/dockerhub-description.yml" jobs: description: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4 - name: Fix Relative Paths run: | diff --git a/.github/workflows/grype.yml b/.github/workflows/grype.yml index 6fe28452..6b42f890 100644 --- a/.github/workflows/grype.yml +++ b/.github/workflows/grype.yml @@ -18,9 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4 + - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 with: username: ${{ secrets.registry_user }} password: ${{ secrets.registry_password }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7408500d..37cb4233 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,10 +11,10 @@ permissions: jobs: release: if: github.event.pull_request.merged == true - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4 with: fetch-depth: 0 - name: install autotag binary diff --git a/.github/workflows/tags.yml b/.github/workflows/tags.yml index c59023b2..d274d3cd 100644 --- a/.github/workflows/tags.yml +++ b/.github/workflows/tags.yml @@ -11,7 +11,7 @@ on: value: ${{ jobs.tags.outputs.tags }} jobs: tags: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 outputs: tags: ${{ steps.tags.outputs.tags }} steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e7e3edb..db21e170 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,15 +15,17 @@ on: required: true jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # v4 + - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 with: username: ${{ secrets.registry_user }} password: ${{ secrets.registry_password }} + - uses: actions/setup-java@v3 with: distribution: temurin From 50fa27d500bd986c321e8ff3cf56dc6bbf50822f Mon Sep 17 00:00:00 2001 From: Joe Corall Date: Fri, 7 Feb 2025 08:24:27 -0500 Subject: [PATCH 4/4] Add code server healthcheck (#376) --- .../tests/ServiceHealthcheck/build.gradle.kts | 55 +------------------ .../tests/ServiceHealthcheck/build.gradle.kts | 55 +------------------ ci/healthcheck.gradle.kts | 2 +- code-server/Dockerfile | 2 + .../tests/ServiceHealthcheck/build.gradle.kts | 1 + .../ServiceHealthcheck/docker-compose.yml | 15 +++++ code-server/tests/ServiceHealthcheck/test.sh | 13 +++++ .../tests/ServiceHealthcheck/build.gradle.kts | 55 +------------------ .../tests/ServiceHealthcheck/build.gradle.kts | 55 +------------------ 9 files changed, 36 insertions(+), 217 deletions(-) mode change 100644 => 120000 activemq/tests/ServiceHealthcheck/build.gradle.kts mode change 100644 => 120000 cantaloupe/tests/ServiceHealthcheck/build.gradle.kts create mode 120000 code-server/tests/ServiceHealthcheck/build.gradle.kts create mode 100644 code-server/tests/ServiceHealthcheck/docker-compose.yml create mode 100755 code-server/tests/ServiceHealthcheck/test.sh mode change 100644 => 120000 fcrepo6/tests/ServiceHealthcheck/build.gradle.kts mode change 100644 => 120000 solr/tests/ServiceHealthcheck/build.gradle.kts diff --git a/activemq/tests/ServiceHealthcheck/build.gradle.kts b/activemq/tests/ServiceHealthcheck/build.gradle.kts deleted file mode 100644 index 5dd57e25..00000000 --- a/activemq/tests/ServiceHealthcheck/build.gradle.kts +++ /dev/null @@ -1,54 +0,0 @@ -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("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 - ) - } -} diff --git a/activemq/tests/ServiceHealthcheck/build.gradle.kts b/activemq/tests/ServiceHealthcheck/build.gradle.kts new file mode 120000 index 00000000..118fb428 --- /dev/null +++ b/activemq/tests/ServiceHealthcheck/build.gradle.kts @@ -0,0 +1 @@ +../../../ci/healthcheck.gradle.kts \ No newline at end of file diff --git a/cantaloupe/tests/ServiceHealthcheck/build.gradle.kts b/cantaloupe/tests/ServiceHealthcheck/build.gradle.kts deleted file mode 100644 index 5dd57e25..00000000 --- a/cantaloupe/tests/ServiceHealthcheck/build.gradle.kts +++ /dev/null @@ -1,54 +0,0 @@ -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("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 - ) - } -} diff --git a/cantaloupe/tests/ServiceHealthcheck/build.gradle.kts b/cantaloupe/tests/ServiceHealthcheck/build.gradle.kts new file mode 120000 index 00000000..118fb428 --- /dev/null +++ b/cantaloupe/tests/ServiceHealthcheck/build.gradle.kts @@ -0,0 +1 @@ +../../../ci/healthcheck.gradle.kts \ No newline at end of file diff --git a/ci/healthcheck.gradle.kts b/ci/healthcheck.gradle.kts index 31013aec..d2928ff5 100644 --- a/ci/healthcheck.gradle.kts +++ b/ci/healthcheck.gradle.kts @@ -9,7 +9,7 @@ tasks.named("test") { doFirst { supplyAsync( { - val maxAttempts = 10 + val maxAttempts = 20 val delayBetweenAttempts = 5000L // 5 seconds in milliseconds var attempt = 0 var foundHealthyService = false diff --git a/code-server/Dockerfile b/code-server/Dockerfile index 9dd2fc28..fd0f1687 100644 --- a/code-server/Dockerfile +++ b/code-server/Dockerfile @@ -99,3 +99,5 @@ RUN sed -i "/nginx:x:100:101:nginx:\/var\/lib\/nginx:\/sbin\/nologin/cnginx:x:10 chown -R nginx:nginx /var/lib/nginx && \ chmod a=r,u+w /etc/sudo.conf && \ cleanup.sh + +HEALTHCHECK CMD curl -s http://localhost:8443/healthz | jq -re .status diff --git a/code-server/tests/ServiceHealthcheck/build.gradle.kts b/code-server/tests/ServiceHealthcheck/build.gradle.kts new file mode 120000 index 00000000..118fb428 --- /dev/null +++ b/code-server/tests/ServiceHealthcheck/build.gradle.kts @@ -0,0 +1 @@ +../../../ci/healthcheck.gradle.kts \ No newline at end of file diff --git a/code-server/tests/ServiceHealthcheck/docker-compose.yml b/code-server/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..f9cd59d9 --- /dev/null +++ b/code-server/tests/ServiceHealthcheck/docker-compose.yml @@ -0,0 +1,15 @@ +--- + +# Common to all services +x-common: &common + restart: "no" + +name: code-server-servicehealthcheck +services: + code-server: + <<: *common + image: ${CODE_SERVER:-islandora/code-server:local} + volumes: + - ./test.sh:/test.sh # Test to run. + command: + - /test.sh # Run test and exit. diff --git a/code-server/tests/ServiceHealthcheck/test.sh b/code-server/tests/ServiceHealthcheck/test.sh new file mode 100755 index 00000000..f24bfcf1 --- /dev/null +++ b/code-server/tests/ServiceHealthcheck/test.sh @@ -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 120 + +# The kotlin check should be stopping this container +exit 1 diff --git a/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts b/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts deleted file mode 100644 index 5dd57e25..00000000 --- a/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts +++ /dev/null @@ -1,54 +0,0 @@ -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("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 - ) - } -} diff --git a/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts b/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts new file mode 120000 index 00000000..118fb428 --- /dev/null +++ b/fcrepo6/tests/ServiceHealthcheck/build.gradle.kts @@ -0,0 +1 @@ +../../../ci/healthcheck.gradle.kts \ No newline at end of file diff --git a/solr/tests/ServiceHealthcheck/build.gradle.kts b/solr/tests/ServiceHealthcheck/build.gradle.kts deleted file mode 100644 index 5dd57e25..00000000 --- a/solr/tests/ServiceHealthcheck/build.gradle.kts +++ /dev/null @@ -1,54 +0,0 @@ -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("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 - ) - } -} diff --git a/solr/tests/ServiceHealthcheck/build.gradle.kts b/solr/tests/ServiceHealthcheck/build.gradle.kts new file mode 120000 index 00000000..118fb428 --- /dev/null +++ b/solr/tests/ServiceHealthcheck/build.gradle.kts @@ -0,0 +1 @@ +../../../ci/healthcheck.gradle.kts \ No newline at end of file