[tests] Introduce self destructing environments

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
This commit is contained in:
Andrei Kvapil
2025-07-02 02:20:34 +03:00
parent 78b4d06b25
commit 52714f5cce
7 changed files with 127 additions and 27 deletions

View File

@@ -44,6 +44,17 @@ jobs:
- name: Build Talos image
run: make -C packages/core/installer talos-nocloud
- name: Save git diff as patch
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
run: git diff HEAD > _out/assets/pr.patch
- name: Upload git diff patch
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
uses: actions/upload-artifact@v4
with:
name: pr-patch
path: _out/assets/pr.patch
- name: Upload installer
uses: actions/upload-artifact@v4
@@ -126,6 +137,10 @@ jobs:
if: ${{ always() && (needs.build.result == 'success' || needs.resolve_assets.result == 'success') }}
steps:
# ▸ Checkout and prepare the codebase
- name: Checkout code
uses: actions/checkout@v4
# ▸ Regular PR path download artefacts produced by the *build* job
- name: "Download Talos image (regular PR)"
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
@@ -134,6 +149,17 @@ jobs:
name: talos-image
path: _out/assets
- name: Download PR patch
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
uses: actions/download-artifact@v4
with:
name: pr-patch
path: _out/assets
- name: Apply patch
if: "!contains(github.event.pull_request.labels.*.name, 'release')"
run: |
git apply _out/assets/pr.patch
# ▸ Release PR path fetch artefacts from the corresponding draft release
- name: Download assets from draft release (release PR)
@@ -145,23 +171,15 @@ jobs:
env:
GH_PAT: ${{ secrets.GH_PAT }}
# ▸ Start actual job steps
- name: Set sandbox ID
run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV
# ▸ Start actual job steps
- name: Prepare workspace
run: |
cd ..
rm -rf /tmp/$SANDBOX_NAME
cp -r cozystack /tmp/$SANDBOX_NAME
sudo systemctl stop "rm-workspace-$SANDBOX_NAME.timer" "rm-workspace-$SANDBOX_NAME.service" 2>/dev/null || true
sudo systemctl reset-failed "rm-workspace-$SANDBOX_NAME.timer" "rm-workspace-$SANDBOX_NAME.service" 2>/dev/null || true
sudo systemctl daemon-reexec
sudo systemd-run \
--on-calendar="$(date -d 'now + 24 hours' '+%Y-%m-%d %H:%M:%S')" \
--unit=rm-workspace-$SANDBOX_NAME \
rm -rf /tmp/$SANDBOX_NAME
cp -r ${{ github.workspace }} /tmp/$SANDBOX_NAME
- name: Prepare environment
run: |
cd /tmp/$SANDBOX_NAME
@@ -202,6 +220,11 @@ jobs:
- name: Set sandbox ID
run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV
- name: Sync _out/assets directory
run: |
mkdir -p /tmp/$SANDBOX_NAME/_out/assets
mv _out/assets/* /tmp/$SANDBOX_NAME/_out/assets/
- name: Install Cozystack into sandbox
run: |
cd /tmp/$SANDBOX_NAME
@@ -259,11 +282,3 @@ jobs:
- name: Remove workspace
run: rm -rf /tmp/$SANDBOX_NAME
- name: Tear down timers
run: |
sudo systemctl stop "rm-workspace-$SANDBOX_NAME.timer" "rm-workspace-$SANDBOX_NAME.service" 2>/dev/null || true
sudo systemctl reset-failed "rm-workspace-$SANDBOX_NAME.timer" "rm-workspace-$SANDBOX_NAME.service" 2>/dev/null || true
sudo systemctl stop "teardown-$SANDBOX_NAME.timer" "teardown-$SANDBOX_NAME.service" 2>/dev/null || true
sudo systemctl reset-failed "teardown-$SANDBOX_NAME.timer" "teardown-$SANDBOX_NAME.service" 2>/dev/null || true
sudo systemctl daemon-reexec

View File

@@ -1,5 +1,12 @@
#!/usr/bin/env bats
@test "Required installer assets exist" {
if [ ! -f _out/assets/cozystack-installer.yaml ]; then
echo "Missing: _out/assets/cozystack-installer.yaml" >&2
exit 1
fi
}
@test "Install Cozystack" {
# Create namespace & configmap required by installer
kubectl create namespace cozy-system --dry-run=client -o yaml | kubectl apply -f -

View File

@@ -4,11 +4,6 @@
# -----------------------------------------------------------------------------
@test "Required installer assets exist" {
if [ ! -f _out/assets/cozystack-installer.yaml ]; then
echo "Missing: _out/assets/cozystack-installer.yaml" >&2
exit 1
fi
if [ ! -f _out/assets/nocloud-amd64.raw.xz ]; then
echo "Missing: _out/assets/nocloud-amd64.raw.xz" >&2
exit 1

View File

@@ -15,7 +15,7 @@ help: ## Show this help.
image: image-e2e-sandbox
image-e2e-sandbox:
docker buildx build -f images/e2e-sandbox/Dockerfile ../../.. \
docker buildx build -f images/e2e-sandbox/Dockerfile images/e2e-sandbox \
--provenance false \
--builder=$(BUILDER) \
--platform=$(PLATFORM) \
@@ -62,5 +62,5 @@ apply: delete
-e TALOSCONFIG=/workspace/talosconfig \
-e KUBECONFIG=/workspace/kubeconfig \
"$$(yq .e2e.image values.yaml)" \
sleep infinity
--timeout 30m
docker cp "${ROOT_DIR}" "${SANDBOX_NAME}":/workspace

View File

@@ -19,3 +19,6 @@ RUN curl -sSL "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_${TA
&& chmod +x /usr/local/bin/yq
RUN curl -sSL "https://fluxcd.io/install.sh" | bash
RUN curl -sSL "https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh" | sh -s -- -v "${COZYPKG_VERSION}"
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

View File

@@ -0,0 +1,80 @@
#!/bin/sh
set -eu
SELF_PID="$$"
INTERVAL=30m
while [ $# -gt 0 ]; do
case "$1" in
--timeout)
INTERVAL="$2"
shift 2
;;
*)
echo "Usage: $0 [--timeout SECONDS]"
exit 1
;;
esac
done
ALL_PROCS=$(ps -eo pid=,ppid=,comm=)
get_descendants() {
PARENT="$1"
echo "$PARENT"
echo "$ALL_PROCS" | while read -r PID PPID CMD; do
PID=$(echo "$PID" | tr -d ' ')
PPID=$(echo "$PPID" | tr -d ' ')
if [ "$PPID" = "$PARENT" ]; then
echo "$PID"
get_descendants "$PID"
fi
done
}
is_own_tree() {
PID="$1"
echo "$DESCENDANTS" | grep -q -x "$PID"
}
check_once() {
DESCENDANTS="$(get_descendants "$SELF_PID" | sort -u)"
EXTERNAL_PIDS=$(
echo "$ALL_PROCS" | while read -r PID PPID CMD; do
PID=$(echo "$PID" | tr -d ' ')
CMD=$(echo "$CMD" | tr -d ' ')
if is_own_tree "$PID"; then
continue
fi
case "$CMD" in
*qemu*) continue ;;
esac
echo "PID=$PID CMD=$CMD"
done
)
COUNT=$(echo "$EXTERNAL_PIDS" | wc -w)
echo "$EXTERNAL_PIDS"
[ "$COUNT" -eq 0 ]
}
check_loop() {
while :; do
ALL_PROCS=$(ps -eo pid=,ppid=,comm=)
if check_once; then
echo "No external processes, exiting..."
exit 0
fi
echo "External processes still running, next check in ${INTERVAL}..."
sleep "$INTERVAL"
done
}
echo "Waiting for external processes to be started, next check in ${INTERVAL}..."
sleep "$INTERVAL"
check_loop

View File

@@ -1,2 +1,2 @@
e2e:
image: ghcr.io/cozystack/cozystack/e2e-sandbox:v0.32.1@sha256:b15f85e58be54529d74ab7056d5d47960944abde28f14611e88156989a19c789
image: ghcr.io/cozystack/cozystack/e2e-sandbox:latest@sha256:df79b508c45ab11f728dfb12b5b984c04f64ea5c26cf239095913aa7fc9f73aa