Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change shell to sh #22

Merged
merged 7 commits into from
Mar 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 29 additions & 50 deletions docker-rollout
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/bin/bash
#!/bin/sh
set -e

# Defaults
HEALTHCHECK_TIMEOUT=60
NO_HEALTHCHECK_TIMEOUT=10

# Print metadata for Docker CLI plugin
if [[ "$1" == "docker-cli-plugin-metadata" ]]; then
if [ "$1" = "docker-cli-plugin-metadata" ]; then
cat <<EOF
{
"SchemaVersion": "0.1.0",
Expand All @@ -19,8 +19,8 @@ EOF
fi

# Save docker arguments, i.e. arguments before "rollout"
while [[ $# -gt 0 ]]; do
if [[ "$1" == "rollout" ]]; then
while [ $# -gt 0 ]; do
if [ "$1" = "rollout" ]; then
shift
break
fi
Expand Down Expand Up @@ -64,66 +64,49 @@ exit_with_usage() {
}

healthcheck() {
local container_id="$1"

# shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
if docker $DOCKER_ARGS inspect --format='{{json .State.Health.Status}}' "$container_id" | grep -v "unhealthy" | grep -q "healthy"; then
return 0
fi

return 1
docker $DOCKER_ARGS inspect --format='{{json .State.Health.Status}}' "$1" | grep -v "unhealthy" | grep -q "healthy"
}

scale() {
local service="$1"
local replicas="$2"

# shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
$COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES up --detach --scale "$service=$replicas" --no-recreate "$service"
$COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES up --detach --scale "$1=$2" --no-recreate "$1"
}

main() {
# shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
if [[ "$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE")" == "" ]]; then
if [ -z "$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE")" ]; then
echo "==> Service '$SERVICE' is not running. Starting the service."
$COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES up --detach --no-recreate "$SERVICE"
exit 0
fi

# shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
OLD_CONTAINER_IDS_STRING=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE")
OLD_CONTAINER_IDS=()
for container_id in $OLD_CONTAINER_IDS_STRING; do
OLD_CONTAINER_IDS+=("$container_id")
done

SCALE=${#OLD_CONTAINER_IDS[@]}
OLD_CONTAINER_IDS_STRING=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | tr '\n' '|' | sed 's/|$//')
OLD_CONTAINER_IDS=$(echo "$OLD_CONTAINER_IDS_STRING" | tr '|' ' ')
SCALE=$(echo "$OLD_CONTAINER_IDS" | wc -w | tr -d ' ')
SCALE_TIMES_TWO=$((SCALE * 2))
echo "==> Scaling '$SERVICE' to '$SCALE_TIMES_TWO' instances"
scale "$SERVICE" $SCALE_TIMES_TWO

# Create a variable that contains the IDs of the new containers, but not the old ones
# shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files
NEW_CONTAINER_IDS_STRING=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | grep --invert-match --file <(echo "$OLD_CONTAINER_IDS_STRING"))
NEW_CONTAINER_IDS=()
for container_id in $NEW_CONTAINER_IDS_STRING; do
NEW_CONTAINER_IDS+=("$container_id")
done
NEW_CONTAINER_IDS=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | grep -Ev "$OLD_CONTAINER_IDS_STRING" | tr '\n' ' ')

# Check if first container has healthcheck
# shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
if docker $DOCKER_ARGS inspect --format='{{json .State.Health}}' "${OLD_CONTAINER_IDS[0]}" | grep --quiet "Status"; then
if docker $DOCKER_ARGS inspect --format='{{json .State.Health}}' "$(echo $OLD_CONTAINER_IDS | cut -d\ -f 1)" | grep -q "Status"; then
echo "==> Waiting for new containers to be healthy (timeout: $HEALTHCHECK_TIMEOUT seconds)"
for _ in $(seq 1 "$HEALTHCHECK_TIMEOUT"); do
SUCCESS=0

for NEW_CONTAINER_ID in "${NEW_CONTAINER_IDS[@]}"; do
for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do
if healthcheck "$NEW_CONTAINER_ID"; then
SUCCESS=$((SUCCESS + 1))
fi
done

if [[ "$SUCCESS" == "$SCALE" ]]; then
if [ "$SUCCESS" = "$SCALE" ]; then
break
fi

Expand All @@ -132,21 +115,17 @@ main() {

SUCCESS=0

for NEW_CONTAINER_ID in "${NEW_CONTAINER_IDS[@]}"; do
for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do
if healthcheck "$NEW_CONTAINER_ID"; then
SUCCESS=$((SUCCESS + 1))
fi
done

if [[ "$SUCCESS" != "$SCALE" ]]; then
if [ "$SUCCESS" != "$SCALE" ]; then
echo "==> New containers are not healthy. Rolling back." >&2

for NEW_CONTAINER_ID in "${NEW_CONTAINER_IDS[@]}"; do
# shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
docker $DOCKER_ARGS stop "$NEW_CONTAINER_ID"
# shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
docker $DOCKER_ARGS rm "$NEW_CONTAINER_ID"
done
docker $DOCKER_ARGS stop $NEW_CONTAINER_IDS
docker $DOCKER_ARGS rm $NEW_CONTAINER_IDS

exit 1
fi
Expand All @@ -155,17 +134,15 @@ main() {
sleep "$NO_HEALTHCHECK_TIMEOUT"
fi

echo "==> Stopping old containers"
echo "==> Stopping and removing old containers"

for OLD_CONTAINER_ID in "${OLD_CONTAINER_IDS[@]}"; do
# shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
docker $DOCKER_ARGS stop "$OLD_CONTAINER_ID"
# shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments
docker $DOCKER_ARGS rm "$OLD_CONTAINER_ID"
done
# shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments
docker $DOCKER_ARGS stop $OLD_CONTAINER_IDS
# shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments
docker $DOCKER_ARGS rm $OLD_CONTAINER_IDS
}

while [[ $# -gt 0 ]]; do
while [ $# -gt 0 ]; do
case "$1" in
-h | --help)
usage
Expand All @@ -192,9 +169,11 @@ while [[ $# -gt 0 ]]; do
exit_with_usage
;;
*)
if [[ -n "$SERVICE" ]]; then
if [ -n "$SERVICE" ]; then
echo "SERVICE is already set to '$SERVICE'"
exit_with_usage
if [ "$SERVICE" != "$1" ]; then
exit_with_usage
fi
fi

SERVICE="$1"
Expand All @@ -204,7 +183,7 @@ while [[ $# -gt 0 ]]; do
done

# Require SERVICE argument
if [[ -z "$SERVICE" ]]; then
if [ -z "$SERVICE" ]; then
echo "SERVICE is missing"
exit_with_usage
fi
Expand Down
Loading