gioser

tawasuyu/brahman

Rust 483TOML 191Markdown 50JSON 176777 Definitions

⎇ c56ef2554615e03b5fcdfb80c0e5e5c826a94f00 scripts/build-arje-initrd.sh Shell · 237 lines · 9.0 KB History raw

feat(arje): incluye CLIs admin en el initrd (brahman-status/busctl/brainctl) e4b1d41b6 · sergio ·

1#!/usr/bin/env bash
2# build-arje-initrd.sh — empaqueta ente-zero + shims compat + Tarjeta Semilla
3# en un initramfs CPIO+gzip listo para arrancar bajo QEMU o como /init real.
4#
5# Toolchain: musl-static por default. ente-zero es PID 1; cualquier
6# dependencia dinámica (libgcc_s, libc.so.6, ld-linux) que no esté en el
7# initramfs produce kernel panic. Compilar contra musl elimina el problema
8# completamente — un solo ELF estático.
9#
10# Layout del initrd resultante:
11#   /init                         → wrapper sh que exec /sbin/ente-zero
12#   /sbin/ente-zero               → PID 1 (musl-static)
13#   /usr/sbin/ente-*-compat       → shims systemd (musl-static)
14#   /usr/sbin/ente-echo, ente-policy-provider
15#   /ente/seed.card.json          → Tarjeta Semilla
16#   /bin/{sh,ls,cat,...}          → busybox-static (recomendado)
17#   /dev, /proc, /sys, /run       → puntos de montaje (ente-zero los monta)
18#
19# Uso:
20#   scripts/build-arje-initrd.sh [seed.card.json] [out.cpio.gz]
21#
22#   seed     default: seeds/arje-prod.card.json
23#   out      default: out/arje.initrd.cpio.gz
24#
25# Env:
26#   ARJE_TARGET   triple de cargo (default: x86_64-unknown-linux-musl).
27#                 Para glibc dinámica usar x86_64-unknown-linux-gnu — en
28#                 ese caso hay que vendorear libgcc_s.so.1 + libc.so.6 +
29#                 ld-linux-x86-64.so.2 manualmente o el kernel paniquea.
30#   BUSYBOX_BIN   path a un busybox-static. Default: busca `busybox` en PATH.
31#   EXTRA_BINS    binarios extra a copiar (deben ser estáticos), space-separated.
32#
33# Requisitos del host:
34#   - rust toolchain con el target musl instalado:
35#       rustup target add x86_64-unknown-linux-musl
36#   - musl-gcc para algunos crates con build.rs C (sled, etc.):
37#       Debian/Ubuntu:  apt install musl-tools
38#       Alpine:         apk add musl-dev gcc
39#       Arch:           pacman -S musl
40#   - cpio, gzip.
41#   - busybox-static (recomendado, opcional):
42#       Debian/Ubuntu:  apt install busybox-static
43#       Alpine:         (busybox viene built-in)
44
45set -euo pipefail
46
47SEED="${1:-seeds/arje-prod.card.json}"
48OUT="${2:-out/arje.initrd.cpio.gz}"
49TARGET="${ARJE_TARGET:-x86_64-unknown-linux-musl}"
50BUSYBOX_BIN="${BUSYBOX_BIN:-$(command -v busybox 2>/dev/null || true)}"
51EXTRA_BINS="${EXTRA_BINS:-}"
52
53SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
54REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
55cd "$REPO_DIR"
56
57if [ ! -f "$SEED" ]; then
58  echo "[build-initrd] seed no encontrada: $SEED" >&2
59  exit 2
60fi
61
62# Chequeo del target: si es musl, debe estar instalado. Mensaje accionable
63# cuando falta — la causa #1 de fracaso al primer intento.
64if [[ "$TARGET" == *-musl ]]; then
65  RUSTLIB="$(rustc --print sysroot 2>/dev/null)/lib/rustlib/$TARGET"
66  if [ ! -d "$RUSTLIB" ]; then
67    cat >&2 <<EOF
68[build-initrd] target musl no instalado: $TARGET
69
70Instalalo con uno de:
71
72  # Si tenés rustup:
73  rustup target add $TARGET
74
75  # Si tu rust viene del paquete del sistema (Debian/Ubuntu):
76  apt install rustup && rustup default stable && rustup target add $TARGET
77
78Y asegurate de tener musl-gcc para los crates con build.rs C:
79
80  apt install musl-tools          # Debian/Ubuntu
81  apk add musl-dev gcc            # Alpine
82  pacman -S musl                  # Arch
83
84Si querés saltar musl (NO recomendado para PID 1, te dará kernel panic
85por libgcc_s.so.1 faltante a menos que la vendorees):
86
87  ARJE_TARGET=x86_64-unknown-linux-gnu scripts/build-arje-initrd.sh
88EOF
89    exit 5
90  fi
91fi
92
93# 1. Build release de ente-zero y todos los compat shims con el target elegido.
94echo "[build-initrd] cargo build --release --target $TARGET de ente-zero + shims"
95cargo build --release --target "$TARGET" \
96  -p ente-zero \
97  -p ente-echo \
98  -p ente-logind-compat \
99  -p ente-hostnamed-compat \
100  -p ente-timedated-compat \
101  -p ente-localed-compat \
102  -p ente-journald-compat \
103  -p ente-resolved-compat \
104  -p ente-polkit-compat \
105  -p ente-machined-compat \
106  -p ente-systemd1-compat \
107  -p ente-notify-compat \
108  -p ente-timer-compat \
109  -p ente-tmpfiles-compat \
110  -p ente-binfmt-compat \
111  -p ente-policy-provider
112
113# 1b. Build de las CLI de administración. Son `[[example]]` de sus crates
114#     respectivos — un solo binario cada una, sin estado propio.
115echo "[build-initrd] cargo build --release --target $TARGET de CLIs admin"
116cargo build --release --target "$TARGET" \
117  --example brahman-status -p brahman-admin \
118  --example busctl         -p ente-bus \
119  --example brainctl       -p ente-brain
120
121BIN_DIR="target/$TARGET/release"
122EX_DIR="target/$TARGET/release/examples"
123
124# 2. Validar la seed. validate.sh corre el binario del host (release plain),
125#    sólo verifica el schema — independiente del target.
126if ! seeds/validate.sh "$SEED" >/dev/null 2>&1; then
127  echo "[build-initrd] seed inválida: $SEED" >&2
128  exit 3
129fi
130
131# 3. Sanity check: si compilamos musl, los ELF deben ser ESTÁTICOS.
132#    Si quedó alguno con interpreter dinámico, el kernel paniquea.
133if [[ "$TARGET" == *-musl ]] && command -v file >/dev/null 2>&1; then
134  bad=0
135  for b in "$BIN_DIR/ente-zero" "$BIN_DIR/ente-echo"; do
136    [ -f "$b" ] || continue
137    if file "$b" | grep -q "dynamically linked"; then
138      echo "[build-initrd] WARN: $b quedó DYNAMIC (esperábamos static):" >&2
139      file "$b" >&2
140      bad=$((bad + 1))
141    fi
142  done
143  if [ "$bad" -gt 0 ]; then
144    echo "[build-initrd] abortando — un binario PID-1 dinámico paniquea el kernel" >&2
145    exit 6
146  fi
147fi
148
149# 4. Stage root del initrd.
150STAGE="$(mktemp -d -t arje-initrd.XXXXXX)"
151trap 'rm -rf "$STAGE"' EXIT
152mkdir -p "$STAGE"/{bin,sbin,usr/bin,usr/sbin,etc,ente,proc,sys,dev,run,tmp,sys/fs/cgroup}
153
154# 5. Copiar binarios arje.
155install -m 0755 "$BIN_DIR/ente-zero" "$STAGE/sbin/ente-zero"
156for b in ente-echo ente-policy-provider \
157         ente-logind-compat ente-hostnamed-compat ente-timedated-compat \
158         ente-localed-compat ente-journald-compat ente-resolved-compat \
159         ente-polkit-compat ente-machined-compat ente-systemd1-compat \
160         ente-notify-compat ente-timer-compat ente-tmpfiles-compat \
161         ente-binfmt-compat; do
162  install -m 0755 "$BIN_DIR/$b" "$STAGE/usr/sbin/$b"
163done
164
165# 5b. CLIs de administración → /usr/bin (no /usr/sbin: no son services).
166for e in brahman-status busctl brainctl; do
167  install -m 0755 "$EX_DIR/$e" "$STAGE/usr/bin/$e"
168done
169
170# 6. Userspace mínimo. Con binarios musl-static no necesitamos vendorear
171#    libc/ld-linux. Las dos rutas:
172#    (a) busybox-static apuntado por $BUSYBOX_BIN → 1 binario, todo simlink.
173#    (b) sin busybox → copiar /bin/sh + sus deps via ldd. Sólo seguro si el
174#        /bin/sh del host es estático (ej. dash en algunos distros NO lo es).
175if [ -n "$BUSYBOX_BIN" ] && [ -x "$BUSYBOX_BIN" ]; then
176  echo "[build-initrd] usando busybox-static: $BUSYBOX_BIN"
177  # Validar que el busybox es realmente estático (causa frecuente de panic).
178  if command -v file >/dev/null 2>&1 && \
179     file "$BUSYBOX_BIN" | grep -q "dynamically linked"; then
180    echo "[build-initrd] ERROR: $BUSYBOX_BIN es dinámico — necesitás busybox-static" >&2
181    echo "  apt install busybox-static  # Debian/Ubuntu" >&2
182    exit 7
183  fi
184  install -m 0755 "$BUSYBOX_BIN" "$STAGE/bin/busybox"
185  ( cd "$STAGE/bin" && for app in sh ls cat mount umount mkdir cp mv \
186       echo grep sed awk ps kill sleep insmod modprobe poweroff reboot \
187       sysctl dmesg ip ifconfig; do
188       ln -sf busybox "$app"
189    done )
190else
191  echo "[build-initrd] WARN: sin busybox-static — vendoreando /bin/sh + libs via ldd"
192  echo "  Esto es FRÁGIL. Instalá busybox-static y reintentá:"
193  echo "    apt install busybox-static    # Debian/Ubuntu"
194  copy_lib() {
195    local lib="$1"
196    [ -f "$lib" ] || return 0
197    local dest="$STAGE${lib}"
198    mkdir -p "$(dirname "$dest")"
199    cp -L "$lib" "$dest"
200  }
201  for b in /bin/sh /bin/ls /bin/cat /bin/mount /bin/umount /bin/mkdir; do
202    [ -x "$b" ] || continue
203    cp -L "$b" "$STAGE${b}"
204    while read -r lib; do copy_lib "$lib"; done < <(
205      ldd "$b" 2>/dev/null | awk '{ for (i=1;i<=NF;i++) if ($i ~ /^\//) print $i }'
206    )
207  done
208fi
209
210# 7. Tarjeta Semilla. Path canónico en prod: /ente/seed.card.json
211install -m 0644 "$SEED" "$STAGE/ente/seed.card.json"
212
213# 8. /init wrapper. El kernel pasa control a /init; nosotros invocamos
214#    ente-zero como PID 1 real con su env mínimo.
215cat > "$STAGE/init" <<'EOF'
216#!/bin/sh
217# arje /init — kernel → este script → ente-zero (PID 1 lo hereda via exec)
218export PATH=/usr/sbin:/usr/bin:/sbin:/bin
219export RUST_LOG="${RUST_LOG:-ente_zero=info,brahman_handshake=info,info}"
220# ente-zero monta /proc /sys /dev /sys/fs/cgroup él mismo.
221exec /sbin/ente-zero
222EOF
223chmod 0755 "$STAGE/init"
224
225# 9. Binarios extra a vendorear (deben ser estáticos).
226if [ -n "$EXTRA_BINS" ]; then
227  for b in $EXTRA_BINS; do
228    [ -x "$b" ] || { echo "[build-initrd] EXTRA_BINS: $b no existe"; exit 4; }
229    install -m 0755 "$b" "$STAGE/usr/sbin/$(basename "$b")"
230  done
231fi
232
233# 10. Empaquetar CPIO + gzip. Formato newc (estándar para Linux initramfs).
234mkdir -p "$(dirname "$OUT")"
235( cd "$STAGE" && find . -print0 | cpio -o -H newc --null --quiet ) | gzip -9 > "$OUT"
236echo "[build-initrd] generado: $OUT ($(du -h "$OUT" | cut -f1))"
237echo "[build-initrd] target:    $TARGET"