From 09dffc3933cb28b5886e6e571634551c8cc35363 Mon Sep 17 00:00:00 2001 From: Andrew Stowell Date: Fri, 24 Jul 2026 23:43:31 -0400 Subject: [PATCH] new docker scripts, pull and heal. --- crons/docker-healing.sh | 68 ++++++++++++++++++++++++++++++++++++++ pull-docker.sh | 73 +++++++++++++++++++++++++++++++++++++++++ setup/config/vim-vimrc | 6 ++++ 3 files changed, 147 insertions(+) create mode 100755 crons/docker-healing.sh create mode 100755 pull-docker.sh diff --git a/crons/docker-healing.sh b/crons/docker-healing.sh new file mode 100755 index 0000000..c4bf98f --- /dev/null +++ b/crons/docker-healing.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +notify() { + local color="$1" + local msg="$2" + local hostname=$(hostname) + echo "$msg" + ntfy pub -T "${color}_square" -t "Docker Health on ${hostname}" docker "$msg" >/dev/null 2>&1 || true +} + +declare -A compose_projects +declare -a standalone_containers + +# Find unhealthy containers +while read -r container; do + health=$(docker inspect \ + --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' \ + "$container") + + # Ignore missing health checks and containers still starting + if [[ "$health" != "unhealthy" ]]; then + continue + fi + + project_dir=$(docker inspect \ + --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}' \ + "$container") + + if [[ -n "$project_dir" && "$project_dir" != "" ]]; then + compose_projects["$project_dir"]+="$container " + else + standalone_containers+=("$container") + fi + +done < <(docker ps -q) + +# Restart compose projects once each +for project_dir in "${!compose_projects[@]}"; do + containers="${compose_projects[$project_dir]}" + + notify "orange" "Unhealthy containers in $(basename "$project_dir"): $containers" + + if [[ -f "$project_dir/compose.yaml" ]]; then + if docker compose \ + --project-directory "$project_dir" \ + up -d --force-recreate; then + + notify "green" "Recovery succeeded: $(basename "$project_dir")" + else + notify "red" "Recovery FAILED: $(basename "$project_dir")" + fi + else + notify "black" "Missing compose.yaml in $project_dir" + fi +done + +# Restart standalone containers +for container in "${standalone_containers[@]}"; do + notify "orange" "Unhealthy standalone container $container" + + if docker restart "$container" >/dev/null; then + notify "green" "Recovery succeeded: $container" + else + notify "red" "Recovery FAILED: $container" + fi +done + diff --git a/pull-docker.sh b/pull-docker.sh new file mode 100755 index 0000000..9cfbcad --- /dev/null +++ b/pull-docker.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +# perform a "docker compose pull" on each location specified (recursively), or current location if none specified. +# +# will only search symbolic links when passed "-l" option, must be before any locations +# will only search hidden directories when passed "-h" option, must be before any locations +# pull-all.sh [-l][-h] # current location implied +# pull-all.sh [-l][-h] ~/my-projects /var/group-projects + +# check for "-l" and "-h" in command prompt +followLinks="-H" +checkHidden="*/.*/*compose.yaml" +while getopts "lh" option; do + case $option in + l) + followLinks="-L" + ;; + h) + checkHidden="" + ;; + esac +done +shift "$((OPTIND-1))" + +if [[ "-H" == "$followLinks" ]]; then + echo "use -l to follow symbolic links" +fi + +if [[ -n "$checkHidden" ]]; then + echo "use -h to check hidden directories" +fi + +# function to process each location +function process_docker_pull () { + startedIn=`pwd` + location=$(realpath $(dirname "$@")) + line="--- --- --- --- --- --- --- --- ---" + # use "--" to tell printf there are no more commands, only strings to print + printf -- "--- docker compose pull %s %s ---\n" "$location" "${line:${#location}}" + cd "$location" + + # populate $runningServices[] + mapfile -t runningServices < <( + docker compose ps --services --status running + ) + + quietDocker=$(docker compose pull --ignore-buildable --ignore-pull-failures) + + if docker compose up -d --dry-run | grep -q "Recreate"; then + # Only restart services that were already running + if ((${#runningServices[@]} > 0)); then + echo "restarting the following services: ${runningServices[@]}" + quietDocker=$(docker compose up -d "${runningServices[@]}") + else + echo "updates downloaded, no services were running" + fi + else + messageSuffix="" + if ((${#runningServices[@]} > 0)); then + messageSuffix=", services already current: ${runningServices[@]}" + fi + echo "no changes detected$messageSuffix" + fi + + cd "$startedIn" +} + +# find all folders named ".git" under given locations, +# and call process_git_pull on each location that was found. +# we then work on the folder that contained the ".git" folder. + +find "$followLinks" "$@" -type f \( -name 'compose.yaml' -o -name 'docker-compose.yaml' \) -not -path "$checkHidden" | sort | while read -r file; do process_docker_pull "$file"; done + diff --git a/setup/config/vim-vimrc b/setup/config/vim-vimrc index 519c2cd..7181b5f 100644 --- a/setup/config/vim-vimrc +++ b/setup/config/vim-vimrc @@ -66,6 +66,12 @@ Plug 'airblade/vim-gitgutter' Plug 'vim-airline/vim-airline' Plug 'vim-airline/vim-airline-themes' +" twig support (php templating) +Plug 'lumiliet/vim-twig' + +" AnsiEsc to make editing colorful files better +Plug 'powerman/vim-plugin-AnsiEsc' + call plug#end() " config git-gutter