Use simple preferred scheduling for Factorio
Test and deploy Factorio / validate (push) Successful in 30s
Test and deploy Factorio / deploy (push) Successful in 17s

This commit is contained in:
2026-10-17 16:34:59 +02:00
parent 72a1d3e886
commit 1aa4d28a60
15 changed files with 25 additions and 285 deletions
-34
View File
@@ -1,34 +0,0 @@
#!/bin/sh
# Read-only node health; patch only the named Factorio Deployment.
set -eu
node=$(kubectl get node arschrock --ignore-not-found -o json)
deployment=$(kubectl -n factorio get deployment factorio -o json)
current=$(printf '%s' "$deployment" | jq -c '.spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].values')
if [ -z "$node" ]; then
mode=odroids
else
mode=$(printf '%s' "$node" | jq -r '
if .metadata.labels["factorio.brunner.ninja/unavailable"] == "true" or .spec.unschedulable == true then "odroids"
else ([.status.conditions[] | select(.type == "Ready")][0]) as $ready |
if $ready == null then "hold"
elif (now - ($ready.lastTransitionTime | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601)) < 300 then "hold"
elif $ready.status == "True" then "primary" else "odroids" end
end')
fi
case "$mode" in
primary) desired='["arschrock"]' ;;
odroids) desired='["odroid-h3-00","odroid-h3-01","odroid-h3-02","odroid-h3-03","odroid-h3-04","odroid-h3-05"]' ;;
hold) echo 'Node health transition less than five minutes ago; holding placement'; exit 0 ;;
*) exit 1 ;;
esac
if [ "$current" = "$desired" ]; then
echo "Placement unchanged: $mode"
exit 0
fi
# Optimistic concurrency: never overwrite a concurrent deployment or maintenance action.
patch=$(printf '%s' "$deployment" | jq -c --argjson nodes "$desired" '[
{op:"test",path:"/metadata/resourceVersion",value:.metadata.resourceVersion},
{op:"replace",path:"/spec/template/spec/affinity/nodeAffinity/requiredDuringSchedulingIgnoredDuringExecution/nodeSelectorTerms/0/matchExpressions/0/values",value:$nodes}
]')
kubectl -n factorio patch deployment factorio --type=json -p "$patch"
echo "Placement changed to $mode"
+1 -5
View File
@@ -1,4 +1,4 @@
"""Preserve reconciler-owned placement; roll when mounted configuration changes."""
"""Roll the server when mounted configuration changes."""
import hashlib
import json
import sys
@@ -6,16 +6,12 @@ from pathlib import Path
import yaml
docs = list(yaml.safe_load_all(Path(sys.argv[1]).read_text()))
live_text = Path(sys.argv[2]).read_text().strip()
live = json.loads(live_text) if live_text else None
config = {d['metadata']['name']: d.get('data', {}) for d in docs if d['kind'] == 'ConfigMap' and d['metadata']['namespace'] == 'factorio'}
checksum = hashlib.sha256(json.dumps(config, sort_keys=True).encode()).hexdigest()
for doc in docs:
if doc['kind'] == 'Deployment' and doc['metadata']['name'] == 'factorio':
template = doc['spec']['template']
template['metadata'].setdefault('annotations', {})['factorio.brunner.ninja/config-revision'] = checksum
if live:
template['spec']['affinity'] = live['spec']['template']['spec']['affinity']
# The fresh PVC is an administrator bootstrap resource. CI never owns storage.
if doc['kind'] == 'PersistentVolumeClaim':
continue