Runner pool classes + the git host script: a bounded build-remote run takes its pool cores as class release (v5 when its label names a v5 gate or kit), writes the class into its wait line so lease-pool sweeps yield to it, and yields itself only to a higher class (slot self-test green on build-2); infra/build-server/forgejo.sh = the Forgejo stand-up on build-1 as run at 20:29 BST (docker, Caddy block, ufw 2222, app.ini with generated secrets kept on the box)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
e48a512c3f
commit
0a10ca5e2a
2 changed files with 143 additions and 8 deletions
126
infra/build-server/forgejo.sh
Normal file
126
infra/build-server/forgejo.sh
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#!/usr/bin/env bash
|
||||
# The git host (main, 7 October 2026 20:29 BST; GitHub suspended): Forgejo 9 under docker on build-1, data under /srv/git (config
|
||||
# app.ini written once with generated secrets, kept on the box only), ssh on 2222 public, http 3000 on loopback behind Caddy at
|
||||
# git.igneum.network (ACME), deSEC A record by hand (dns.sh pattern). Then, by hand through the API as the owner user igneum-labs
|
||||
# (credentials in ~/.config/igneum/forgejo-admin on the Mac): org igneum-network, private repos igneum and spec, the Mac key on the
|
||||
# owner; registration off, anonymous read off, push-to-create off. Nightly dump to build-2 by /usr/local/bin/forgejo-backup.sh
|
||||
# (forgejo-backup.timer 03:30 UTC). Runs as root on the box: scp it over and run it. Idempotent.
|
||||
set -euo pipefail
|
||||
mkdir -p /srv/git/data /srv/git/config
|
||||
chown -R 1000:1000 /srv/git
|
||||
if [ ! -s /srv/git/config/app.ini ]; then
|
||||
SECRET=$(head -c 48 /dev/urandom | base64 | tr -d '/+=' | head -c 48)
|
||||
JWT=$(head -c 48 /dev/urandom | base64 | tr -d '/+=' | head -c 48)
|
||||
LFSJWT=$(head -c 48 /dev/urandom | base64 | tr -d '/+=' | head -c 48)
|
||||
cat > /srv/git/config/app.ini <<INI
|
||||
APP_NAME = Igneum
|
||||
RUN_MODE = prod
|
||||
RUN_USER = git
|
||||
WORK_PATH = /data/gitea
|
||||
|
||||
[server]
|
||||
PROTOCOL = http
|
||||
DOMAIN = git.igneum.network
|
||||
ROOT_URL = https://git.igneum.network/
|
||||
HTTP_ADDR = 0.0.0.0
|
||||
HTTP_PORT = 3000
|
||||
SSH_DOMAIN = git.igneum.network
|
||||
SSH_PORT = 2222
|
||||
SSH_LISTEN_PORT = 22
|
||||
START_SSH_SERVER = false
|
||||
DISABLE_SSH = false
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = $LFSJWT
|
||||
OFFLINE_MODE = true
|
||||
LANDING_PAGE = login
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
PATH = /data/gitea/forgejo.db
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
DEFAULT_PRIVATE = private
|
||||
FORCE_PRIVATE = true
|
||||
ENABLE_PUSH_CREATE_USER = false
|
||||
ENABLE_PUSH_CREATE_ORG = false
|
||||
DEFAULT_BRANCH = master
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = true
|
||||
REQUIRE_SIGNIN_VIEW = true
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = true
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = false
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = $SECRET
|
||||
INTERNAL_TOKEN = $JWT
|
||||
PASSWORD_HASH_ALGO = argon2
|
||||
MIN_PASSWORD_LENGTH = 16
|
||||
|
||||
[oauth2]
|
||||
ENABLED = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = false
|
||||
ENABLE_OPENID_SIGNUP = false
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
COOKIE_SECURE = true
|
||||
|
||||
[log]
|
||||
MODE = file
|
||||
LEVEL = Info
|
||||
ROOT_PATH = /data/gitea/log
|
||||
|
||||
[other]
|
||||
SHOW_FOOTER_VERSION = false
|
||||
|
||||
[actions]
|
||||
ENABLED = false
|
||||
|
||||
[packages]
|
||||
ENABLED = false
|
||||
|
||||
[federation]
|
||||
ENABLED = false
|
||||
INI
|
||||
chown 1000:1000 /srv/git/config/app.ini; chmod 600 /srv/git/config/app.ini
|
||||
fi
|
||||
if ! docker ps -a --format '{{.Names}}' | grep -qx forgejo; then
|
||||
docker run -d --name forgejo --restart unless-stopped \
|
||||
-e USER_UID=1000 -e USER_GID=1000 -e FORGEJO_CUSTOM=/data/gitea \
|
||||
-v /srv/git/data:/data -v /srv/git/config/app.ini:/data/gitea/conf/app.ini \
|
||||
-v /etc/timezone:/etc/timezone:ro -v /etc/localtime:/etc/localtime:ro \
|
||||
-p 127.0.0.1:3000:3000 -p 2222:22 \
|
||||
--cpus 4 --memory 8g \
|
||||
codeberg.org/forgejo/forgejo:9 >/dev/null
|
||||
fi
|
||||
ufw allow 2222/tcp >/dev/null
|
||||
if ! grep -q "^git.igneum.network" /etc/caddy/Caddyfile; then
|
||||
cat >> /etc/caddy/Caddyfile <<'CADDY'
|
||||
|
||||
# the git host (Forgejo in docker, infra/build-server/forgejo.sh): everything proxied, nothing cached
|
||||
git.igneum.network {
|
||||
tls {
|
||||
issuer acme
|
||||
}
|
||||
reverse_proxy 127.0.0.1:3000
|
||||
request_body {
|
||||
max_size 2GB
|
||||
}
|
||||
}
|
||||
CADDY
|
||||
caddy fmt --overwrite /etc/caddy/Caddyfile >/dev/null 2>&1 || true
|
||||
systemctl reload caddy
|
||||
fi
|
||||
for i in $(seq 1 30); do curl -fsS -o /dev/null http://127.0.0.1:3000/ 2>/dev/null && break; sleep 2; done
|
||||
echo "forgejo container: $(docker ps --format '{{.Names}} {{.Status}}' | grep forgejo)"
|
||||
echo "http 3000: $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/)"
|
||||
echo "ssh 2222: $(timeout 5 bash -c 'exec 3<>/dev/tcp/127.0.0.1/2222; head -c 40 <&3' 2>/dev/null | tr -d '\r\n' | cut -c1-40)"
|
||||
|
|
@ -480,18 +480,27 @@ BR_RUN_LOG="$RUN_LOG_DIR/$BR_HOST-$BR_T0-$BR_PID.log"; export BR_RUN_LOG
|
|||
# (nice 0, a gate or a release build) is outside the pool and keeps the full set.
|
||||
ncpu=$(nproc); cores_str="0-$((ncpu - 1))"
|
||||
pool_fds=(); pool_cores=()
|
||||
# the pool's priority classes (lease.sh, main 7 Oct 2026 20:37 BST: release > v5 > measure > adv): a bounded build or suite is class
|
||||
# release (rank 0) unless its label names a "v5 gate" or "v5 kit" (class v5, rank 1); the wait file carries "class <name>/<rank>:" so
|
||||
# `lease pool` sweeps (class adv) yield to it, and it yields while a higher class waits (nothing outranks release)
|
||||
pool_class() { case "$BR_LABEL" in *"v5 gate"*|*"v5 kit"*) echo "v5/1" ;; *) echo "release/0" ;; esac; }
|
||||
pool_take() { # <want> <min>: lease up to <want> free pool cores, at least <min>, waiting up to 2 h; sets pool_cores/pool_fds
|
||||
local want="$1" min="$2" t0 c fd taken
|
||||
local want="$1" min="$2" t0 c fd taken cls rank higher
|
||||
cls=$(pool_class); rank=${cls#*/}
|
||||
t0=$(date +%s)
|
||||
while :; do
|
||||
taken=0; pool_fds=(); pool_cores=()
|
||||
for ((c = ${BR_POOL_RESERVE:-8}; c < ncpu && taken < want; c++)); do
|
||||
exec {fd}>>"$SLOTS_DIR/core-$c"
|
||||
if flock -n "$fd"; then pool_fds+=("$fd"); pool_cores+=("$c"); taken=$((taken + 1)); else exec {fd}>&-; fi
|
||||
done
|
||||
if [ "$taken" -ge "$min" ]; then return 0; fi
|
||||
for fd in "${pool_fds[@]}"; do exec {fd}>&-; done; pool_fds=(); pool_cores=()
|
||||
[ -f "$waitfile" ] || { echo "build-remote: the bounded pool has $taken free core(s) (want $want, at least $min): waiting for the pool" >&2; holder_line "$(( $(date +%s) - BR_T0 ))" > "$waitfile"; }
|
||||
higher=$(cat "$SLOTS_DIR"/wait-* 2>/dev/null | grep -v "^pid $BR_PID " | sed -n 's/.* class [a-z0-9]*\/\([0-9]\):.*/\1/p' | awk -v r="$rank" '$1 < r' | head -1)
|
||||
if [ -z "$higher" ]; then
|
||||
for ((c = ${BR_POOL_RESERVE:-8}; c < ncpu && taken < want; c++)); do
|
||||
exec {fd}>>"$SLOTS_DIR/core-$c"
|
||||
if flock -n "$fd"; then pool_fds+=("$fd"); pool_cores+=("$c"); taken=$((taken + 1)); else exec {fd}>&-; fi
|
||||
done
|
||||
if [ "$taken" -ge "$min" ]; then return 0; fi
|
||||
for fd in "${pool_fds[@]}"; do exec {fd}>&-; done; pool_fds=(); pool_cores=()
|
||||
fi
|
||||
[ -f "$waitfile" ] || { echo "build-remote: the bounded pool has $taken free core(s) (want $want, at least $min, class ${cls%/*}): waiting for the pool" >&2; }
|
||||
printf '%s class %s: pool\n' "$(holder_line "$(( $(date +%s) - BR_T0 ))")" "$cls" > "$waitfile"
|
||||
[ $(( $(date +%s) - t0 )) -lt 7200 ] || give_up "the bounded pool"
|
||||
sleep 10
|
||||
done
|
||||
|
|
|
|||
Loading…
Reference in a new issue