diff --git a/code-server/Dockerfile b/code-server/Dockerfile index 9dd2fc28..2c31bfa6 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 | grep alive diff --git a/code-server/tests/ServiceHealthcheck/build.gradle.kts b/code-server/tests/ServiceHealthcheck/build.gradle.kts new file mode 100644 index 00000000..5dd57e25 --- /dev/null +++ b/code-server/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/code-server/tests/ServiceHealthcheck/docker-compose.yml b/code-server/tests/ServiceHealthcheck/docker-compose.yml new file mode 100644 index 00000000..b447996a --- /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: + codeserver: + <<: *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..384fea74 --- /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 60 + +# The kotlin check should be stopping this container +exit 1