diff --git a/Cargo.lock b/Cargo.lock index 02573c11a..e1cc1c5d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3857,6 +3857,7 @@ dependencies = [ "http", "indexmap", "indoc", + "insta", "java-properties", "jiff", "json-patch", diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index ee60b2114..96e712de3 100644 --- a/crates/stackable-operator/CHANGELOG.md +++ b/crates/stackable-operator/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Fixed + +- BREAKING: `wait_for_termination` in `COMMON_BASH_TRAP_FUNCTIONS` now returns the exit status of the process + it waited for instead of always returning `0` ([#1265]). +- `handle_term_signal` in `COMMON_BASH_TRAP_FUNCTIONS` no longer aborts under `set -u` when SIGTERM arrives + before the child process ID is known ([#1265]). + +[#1265]: https://github.com/stackabletech/operator-rs/pull/1265 + ## [0.119.0] - 2026-09-23 ### Removed diff --git a/crates/stackable-operator/Cargo.toml b/crates/stackable-operator/Cargo.toml index 86caf2e30..7c898880c 100644 --- a/crates/stackable-operator/Cargo.toml +++ b/crates/stackable-operator/Cargo.toml @@ -66,6 +66,7 @@ xml.workspace = true [dev-dependencies] indoc.workspace = true +insta.workspace = true rstest.workspace = true [lints] diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha1_impl__tests__multiple_git_syncs_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha1_impl__tests__multiple_git_syncs_containers.snap new file mode 100644 index 000000000..686f34002 --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha1_impl__tests__multiple_git_syncs_containers.snap @@ -0,0 +1,216 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha1_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=false --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-1 && exec > >(tee /stackable/log/git-sync-1/container.stdout.log) 2> >(tee /stackable/log/git-sync-1/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=false --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: git-credentials + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-1 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-1 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-2 && exec > >(tee /stackable/log/git-sync-2/container.stdout.log) 2> >(tee /stackable/log/git-sync-2/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=false --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-2 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-2 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha1_impl__tests__multiple_git_syncs_init_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha1_impl__tests__multiple_git_syncs_init_containers.snap new file mode 100644 index 000000000..91530caf5 --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha1_impl__tests__multiple_git_syncs_init_containers.snap @@ -0,0 +1,105 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha1_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=true --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-1-init && exec > >(tee /stackable/log/git-sync-1-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-1-init/container.stderr.log >&2) + /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=true --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: git-credentials + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-1-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-1 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-2-init && exec > >(tee /stackable/log/git-sync-2-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-2-init/container.stderr.log >&2) + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=true --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-2-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-2 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ca_cert_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ca_cert_containers.snap new file mode 100644 index 000000000..5530066b6 --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ca_cert_containers.snap @@ -0,0 +1,73 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=3 --git-config='http.sslCAInfo:/stackable/gitca-0/ca.crt,safe.directory:/tmp/git' --link=current --one-time=false --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume + - mountPath: /stackable/gitca-0 + name: ca-cert-0 diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ca_cert_init_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ca_cert_init_containers.snap new file mode 100644 index 000000000..e0f787ed1 --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ca_cert_init_containers.snap @@ -0,0 +1,36 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) + /stackable/git-sync --depth=3 --git-config='http.sslCAInfo:/stackable/gitca-0/ca.crt,safe.directory:/tmp/git' --link=current --one-time=true --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume + - mountPath: /stackable/gitca-0 + name: ca-cert-0 diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ssh_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ssh_containers.snap new file mode 100644 index 000000000..2a19a5be4 --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ssh_containers.snap @@ -0,0 +1,77 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=false --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_SSH_KEY_FILE + value: /stackable/gitssh-0/key + - name: GITSYNC_SSH_KNOWN_HOSTS_FILE + value: /stackable/gitssh-0/knownHosts + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume + - mountPath: /stackable/gitssh-0 + name: ssh-keys-info-0 diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ssh_init_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ssh_init_containers.snap new file mode 100644 index 000000000..07698da0e --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__git_sync_ssh_init_containers.snap @@ -0,0 +1,40 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) + /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=true --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_SSH_KEY_FILE + value: /stackable/gitssh-0/key + - name: GITSYNC_SSH_KNOWN_HOSTS_FILE + value: /stackable/gitssh-0/knownHosts + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume + - mountPath: /stackable/gitssh-0 + name: ssh-keys-info-0 diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__multiple_git_syncs_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__multiple_git_syncs_containers.snap new file mode 100644 index 000000000..3f174326b --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__multiple_git_syncs_containers.snap @@ -0,0 +1,216 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=false --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-1 && exec > >(tee /stackable/log/git-sync-1/container.stdout.log) 2> >(tee /stackable/log/git-sync-1/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=false --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: git-credentials + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-1 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-1 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-2 && exec > >(tee /stackable/log/git-sync-2/container.stdout.log) 2> >(tee /stackable/log/git-sync-2/container.stderr.log >&2) + + prepare_signal_handlers() + { + unset term_child_pid + unset term_kill_needed + trap 'handle_term_signal' TERM + } + + handle_term_signal() + { + if [ -n "${term_child_pid:-}" ]; then + kill -TERM "${term_child_pid}" 2>/dev/null + else + term_kill_needed="yes" + fi + } + + wait_for_termination() + { + set +e + term_child_pid=$1 + if [[ -v term_kill_needed ]]; then + kill -TERM "${term_child_pid}" 2>/dev/null + fi + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + trap - TERM + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi + set -e + return ${term_child_status} + } + + prepare_signal_handlers + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=false --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git & + wait_for_termination $! + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-2 + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-2 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume diff --git a/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__multiple_git_syncs_init_containers.snap b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__multiple_git_syncs_init_containers.snap new file mode 100644 index 000000000..bb2d6c5ee --- /dev/null +++ b/crates/stackable-operator/src/crd/git_sync/snapshots/stackable_operator__crd__git_sync__v1alpha2_impl__tests__multiple_git_syncs_init_containers.snap @@ -0,0 +1,105 @@ +--- +source: crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs +expression: "serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap()" +--- +- args: + - |- + mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=true --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-0-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-0 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-1-init && exec > >(tee /stackable/log/git-sync-1-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-1-init/container.stderr.log >&2) + /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=true --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: git-credentials + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-1-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-1 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume +- args: + - |- + mkdir --parents /stackable/log/git-sync-2-init && exec > >(tee /stackable/log/git-sync-2-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-2-init/container.stderr.log >&2) + /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=true --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git + command: + - /bin/bash + - -x + - -euo + - pipefail + - -c + env: + - name: GITSYNC_USERNAME + value: overridden-username + - name: VAR1 + value: value1 + image: oci.stackable.tech/sdp/product:latest + imagePullPolicy: Always + name: git-sync-2-init + resources: + limits: + cpu: 200m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi + volumeMounts: + - mountPath: /tmp/git + name: content-from-git-2 + - mountPath: /stackable/log + name: log-volume + - mountPath: /mnt/extra-volume + name: extra-volume diff --git a/crates/stackable-operator/src/crd/git_sync/v1alpha1_impl.rs b/crates/stackable-operator/src/crd/git_sync/v1alpha1_impl.rs index 20cfc7e5f..5b1577068 100644 --- a/crates/stackable-operator/src/crd/git_sync/v1alpha1_impl.rs +++ b/crates/stackable-operator/src/crd/git_sync/v1alpha1_impl.rs @@ -480,334 +480,16 @@ mod tests { assert_eq!(3, git_sync_resources.git_sync_containers.len()); - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=false --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.first()).unwrap() - ); - - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-1 && exec > >(tee /stackable/log/git-sync-1/container.stdout.log) 2> >(tee /stackable/log/git-sync-1/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=false --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_PASSWORD - valueFrom: - secretKeyRef: - key: password - name: git-credentials -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-1 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-1 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.get(1)).unwrap() - ); - - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-2 && exec > >(tee /stackable/log/git-sync-2/container.stdout.log) 2> >(tee /stackable/log/git-sync-2/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=false --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-2 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-2 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.get(2)).unwrap() + insta::assert_snapshot!( + "multiple_git_syncs_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap() ); assert_eq!(3, git_sync_resources.git_sync_init_containers.len()); - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=true --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.first()).unwrap() - ); - - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-1-init && exec > >(tee /stackable/log/git-sync-1-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-1-init/container.stderr.log >&2) - /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=true --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_PASSWORD - valueFrom: - secretKeyRef: - key: password - name: git-credentials -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-1-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-1 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.get(1)).unwrap() - ); - - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-2-init && exec > >(tee /stackable/log/git-sync-2-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-2-init/container.stderr.log >&2) - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=true --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-2-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-2 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.get(2)).unwrap() + insta::assert_snapshot!( + "multiple_git_syncs_init_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap() ); assert_eq!(3, git_sync_resources.git_content_volumes.len()); diff --git a/crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs b/crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs index eba308bfb..93311f397 100644 --- a/crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs +++ b/crates/stackable-operator/src/crd/git_sync/v1alpha2_impl.rs @@ -611,334 +611,16 @@ mod tests { assert_eq!(3, git_sync_resources.git_sync_containers.len()); - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=false --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.first()).unwrap() - ); - - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-1 && exec > >(tee /stackable/log/git-sync-1/container.stdout.log) 2> >(tee /stackable/log/git-sync-1/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=false --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_PASSWORD - valueFrom: - secretKeyRef: - key: password - name: git-credentials -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-1 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-1 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.get(1)).unwrap() - ); - - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-2 && exec > >(tee /stackable/log/git-sync-2/container.stdout.log) 2> >(tee /stackable/log/git-sync-2/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=false --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-2 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-2 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.get(2)).unwrap() + insta::assert_snapshot!( + "multiple_git_syncs_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap() ); assert_eq!(3, git_sync_resources.git_sync_init_containers.len()); - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git' --link=current --one-time=true --period=20s --ref=main --repo=https://github.com/stackabletech/repo1 --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.first()).unwrap() - ); - - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-1-init && exec > >(tee /stackable/log/git-sync-1-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-1-init/container.stderr.log >&2) - /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=true --period=60s --ref=trunk --repo=https://github.com/stackabletech/repo2 --rev=HEAD --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_PASSWORD - valueFrom: - secretKeyRef: - key: password - name: git-credentials -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-1-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-1 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.get(1)).unwrap() - ); - - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-2-init && exec > >(tee /stackable/log/git-sync-2-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-2-init/container.stderr.log >&2) - /stackable/git-sync --depth=1 --git-config='safe.directory:/tmp/git,key:value,safe.directory:/safe-dir' --link=current --one-time=true --period=20s --ref=feat/git-sync --repo=https://github.com/stackabletech/repo3 --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_USERNAME - value: overridden-username -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-2-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-2 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.get(2)).unwrap() + insta::assert_snapshot!( + "multiple_git_syncs_init_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap() ); assert_eq!(3, git_sync_resources.git_content_volumes.len()); @@ -1015,7 +697,6 @@ name: content-from-git-2 } #[test] - #[expect(clippy::too_many_lines)] fn test_git_sync_ssh() { let git_sync_spec = r#" # GitSync using SSH @@ -1066,120 +747,16 @@ name: content-from-git-2 assert_eq!(1, git_sync_resources.git_sync_containers.len()); - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=false --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_SSH_KEY_FILE - value: /stackable/gitssh-0/key -- name: GITSYNC_SSH_KNOWN_HOSTS_FILE - value: /stackable/gitssh-0/knownHosts -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -- mountPath: /stackable/gitssh-0 - name: ssh-keys-info-0 -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.first()).unwrap() + insta::assert_snapshot!( + "git_sync_ssh_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap() ); assert_eq!(1, git_sync_resources.git_sync_init_containers.len()); - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) - /stackable/git-sync --depth=3 --git-config='safe.directory:/tmp/git,http.sslCAInfo:/tmp/ca-cert/ca.crt' --link=current --one-time=true --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: GITSYNC_SSH_KEY_FILE - value: /stackable/gitssh-0/key -- name: GITSYNC_SSH_KNOWN_HOSTS_FILE - value: /stackable/gitssh-0/knownHosts -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -- mountPath: /stackable/gitssh-0 - name: ssh-keys-info-0 -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.first()).unwrap() + insta::assert_snapshot!( + "git_sync_ssh_init_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap() ); assert_eq!(1, git_sync_resources.git_content_volumes.len()); @@ -1223,7 +800,6 @@ secret: } #[test] - #[allow(clippy::too_many_lines)] fn test_git_sync_ca_cert() { let git_sync_spec = r#" # GitSync using SSH @@ -1276,112 +852,16 @@ secret: assert_eq!(1, git_sync_resources.git_sync_containers.len()); - assert_eq!( - r#"args: -- |- - mkdir --parents /stackable/log/git-sync-0 && exec > >(tee /stackable/log/git-sync-0/container.stdout.log) 2> >(tee /stackable/log/git-sync-0/container.stderr.log >&2) - - prepare_signal_handlers() - { - unset term_child_pid - unset term_kill_needed - trap 'handle_term_signal' TERM - } - - handle_term_signal() - { - if [ "${term_child_pid}" ]; then - kill -TERM "${term_child_pid}" 2>/dev/null - else - term_kill_needed="yes" - fi - } - - wait_for_termination() - { - set +e - term_child_pid=$1 - if [[ -v term_kill_needed ]]; then - kill -TERM "${term_child_pid}" 2>/dev/null - fi - wait ${term_child_pid} 2>/dev/null - trap - TERM - wait ${term_child_pid} 2>/dev/null - set -e - } - - prepare_signal_handlers - /stackable/git-sync --depth=3 --git-config='http.sslCAInfo:/stackable/gitca-0/ca.crt,safe.directory:/tmp/git' --link=current --one-time=false --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git & - wait_for_termination $! -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0 -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -- mountPath: /stackable/gitca-0 - name: ca-cert-0 -"#, - serde_yaml::to_string(&git_sync_resources.git_sync_containers.first()).unwrap() + insta::assert_snapshot!( + "git_sync_ca_cert_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_containers).unwrap() ); assert_eq!(1, git_sync_resources.git_sync_init_containers.len()); - assert_eq!( - r"args: -- |- - mkdir --parents /stackable/log/git-sync-0-init && exec > >(tee /stackable/log/git-sync-0-init/container.stdout.log) 2> >(tee /stackable/log/git-sync-0-init/container.stderr.log >&2) - /stackable/git-sync --depth=3 --git-config='http.sslCAInfo:/stackable/gitca-0/ca.crt,safe.directory:/tmp/git' --link=current --one-time=true --period=60s --ref=trunk --repo=ssh://git@github.com/stackabletech/repo.git --rev=HEAD --root=/tmp/git -command: -- /bin/bash -- -x -- -euo -- pipefail -- -c -env: -- name: VAR1 - value: value1 -image: oci.stackable.tech/sdp/product:latest -imagePullPolicy: Always -name: git-sync-0-init -resources: - limits: - cpu: 200m - memory: 64Mi - requests: - cpu: 100m - memory: 64Mi -volumeMounts: -- mountPath: /tmp/git - name: content-from-git-0 -- mountPath: /stackable/log - name: log-volume -- mountPath: /mnt/extra-volume - name: extra-volume -- mountPath: /stackable/gitca-0 - name: ca-cert-0 -", - serde_yaml::to_string(&git_sync_resources.git_sync_init_containers.first()).unwrap() + insta::assert_snapshot!( + "git_sync_ca_cert_init_containers", + serde_yaml::to_string(&git_sync_resources.git_sync_init_containers).unwrap() ); assert_eq!(1, git_sync_resources.git_content_volumes.len()); diff --git a/crates/stackable-operator/src/product_logging/framework.rs b/crates/stackable-operator/src/product_logging/framework.rs index 35c7bab02..3750acf7a 100644 --- a/crates/stackable-operator/src/product_logging/framework.rs +++ b/crates/stackable-operator/src/product_logging/framework.rs @@ -1386,8 +1386,10 @@ sinks: /// {remove_vector_shutdown_file_command} /// prepare_signal_handlers /// my-application start & -/// wait_for_termination $! +/// product_exit_code=0 +/// wait_for_termination $! || product_exit_code=$? /// {create_vector_shutdown_file_command} +/// exit \"${{product_exit_code}}\" /// ", /// remove_vector_shutdown_file_command = /// remove_vector_shutdown_file_command(STACKABLE_LOG_DIR), diff --git a/crates/stackable-operator/src/utils/bash.rs b/crates/stackable-operator/src/utils/bash.rs index b93b77173..6163256fa 100644 --- a/crates/stackable-operator/src/utils/bash.rs +++ b/crates/stackable-operator/src/utils/bash.rs @@ -1,7 +1,8 @@ /// This is a bash snippet, which adds two functions out of interest: /// /// 1. `prepare_signal_handlers` call this first to set up the needed traps -/// 2. `wait_for_termination` waits for the PID you passed as the first argument to terminate +/// 2. `wait_for_termination` waits for the PID you passed as the first argument to terminate and +/// returns its exit status /// /// An example use could be /// ```text @@ -9,9 +10,19 @@ /// echo "Run before startup" /// prepare_signal_handlers /// {hadoop_home}/bin/hdfs {role} & -/// wait_for_termination $! +/// product_exit_code=0 +/// wait_for_termination $! || product_exit_code=$? /// echo "Run after termination" +/// exit "${product_exit_code}" /// ``` +// A `wait` status above 128 can mean two things: +// 1. bash reports a signal death as `128 + signal` +// 2. an in-progress `wait` abort with such a status when a trapped signal arrives +// +// We wait a second time to get the actual child status, which immediately returns the +// status again in case 1. In case 2 the child is still running and we do need to wait. +// +// See https://www.gnu.org/software/bash/manual/html_node/Signals.html pub const COMMON_BASH_TRAP_FUNCTIONS: &str = r#" prepare_signal_handlers() { @@ -22,7 +33,7 @@ prepare_signal_handlers() handle_term_signal() { - if [ "${term_child_pid}" ]; then + if [ -n "${term_child_pid:-}" ]; then kill -TERM "${term_child_pid}" 2>/dev/null else term_kill_needed="yes" @@ -37,8 +48,87 @@ wait_for_termination() kill -TERM "${term_child_pid}" 2>/dev/null fi wait ${term_child_pid} 2>/dev/null + term_child_status=$? trap - TERM - wait ${term_child_pid} 2>/dev/null + if [ "${term_child_status}" -gt 128 ]; then + wait ${term_child_pid} 2>/dev/null + term_child_status=$? + fi set -e + return ${term_child_status} } "#; + +#[cfg(test)] +mod tests { + use std::process::Command; + + use super::*; + + fn run_container_command(script: &str) -> (i32, String) { + let output = Command::new("/bin/bash") + .args(["-euo", "pipefail", "-c", script]) + .output() + .expect("bash can be executed in the test environment"); + let exit_code = output + .status + .code() + .expect("the shell terminated regularly and not by a signal"); + let stdout = String::from_utf8(output.stdout).expect("the script only prints UTF-8"); + (exit_code, stdout) + } + + #[test] + fn crash_of_child_process() { + let (exit_code, _) = run_container_command(&format!( + "{COMMON_BASH_TRAP_FUNCTIONS} +prepare_signal_handlers +bash -c 'exit 42' & +wait_for_termination $!" + )); + + assert_eq!(42, exit_code); + } + + #[test] + fn graceful_shutdown_of_child_process() { + let (exit_code, _) = run_container_command(&format!( + "{COMMON_BASH_TRAP_FUNCTIONS} +prepare_signal_handlers +bash -c 'trap \"exit 7\" TERM; sleep 10 >/dev/null 2>&1 & wait $!' & +child_pid=$! +(sleep 0.2; kill -TERM $$) & +wait_for_termination $child_pid" + )); + + assert_eq!(7, exit_code); + } + + #[test] + fn crash_with_command_after_the_call() { + let (exit_code, stdout) = run_container_command(&format!( + "{COMMON_BASH_TRAP_FUNCTIONS} +prepare_signal_handlers +bash -c 'exit 42' & +product_exit_code=0 +wait_for_termination $! || product_exit_code=$? +echo tail-ran +exit \"${{product_exit_code}}\"" + )); + assert_eq!(42, exit_code); + assert!(stdout.contains("tail-ran\n")); + } + + #[test] + fn sigterm_before_child_pid_is_known() { + let (exit_code, _) = run_container_command(&format!( + "{COMMON_BASH_TRAP_FUNCTIONS} +prepare_signal_handlers +kill -TERM $$ +sleep 10 & +wait_for_termination $! +" + )); + assert_eq!(143, exit_code); + } +}