From 50fa27d500bd986c321e8ff3cf56dc6bbf50822f Mon Sep 17 00:00:00 2001 From: Joe Corall Date: Fri, 7 Feb 2025 08:24:27 -0500 Subject: [PATCH] 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