Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d86f209
Add --include-deps option to Docker image pulls and retries to Docker…
bjreath Sep 10, 2020
c5883ed
Merge pull request #8 from joinhandshake/apr/4.16.0-port
rayalan Jan 17, 2024
0782f49
Fix for graceful shutdown option. Don't call docker rm --force until …
Apr 24, 2024
853a524
Merge remote-tracking branch 'upstream/master' into davkutalek/premat…
Apr 25, 2024
af54780
working on testing graceful shutdown fix
Apr 25, 2024
bebc54f
fixed broken tests
Apr 25, 2024
1b6df23
try running docker shell arg in [] to use exec mode
Apr 29, 2024
dc72a0f
try graceful compose shutdown
Apr 30, 2024
553a8d6
pass service name arg to stop/wait
Apr 30, 2024
4dbb936
exit upon getting term signal, otherwise service restarts
Apr 30, 2024
846e1bc
Don't run docker command in subshell, obviously signals wont make it\!
Apr 30, 2024
e5fd440
rewrite run.sh to use docker compose exec form. All the tests broke, …
Apr 30, 2024
99c0fc3
revert previous since it isn't working
Apr 30, 2024
722c50e
attempt to run shell script without sh -c which creates new shell
Apr 30, 2024
47d200d
syntax fix
Apr 30, 2024
aa1220c
try subshell with direct command
Apr 30, 2024
8e06129
refactor subshell to make it a little clearer, prevent exitcode -u issue
May 1, 2024
1a5d072
try not using a subshell again
May 1, 2024
385869d
Revert failed changes, Cleanup with some learnings. all tests passing
May 6, 2024
4eeae5d
one last attempt with no subshell and no sh -c
May 6, 2024
2e15fd5
use subshell but not bin/sh
May 6, 2024
88a6602
use bin/sh without e flag
May 6, 2024
8714720
fix service ref
May 7, 2024
8189dcf
revert prev
May 7, 2024
d21572b
no subshell
May 7, 2024
fccdf08
no sh
May 7, 2024
92ae4b4
revert
May 7, 2024
6490c0b
add logging
May 7, 2024
2d801bb
revert remove sh
May 7, 2024
130008f
Merge tag 'v4.16.0.1' into davkutalek/premature-kill-fix
May 8, 2024
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
34 changes: 15 additions & 19 deletions commands/run.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/bin/bash
set -ueo pipefail

. "$DIR/../lib/log.bash"

# Run takes a service name, pulls down any pre-built image for that name
# and then runs docker-compose run a generated project name

Expand Down Expand Up @@ -71,9 +73,9 @@ fi

# If there are multiple services to pull, run it in parallel (although this is now the default)
if [[ ${#pull_services[@]} -gt 1 ]] ; then
pull_params+=("pull" "--parallel" "${pull_services[@]}")
pull_params+=("pull" "--parallel" "--include-deps" "${pull_services[@]}")
elif [[ ${#pull_services[@]} -eq 1 ]] ; then
pull_params+=("pull" "${pull_services[0]}")
pull_params+=("pull" "--include-deps" "${pull_services[0]}")
fi

# Pull down specified services
Expand Down Expand Up @@ -447,36 +449,30 @@ elif [[ ${#command[@]} -gt 0 ]] ; then
fi

ensure_stopped() {
echo '+++ :warning: Signal received, stopping container'
docker stop "${container_name}" || true
log 143
echo '+++ :warning: Signal received, stopping container gracefully'
# docker stop "${container_name}" || true
compose_cleanup ${run_service}
echo '~~~ Last log lines that may be missing above (if container was not already removed)'
docker logs "${container_name}" || true
exitcode='TRAP'
exit 143
}

trap ensure_stopped SIGINT SIGTERM SIGQUIT
trap 'ensure_stopped "$?"' SIGINT SIGTERM SIGQUIT

if [[ "${BUILDKITE_PLUGIN_DOCKER_COMPOSE_COLLAPSE_LOGS:-false}" = "true" ]]; then
group_type="---"
else
group_type="+++"
fi

# Disable -e to prevent cancelling step if the command fails for whatever reason
set +e
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unneccessary if we use the || exitcode=$? syntax.

( # subshell is necessary to trap signals (compose v2 fails to stop otherwise)
exitcode=0
(
echo "${group_type} :docker: Running ${display_command[*]:-} in service $run_service" >&2
run_docker_compose "${run_params[@]}"
)
exitcode=$?

# Restore -e as an option.
set -e
) || exitcode=$?

if [[ $exitcode = "TRAP" ]]; then
# command failed due to cancellation signal, make sure there is an error but no further output
exitcode=-1
elif [[ $exitcode -ne 0 ]] ; then
if [[ $exitcode -ne 0 ]] ; then
echo "^^^ +++"
echo "+++ :warning: Failed to run command, exited with $exitcode, run params:"
echo "${run_params[@]}"
Expand All @@ -490,4 +486,4 @@ if [[ -n "${BUILDKITE_AGENT_ACCESS_TOKEN:-}" ]] ; then
fi
fi

return "$exitcode"
return "$exitcode"
2 changes: 1 addition & 1 deletion hooks/pre-exit
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ if [[ -n "$(plugin_read_list RUN)" ]] && [[ "$(plugin_read_config CLEANUP "true"
. "$DIR/../lib/run.bash"

echo "~~~ :docker: Cleaning up after docker-compose" >&2
compose_cleanup
compose_cleanup ""
fi
40 changes: 40 additions & 0 deletions lib/log.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash

log() {
msg="SIG $1 received, process exiting"
echo "${msg}"
buildkite-agent meta-data set "dd_tags.job-signal-${BUILDKITE_STEP_KEY}" "$1"
buildkite-agent meta-data set "dd_tags.step-error-code-${BUILDKITE_STEP_KEY}" "$1"
buildkite-agent meta-data set "dd_tags.job-error-code-${BUILDKITE_JOB_ID}" "$1"

echo "$(pidof buildkite-agent) is the pid of the buildkite agent" || true

send_job_signaled_to_dd "${msg}" "${1}"
}

send_job_signaled_to_dd() {
send_event_to_dd '{ "title": "Job '"${BUILDKITE_STEP_KEY}"' received signal", "text": "'"${1}"'", "alert_type": "error", "tags": [ "ci:job_signal", "exit_status:'"${2}"'", "job_name:'"${BUILDKITE_STEP_KEY}"'", "build_id:'"${BUILDKITE_BUILD_ID}"'", "branch:'"${BUILDKITE_BRANCH}"'", "hs_source:docker_compose_plugin", "env:ci" ] }'
}

send_event_to_dd() {
if command -v curl >/dev/null 2>&1; then
echo "Using curl to send event to Datadog"
curl -X POST "https://api.datadoghq.com/api/v1/events" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "DD-API-KEY: ${DD_API_KEY}" \
-d "$1"
elif command -v wget >/dev/null 2>&1; then
echo "Using wget to send event to Datadog"
wget \
--header="Accept: application/json" \
--header="Content-Type: application/json" \
--header="DD-API-KEY: ${DD_API_KEY}" \
--post-data="$1" \
--output-document - \
https://api.datadoghq.com/api/v1/events
else
echo "No suitable network tool found to send event to Datadog"
exit 1
fi
}
27 changes: 20 additions & 7 deletions lib/run.bash
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#!/bin/bash

compose_cleanup() {
if [[ "$(plugin_read_config GRACEFUL_SHUTDOWN 'false')" == "false" ]]; then
# Send all containers a SIGKILL
run_docker_compose kill || true
else
# Send all containers a friendly SIGTERM, followed by a SIGKILL after exceeding the stop_grace_period
run_docker_compose stop || true
kill_or_wait_for_stop() {

if [[ "$(plugin_read_config GRACEFUL_SHUTDOWN 'false')" == "true" ]]; then
# This will block until the container exits
run_docker_compose wait "$1"
container_exit_code=$?
echo "exit code was $container_exit_code"
fi

# This will kill the container if it hasn't exited yet
# `compose down` doesn't support force removing images
if [[ "$(plugin_read_config LEAVE_VOLUMES 'false')" == "false" ]]; then
run_docker_compose rm --force -v || true
Expand All @@ -24,6 +25,18 @@ compose_cleanup() {
fi
}

compose_cleanup() {
kill_or_wait_for_stop "$1" &
sleep 1

# No need to call kill directly for GRACEFUL_SHUTDOWN == false since rm --force will send the same kill signal
if [[ "$(plugin_read_config GRACEFUL_SHUTDOWN 'false')" == "true" ]]; then
echo "graceful shutdown was true, stopping ${1}"
# Send all containers a friendly SIGTERM, followed by a SIGKILL after exceeding the stop_grace_period
run_docker_compose stop "$1" || true
fi
}

# Checks for failed containers and writes logs for them the the provided dir
check_linked_containers_and_save_logs() {
local service="$1"
Expand Down
4 changes: 4 additions & 0 deletions plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ configuration:
type: [ boolean, array ]
skip-checkout:
type: boolean
stop-signal:
type: string
leave-volumes:
type: boolean
skip-pull:
type: boolean
ssh:
Expand Down
3 changes: 1 addition & 2 deletions tests/cleanup.bats
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ load '../lib/run'
export BUILDKITE_PLUGIN_DOCKER_COMPOSE_CLEANUP=true

stub docker \
"compose -f docker-compose.yml -p buildkite1111 kill : echo killing containers" \
"compose -f docker-compose.yml -p buildkite1111 rm --force -v : echo removing stopped containers" \
"compose -f docker-compose.yml -p buildkite1111 rm --force -v : echo killing and removing stopped containers" \
"compose -f docker-compose.yml -p buildkite1111 down --remove-orphans --volumes : echo removing everything"

run "$PWD"/hooks/pre-exit
Expand Down
19 changes: 9 additions & 10 deletions tests/docker-compose-cleanup.bats
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,26 @@ setup () {
run compose_cleanup

assert_success
assert_equal "${lines[0]}" "kill"
assert_equal "${lines[1]}" "rm --force -v"
assert_equal "${lines[2]}" "down --remove-orphans --volumes"
assert_equal "${lines[0]}" "rm --force -v"
assert_equal "${lines[1]}" "down --remove-orphans --volumes"
}

@test "Possible to gracefully shutdown containers in docker-compose cleanup" {
export BUILDKITE_PLUGIN_DOCKER_COMPOSE_GRACEFUL_SHUTDOWN=1
export BUILDKITE_PLUGIN_DOCKER_COMPOSE_GRACEFUL_SHUTDOWN="true"
run compose_cleanup

assert_success
assert_equal "${lines[0]}" "stop"
assert_equal "${lines[1]}" "rm --force -v"
assert_equal "${lines[2]}" "down --remove-orphans --volumes"
assert_output --partial "wait"
assert_equal "${lines[1]}" "exit code was 0"
assert_equal "${lines[2]}" "rm --force -v"
assert_equal "${lines[3]}" "down --remove-orphans --volumes"
}

@test "Possible to skip volume destruction in docker-compose cleanup" {
export BUILDKITE_PLUGIN_DOCKER_COMPOSE_LEAVE_VOLUMES=1
run compose_cleanup

assert_success
assert_equal "${lines[0]}" "kill"
assert_equal "${lines[1]}" "rm --force"
assert_equal "${lines[2]}" "down --remove-orphans"
assert_equal "${lines[0]}" "rm --force"
assert_equal "${lines[1]}" "down --remove-orphans"
}