From f69a29403b3adcf0c2c8767c056e073c27c398e5 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sun, 7 Jul 2024 19:31:16 +0200 Subject: [PATCH] Add health check test image. (#918) --- .github/workflows/docker-images.yml | 3 ++ tests/images/healthcheck/build.sh | 39 ++++++++++++++++++++++++ tests/images/healthcheck/is-healthy.go | 35 +++++++++++++++++++++ tests/images/healthcheck/main.go | 31 +++++++++++++++++++ tests/images/healthcheck/make-healthy.go | 35 +++++++++++++++++++++ 5 files changed, 143 insertions(+) create mode 100755 tests/images/healthcheck/build.sh create mode 100644 tests/images/healthcheck/is-healthy.go create mode 100644 tests/images/healthcheck/main.go create mode 100644 tests/images/healthcheck/make-healthy.go diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index bb0fa6492..67cdd85f4 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -39,6 +39,9 @@ jobs: - name: simple-2 tag: tag tag-as-latest: true + - name: healthcheck + tag: check + tag-as-latest: true steps: - name: Check out repository diff --git a/tests/images/healthcheck/build.sh b/tests/images/healthcheck/build.sh new file mode 100755 index 000000000..0d90f89d6 --- /dev/null +++ b/tests/images/healthcheck/build.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +if [ ! -e main.go ]; then + echo "Must be run in a directory that contains main.go." + exit 1 +fi + +PROGRAMS="main is-healthy make-healthy" + +set -eux +IMAGE_NAME="${1:-localhost/$(basename "$(pwd)"):latest}" +podman manifest rm "${IMAGE_NAME}" || true +podman image rm "${IMAGE_NAME}" || true +buildah manifest create "${IMAGE_NAME}" +for ARCH in amd64 arm64; do + for PROGRAM in ${PROGRAMS}; do + rm -f "${PROGRAM}-${ARCH}" + GOARCH="${ARCH}" go build -ldflags "-s -w" -o "${PROGRAM}-${ARCH}" "${PROGRAM}.go" + done + + # Need format=docker for health checks to work + WORKING_CONTAINER="$(buildah from --arch "${ARCH}" --format docker scratch)" + for PROGRAM in ${PROGRAMS}; do + buildah copy "${WORKING_CONTAINER}" "${PROGRAM}-${ARCH}" "/${PROGRAM}" + done + buildah config --entrypoint '["/main"]' "${WORKING_CONTAINER}" + buildah config --healthcheck /is-healthy "${WORKING_CONTAINER}" + buildah config --healthcheck-interval 1s "${WORKING_CONTAINER}" + buildah config --healthcheck-retries 1 "${WORKING_CONTAINER}" + buildah config --healthcheck-start-period 10s "${WORKING_CONTAINER}" + buildah commit --format docker --manifest "${IMAGE_NAME}" "${WORKING_CONTAINER}" + + for PROGRAM in ${PROGRAMS}; do + rm -f "${PROGRAM}-${ARCH}" + done +done diff --git a/tests/images/healthcheck/is-healthy.go b/tests/images/healthcheck/is-healthy.go new file mode 100644 index 000000000..a002ddce5 --- /dev/null +++ b/tests/images/healthcheck/is-healthy.go @@ -0,0 +1,35 @@ +/* + Copyright (c) Ansible Project + GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package main + +import ( + "bytes" + "fmt" + "os" +) + +func main() { + data, err := os.ReadFile("health.txt") + if err != nil { + fmt.Fprintf(os.Stderr, "Error while reading health status: %s\n", err) + os.Exit(1) + } + if bytes.Equal(data, []byte("healthy")) { + fmt.Fprintf(os.Stdout, "Healthy.\n") + os.Exit(0) + } + if bytes.Equal(data, []byte("unhealthy")) { + fmt.Fprintf(os.Stdout, "Unhealthy!\n") + os.Exit(1) + } + if bytes.Equal(data, []byte("starting")) { + fmt.Fprintf(os.Stdout, "Starting...\n") + os.Exit(1) + } + fmt.Fprintf(os.Stderr, "Unknown health status: %s\n", data) + os.Exit(1) +} diff --git a/tests/images/healthcheck/main.go b/tests/images/healthcheck/main.go new file mode 100644 index 000000000..842729db3 --- /dev/null +++ b/tests/images/healthcheck/main.go @@ -0,0 +1,31 @@ +/* + Copyright (c) Ansible Project + GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package main + +import ( + "fmt" + "os" + "time" +) + +func main() { + os.WriteFile("health.txt", []byte("starting"), 0644) + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "%s must have 1 argument, not %d arguments\n", os.Args[0], len(os.Args)) + os.Exit(1) + } + delay, err := time.ParseDuration(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "Cannot parse delay duration: %s\n", err) + os.Exit(1) + } + if delay.Microseconds() <= 0 { + fmt.Fprintf(os.Stderr, "Delay must be positive!\n") + os.Exit(1) + } + time.Sleep(delay) +} diff --git a/tests/images/healthcheck/make-healthy.go b/tests/images/healthcheck/make-healthy.go new file mode 100644 index 000000000..b046f21ee --- /dev/null +++ b/tests/images/healthcheck/make-healthy.go @@ -0,0 +1,35 @@ +/* + Copyright (c) Ansible Project + GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) + SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package main + +import ( + "fmt" + "os" + "strconv" +) + +func main() { + healthy := true + if len(os.Args) > 2 { + fmt.Fprintf(os.Stderr, "%s must have 0 or 1 argument, not %d arguments\n", os.Args[0], len(os.Args)) + os.Exit(1) + } else if len(os.Args) == 2 { + var err error + healthy, err = strconv.ParseBool(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "Cannot parse boolean: %s\n", err) + os.Exit(1) + } + } + var state []byte + if healthy { + state = []byte("healthy") + } else { + state = []byte("unhealthy") + } + os.WriteFile("health.txt", state, 0644) +}