#!/usr/bin/env bash set -euo pipefail readonly expected_context="kubernetes-admin@kubernetes" readonly node="arschrock" readonly dynmap_ready_label="minecraft.brunner.ninja/dynmap-ready" readonly library_services=(lidarr.service readarr.service radarr.service sonarr.service bazarr.service) readonly whisparr_service="whisparr.service" current_context="$(kubectl config current-context)" if [[ "${current_context}" != "${expected_context}" ]]; then echo "Refusing to modify ${node}: context is ${current_context}, expected ${expected_context}." >&2 exit 1 fi # These host-native library managers must never inspect the empty Btrfs # directory underneath /komposthaufen when its Bcachefs mount is offline. sudo -n systemctl stop "${library_services[@]}" "${whisparr_service}" for service in "${library_services[@]}" "${whisparr_service}"; do if sudo -n systemctl is-active --quiet "${service}"; then echo "${service} is still active; do not unmount /komposthaufen." >&2 exit 1 fi done kubectl get node "${node}" >/dev/null if ! kubectl label node "${node}" media.brunner.ninja/multimedia-ready- 2>/dev/null; then labels=$(kubectl get node "${node}" --output=jsonpath='{.metadata.labels}') if [[ "${labels}" == *"media.brunner.ninja/multimedia-ready"* ]]; then echo "Could not remove the media-ready label from ${node}; do not unmount." >&2 exit 1 fi fi for namespace in plex jellyfin copyparty; do scheduled_pods=$(kubectl --namespace "${namespace}" get pods \ --selector="app.kubernetes.io/component=server" \ --field-selector="spec.nodeName=${node}" \ --output=name) if [[ -n "${scheduled_pods}" ]]; then mapfile -t pod_names <<< "${scheduled_pods}" kubectl --namespace "${namespace}" delete "${pod_names[@]}" --wait=false for pod in "${pod_names[@]}"; do kubectl --namespace "${namespace}" wait --for=delete "${pod}" --timeout=5m done fi done if ! kubectl label node "${node}" "${dynmap_ready_label}-" 2>/dev/null; then labels=$(kubectl get node "${node}" --output=jsonpath='{.metadata.labels}') if [[ "${labels}" == *"${dynmap_ready_label}"* ]]; then echo "Could not remove the Dynmap-ready label from ${node}; do not unmount." >&2 exit 1 fi fi mapfile -t paper_pods < <(kubectl --namespace mcserver get pods \ --selector="app.kubernetes.io/name=minecraft-paper,app.kubernetes.io/instance=paper" \ --field-selector="spec.nodeName=${node}" --output=name) if ((${#paper_pods[@]})); then kubectl --namespace mcserver delete "${paper_pods[@]}" --wait=false for pod in "${paper_pods[@]}"; do kubectl --namespace mcserver wait --for=delete "${pod}" --timeout=15m done fi for namespace in plex jellyfin copyparty; do remaining_pods=$(kubectl --namespace "${namespace}" get pods \ --selector="app.kubernetes.io/component=server" \ --field-selector="spec.nodeName=${node}" \ --output=name) if [[ -n "${remaining_pods}" ]]; then echo "A ${namespace} Pod is still assigned to ${node}; do not unmount." >&2 exit 1 fi done echo "Plex, Jellyfin, Copyparty and Paper are stopped on ${node}. Replacements stay Pending until their storage-ready labels return."