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
All checks were successful
Build And Publish Production Image / Build And Publish Production Image (push) Successful in 7s
This commit is contained in:
@@ -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}"
|
||||
|
||||
Reference in New Issue
Block a user