249 lines
7.2 KiB
Bash
Executable File
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 "$@"
|