ci / docker (push) Failing after 44s
Adds a shared .gitea/scripts/komodo-deploy.sh that calls the Komodo /execute/DeployStack API after the image is pushed, then polls /read/GetUpdate until the deploy completes. A push webhook cannot do this correctly: it fires before the image exists in the registry, so Komodo would redeploy the previous :latest. - docker.yml deploys stack 'qbit-maid' (required) - docker-dev.yml deploys vars.KOMODO_STACK_DEV, skipped when unset
163 lines
4.6 KiB
Bash
163 lines
4.6 KiB
Bash
#!/bin/sh
|
|
#
|
|
# Trigger a Komodo deploy and optionally wait for it to finish.
|
|
#
|
|
# Required env:
|
|
# KOMODO_URL Base URL of Komodo Core, e.g. https://k.jonb.io
|
|
# KOMODO_API_KEY Komodo API key
|
|
# KOMODO_API_SECRET Komodo API secret
|
|
# KOMODO_TARGET Stack name/id (or Procedure name/id)
|
|
#
|
|
# Optional env:
|
|
# KOMODO_TARGET_TYPE "stack" (default) or "procedure"
|
|
# KOMODO_REQUIRED "true" to fail when KOMODO_TARGET is empty
|
|
# KOMODO_WAIT "true" (default) to poll until the update completes
|
|
# KOMODO_WAIT_TIMEOUT Seconds to wait for completion (default 600)
|
|
# KOMODO_WAIT_INTERVAL Seconds between polls (default 10)
|
|
#
|
|
# Exits non-zero if the request is rejected or the deploy fails.
|
|
|
|
set -eu
|
|
|
|
KOMODO_TARGET_TYPE="${KOMODO_TARGET_TYPE:-stack}"
|
|
KOMODO_REQUIRED="${KOMODO_REQUIRED:-false}"
|
|
KOMODO_WAIT="${KOMODO_WAIT:-true}"
|
|
KOMODO_WAIT_TIMEOUT="${KOMODO_WAIT_TIMEOUT:-600}"
|
|
KOMODO_WAIT_INTERVAL="${KOMODO_WAIT_INTERVAL:-10}"
|
|
|
|
if [ -z "${KOMODO_TARGET:-}" ]; then
|
|
if [ "$KOMODO_REQUIRED" = "true" ]; then
|
|
echo "::error::KOMODO_TARGET is empty but KOMODO_REQUIRED=true" >&2
|
|
exit 1
|
|
fi
|
|
echo "KOMODO_TARGET is not set - skipping Komodo deploy."
|
|
exit 0
|
|
fi
|
|
|
|
: "${KOMODO_URL:?KOMODO_URL is required}"
|
|
: "${KOMODO_API_KEY:?KOMODO_API_KEY is required}"
|
|
: "${KOMODO_API_SECRET:?KOMODO_API_SECRET is required}"
|
|
|
|
# Normalise: strip any trailing slash so path joins are predictable.
|
|
KOMODO_URL="${KOMODO_URL%/}"
|
|
|
|
case "$KOMODO_TARGET_TYPE" in
|
|
stack)
|
|
EXECUTE="DeployStack"
|
|
PARAMS="{\"stack\": \"${KOMODO_TARGET}\"}"
|
|
;;
|
|
procedure)
|
|
EXECUTE="RunProcedure"
|
|
PARAMS="{\"procedure\": \"${KOMODO_TARGET}\"}"
|
|
;;
|
|
*)
|
|
echo "::error::KOMODO_TARGET_TYPE must be 'stack' or 'procedure', got '${KOMODO_TARGET_TYPE}'" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
tmp=$(mktemp)
|
|
trap 'rm -f "$tmp"' EXIT
|
|
|
|
# api <path> <json-body> -> writes body to $tmp, echoes HTTP status code
|
|
api() {
|
|
curl -sS -o "$tmp" -w '%{http_code}' \
|
|
-X POST "${KOMODO_URL}$1" \
|
|
-H 'Content-Type: application/json' \
|
|
-H "x-api-key: ${KOMODO_API_KEY}" \
|
|
-H "x-api-secret: ${KOMODO_API_SECRET}" \
|
|
-d "$2"
|
|
}
|
|
|
|
echo "Requesting ${EXECUTE} for '${KOMODO_TARGET}' on ${KOMODO_URL}"
|
|
|
|
if ! code=$(api "/execute/${EXECUTE}" "$PARAMS"); then
|
|
echo "::error::Could not reach Komodo at ${KOMODO_URL}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
body=$(cat "$tmp")
|
|
|
|
if [ "$code" != "200" ]; then
|
|
echo "::error::Komodo rejected ${EXECUTE} for '${KOMODO_TARGET}' (HTTP ${code})" >&2
|
|
echo "$body" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Komodo accepted the request (HTTP 200)."
|
|
|
|
# The execute endpoint returns immediately with an Update; the deploy itself
|
|
# runs asynchronously. Poll /read/GetUpdate until it reaches a terminal state.
|
|
if [ "$KOMODO_WAIT" != "true" ]; then
|
|
echo "KOMODO_WAIT is not 'true' - not waiting for completion."
|
|
exit 0
|
|
fi
|
|
|
|
if ! command -v python3 >/dev/null 2>&1; then
|
|
echo "python3 not available - cannot poll for completion. Deploy was queued."
|
|
exit 0
|
|
fi
|
|
|
|
update_id=$(printf '%s' "$body" | python3 -c '
|
|
import json, sys
|
|
d = json.load(sys.stdin)
|
|
print(d.get("_id", {}).get("$oid", ""))
|
|
' 2>/dev/null || true)
|
|
|
|
if [ -z "$update_id" ]; then
|
|
echo "Could not read update id from response - not polling. Deploy was queued."
|
|
exit 0
|
|
fi
|
|
|
|
echo "Waiting for update ${update_id} (timeout ${KOMODO_WAIT_TIMEOUT}s)..."
|
|
|
|
elapsed=0
|
|
while [ "$elapsed" -lt "$KOMODO_WAIT_TIMEOUT" ]; do
|
|
sleep "$KOMODO_WAIT_INTERVAL"
|
|
elapsed=$((elapsed + KOMODO_WAIT_INTERVAL))
|
|
|
|
if ! code=$(api "/read/GetUpdate" "{\"id\": \"${update_id}\"}"); then
|
|
echo "::warning::Could not reach Komodo while polling; retrying." >&2
|
|
continue
|
|
fi
|
|
|
|
if [ "$code" != "200" ]; then
|
|
echo "::warning::GetUpdate returned HTTP ${code}; retrying." >&2
|
|
continue
|
|
fi
|
|
|
|
status=$(python3 -c '
|
|
import json, sys
|
|
print(json.load(sys.stdin).get("status", ""))
|
|
' < "$tmp" 2>/dev/null || true)
|
|
|
|
case "$status" in
|
|
Complete)
|
|
if python3 -c '
|
|
import json, sys
|
|
sys.exit(0 if json.load(sys.stdin).get("success") else 1)
|
|
' < "$tmp" 2>/dev/null; then
|
|
echo "Deploy of '${KOMODO_TARGET}' completed successfully."
|
|
exit 0
|
|
fi
|
|
echo "::error::Deploy of '${KOMODO_TARGET}' failed. Komodo update log:" >&2
|
|
python3 -c '
|
|
import json, sys
|
|
d = json.load(sys.stdin)
|
|
for log in d.get("logs", []):
|
|
print(f" [{log.get(\"stage\", \"\")}] {log.get(\"msg\", \"\")}")
|
|
' < "$tmp" >&2 2>/dev/null || cat "$tmp" >&2
|
|
exit 1
|
|
;;
|
|
Queued|InProgress)
|
|
echo " ${elapsed}s: ${status}"
|
|
;;
|
|
*)
|
|
echo " ${elapsed}s: unexpected status '${status}'"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo "::error::Timed out after ${KOMODO_WAIT_TIMEOUT}s waiting for update ${update_id}" >&2
|
|
exit 1
|