feat: implement orphan container cleanup for idempotent stack deployment
All checks were successful
Build And Publish Production Image / Build And Publish Production Image (push) Successful in 7s

This commit is contained in:
2026-03-28 14:56:07 -03:00
parent ff93afd075
commit fda6fc77ee

View File

@@ -153,6 +153,75 @@ jobs:
APPLY_HEADERS=$(mktemp)
APPLY_ERR=$(mktemp)
# If the stack does not exist yet, remove orphan containers with names defined in compose.
# This enables an idempotent create-or-recreate flow when old standalone containers exist.
if [ -z "${STACK_ID}" ]; then
echo "Stack not found in Portainer; checking for orphan containers with conflicting names"
mapfile -t CONTAINER_NAMES < <(awk '/container_name:/{print $2}' docker-compose.prod.yml | tr -d '"' | sed '/^$/d')
for CONTAINER_NAME in "${CONTAINER_NAMES[@]}"; do
FILTERS=$(jq -cn --arg n "^/${CONTAINER_NAME}$" '{name: [$n]}')
FILTERS_URLENC=$(printf '%s' "${FILTERS}" | jq -sRr @uri)
LIST_URL="${ACTIVE_PORTAINER_BASE_URL}/api/endpoints/${PORTAINER_ENDPOINT_ID}/docker/containers/json?all=1&filters=${FILTERS_URLENC}"
LIST_BODY=$(mktemp)
LIST_ERR=$(mktemp)
LIST_HTTP_CODE=$(curl -sS \
--noproxy "*" \
-o "${LIST_BODY}" \
-w "%{http_code}" \
"${LIST_URL}" \
-H "X-API-Key: ${PORTAINER_API_KEY}" \
2>"${LIST_ERR}")
LIST_CURL_EXIT=$?
echo "Container pre-check [${CONTAINER_NAME}] curl=${LIST_CURL_EXIT} http=${LIST_HTTP_CODE}"
if [ "${LIST_CURL_EXIT}" -ne 0 ]; then
echo "Container pre-check stderr for ${CONTAINER_NAME}:"
cat "${LIST_ERR}" || true
continue
fi
if [ "${LIST_HTTP_CODE}" -lt 200 ] || [ "${LIST_HTTP_CODE}" -ge 300 ]; then
echo "Container pre-check non-success response for ${CONTAINER_NAME}:"
cat "${LIST_BODY}" || true
continue
fi
mapfile -t MATCHING_IDS < <(jq -r '.[].Id' "${LIST_BODY}")
if [ "${#MATCHING_IDS[@]}" -eq 0 ]; then
echo "No conflicting container found for ${CONTAINER_NAME}"
continue
fi
for CONTAINER_ID in "${MATCHING_IDS[@]}"; do
DELETE_URL="${ACTIVE_PORTAINER_BASE_URL}/api/endpoints/${PORTAINER_ENDPOINT_ID}/docker/containers/${CONTAINER_ID}?force=1"
DELETE_BODY=$(mktemp)
DELETE_ERR=$(mktemp)
DELETE_HTTP_CODE=$(curl -sS -X DELETE \
--noproxy "*" \
-o "${DELETE_BODY}" \
-w "%{http_code}" \
"${DELETE_URL}" \
-H "X-API-Key: ${PORTAINER_API_KEY}" \
2>"${DELETE_ERR}")
DELETE_CURL_EXIT=$?
echo "Removed conflicting container ${CONTAINER_NAME} (${CONTAINER_ID}) curl=${DELETE_CURL_EXIT} http=${DELETE_HTTP_CODE}"
if [ "${DELETE_CURL_EXIT}" -ne 0 ]; then
echo "Delete stderr:"
cat "${DELETE_ERR}" || true
fi
if [ "${DELETE_HTTP_CODE}" -lt 200 ] || [ "${DELETE_HTTP_CODE}" -ge 300 ]; then
echo "Delete response body:"
cat "${DELETE_BODY}" || true
fi
done
done
fi
if [ -n "${STACK_ID}" ]; then
echo "Updating existing stack id=${STACK_ID}"
REQUEST_URL="${ACTIVE_PORTAINER_BASE_URL}/api/stacks/${STACK_ID}?endpointId=${PORTAINER_ENDPOINT_ID}"