Files
awoooi/ops/runner/check-runner-isolation-readiness.sh

249 lines
7.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Read-only readiness check for splitting the shared 110 Gitea runner pool.
# Run on 110, or from a workstation:
# ssh 192.168.0.110 'bash -s' < ops/runner/check-runner-isolation-readiness.sh
PRIMARY_RUNNER_DIR="${PRIMARY_RUNNER_DIR:-/home/wooo/act-runner}"
PRIMARY_SERVICE_NAME="${PRIMARY_SERVICE_NAME:-gitea-act-runner-host.service}"
SPLIT_RUNNER_DIRS="${SPLIT_RUNNER_DIRS:-/home/wooo/act-runner-awoooi /home/wooo/act-runner-shared /home/wooo/act-runner-ewoooc}"
SPLIT_SERVICE_NAMES="${SPLIT_SERVICE_NAMES:-gitea-act-runner-awoooi.service gitea-act-runner-shared.service gitea-act-runner-ewoooc.service}"
section() {
printf '\n== %s ==\n' "$1"
}
unit_exists() {
local unit="$1"
local load_state
load_state="$(systemctl --user show "$unit" -p LoadState --value 2>/dev/null || true)"
if [ -n "$load_state" ] && [ "$load_state" != "not-found" ]; then
return 0
fi
load_state="$(systemctl show "$unit" -p LoadState --value 2>/dev/null || true)"
[ -n "$load_state" ] && [ "$load_state" != "not-found" ]
}
unit_state() {
local unit="$1"
local load_state
load_state="$(systemctl --user show "$unit" -p LoadState --value 2>/dev/null || true)"
if [ -n "$load_state" ] && [ "$load_state" != "not-found" ]; then
printf 'scope=user '
systemctl --user show "$unit" -p LoadState -p ActiveState -p SubState -p MainPID --no-pager 2>/dev/null | tr '\n' ' '
printf '\n'
return 0
fi
load_state="$(systemctl show "$unit" -p LoadState --value 2>/dev/null || true)"
if [ -n "$load_state" ] && [ "$load_state" != "not-found" ]; then
printf 'scope=system '
systemctl show "$unit" -p LoadState -p ActiveState -p SubState -p MainPID --no-pager 2>/dev/null | tr '\n' ' '
printf '\n'
return 0
fi
printf 'scope=missing ActiveState=missing\n'
}
extract_labels() {
local config_path="$1"
awk '
/^[[:space:]]*labels:[[:space:]]*$/ {
in_labels=1
next
}
in_labels && /^[[:space:]]*-[[:space:]]*/ {
line=$0
sub(/^[[:space:]]*-[[:space:]]*"/, "", line)
sub(/^[[:space:]]*-[[:space:]]*/, "", line)
sub(/"[[:space:]]*$/, "", line)
print line
next
}
in_labels && /^[^[:space:]]/ {
in_labels=0
}
' "$config_path"
}
label_owner() {
local label="$1"
local label_name="${label%%:*}"
case "$label_name" in
awoooi-host)
printf 'awoooi_dedicated'
;;
ewoooc-host)
printf 'foreign_dedicated'
;;
ubuntu-latest|ubuntu-22.04|ubuntu-24.04|self-hosted)
printf 'shared_queue'
;;
*)
printf 'unknown_or_custom'
;;
esac
}
print_primary_runner() {
section "primary runner"
printf 'primary_runner_dir=%s\n' "$PRIMARY_RUNNER_DIR"
printf 'primary_service=%s %s\n' "$PRIMARY_SERVICE_NAME" "$(unit_state "$PRIMARY_SERVICE_NAME")"
if [ -d "$PRIMARY_RUNNER_DIR" ]; then
find "$PRIMARY_RUNNER_DIR" -maxdepth 1 -mindepth 1 \
-printf 'primary_file=%f type=%y mode=%M\n' 2>/dev/null | sort || true
else
printf 'primary_runner_dir_exists=false\n'
fi
if [ -f "${PRIMARY_RUNNER_DIR}/.runner" ]; then
printf 'primary_registration_file=present\n'
else
printf 'primary_registration_file=missing\n'
fi
}
print_label_owners() {
section "primary label owners"
local config_path="${PRIMARY_RUNNER_DIR}/config.yaml"
if [ ! -r "$config_path" ]; then
printf 'config_readable=false\n'
return 0
fi
local labels=()
while IFS= read -r label; do
[ -n "$label" ] && labels+=("$label")
done < <(extract_labels "$config_path")
if [ "${#labels[@]}" -eq 0 ]; then
printf 'labels_found=0\n'
return 0
fi
local owner
local mixed_owner_classes=0
local has_awoooi=0
local has_foreign=0
local has_shared=0
for label in "${labels[@]}"; do
owner="$(label_owner "$label")"
printf 'label=%s owner=%s\n' "$label" "$owner"
case "$owner" in
awoooi_dedicated) has_awoooi=1 ;;
foreign_dedicated) has_foreign=1 ;;
shared_queue) has_shared=1 ;;
esac
done
if [ "$((has_awoooi + has_foreign + has_shared))" -gt 1 ]; then
mixed_owner_classes=1
fi
printf 'mixed_owner_classes=%s\n' "$mixed_owner_classes"
}
print_split_targets() {
section "split target readiness"
local ready_dirs=0
local total_dirs=0
local dir
for dir in $SPLIT_RUNNER_DIRS; do
total_dirs=$((total_dirs + 1))
if [ -d "$dir" ] && [ -f "${dir}/.runner" ] && [ -f "${dir}/config.yaml" ]; then
ready_dirs=$((ready_dirs + 1))
printf 'split_dir=%s status=registered\n' "$dir"
elif [ -d "$dir" ]; then
printf 'split_dir=%s status=incomplete\n' "$dir"
else
printf 'split_dir=%s status=missing\n' "$dir"
fi
done
local ready_services=0
local total_services=0
local service
for service in $SPLIT_SERVICE_NAMES; do
total_services=$((total_services + 1))
if unit_exists "$service"; then
ready_services=$((ready_services + 1))
printf 'split_service=%s %s\n' "$service" "$(unit_state "$service")"
else
printf 'split_service=%s scope=missing ActiveState=missing\n' "$service"
fi
done
printf 'registered_split_dirs=%s/%s\n' "$ready_dirs" "$total_dirs"
printf 'installed_split_services=%s/%s\n' "$ready_services" "$total_services"
}
print_active_tasks() {
section "active tasks"
if ! command -v docker >/dev/null 2>&1; then
printf 'docker=unavailable\n'
return 0
fi
local tasks
tasks="$(docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}' 2>/dev/null | awk '$1 ~ /^GITEA-ACTIONS-TASK-/ { print }' || true)"
if [ -n "$tasks" ]; then
printf '%s\n' "$tasks"
else
printf 'active_action_containers=none\n'
fi
}
print_verdict() {
section "verdict"
local config_path="${PRIMARY_RUNNER_DIR}/config.yaml"
local mixed=0
if [ ! -r "$config_path" ]; then
printf 'isolation_ready=unknown\n'
printf 'blocker=primary_config_unreadable\n'
printf 'safe_next_step=run_on_110_or_set_PRIMARY_RUNNER_DIR\n'
return 0
fi
local owners
owners="$(extract_labels "$config_path" | while IFS= read -r label; do printf '%s\n' "$(label_owner "$label")"; done | sort -u | wc -l | tr -d ' ')"
if [ "${owners:-0}" -gt 1 ]; then
mixed=1
fi
local split_registered=0
local dir
for dir in $SPLIT_RUNNER_DIRS; do
if [ -d "$dir" ] && [ -f "${dir}/.runner" ] && [ -f "${dir}/config.yaml" ]; then
split_registered=$((split_registered + 1))
fi
done
if [ "$mixed" -eq 1 ] && [ "$split_registered" -eq 0 ]; then
printf 'isolation_ready=false\n'
printf 'blocker=single_registered_runner_with_mixed_owner_labels\n'
printf 'safe_next_step=register_additional_runner_dirs_before_removing_live_labels\n'
elif [ "$mixed" -eq 1 ]; then
printf 'isolation_ready=partial\n'
printf 'blocker=split_services_not_fully_installed_or_not_verified\n'
printf 'safe_next_step=drain_then_move_labels_after_split_runner_smoke\n'
else
printf 'isolation_ready=true\n'
printf 'blocker=none\n'
fi
}
main() {
section "audit metadata"
printf 'host=%s\n' "$(hostname 2>/dev/null || printf unknown)"
printf 'user=%s\n' "$(id -un 2>/dev/null || printf unknown)"
printf 'timestamp=%s\n' "$(date -Is 2>/dev/null || date)"
printf 'read_only=true\n'
print_primary_runner
print_label_owners
print_split_targets
print_active_tasks
print_verdict
}
main "$@"