Skip to content

Commit 2a72142

Browse files
committed
wip: freebsd CI
1 parent d432cbc commit 2a72142

4 files changed

Lines changed: 747 additions & 427 deletions

File tree

.docker/build-freebsd.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/sh
2+
set -eux
3+
4+
export HOME=/root
5+
export PATH=/usr/local/bin:/usr/local/sbin:/bin:/usr/bin:/sbin:/usr/sbin
6+
export CCACHE_DIR=/ccache
7+
export RUNNER_TEMP=/runner_temp
8+
export RUNNER_WORKSPACE=/work
9+
export GITHUB_RUN_NUMBER="${GITHUB_RUN_NUMBER:-0}"
10+
export BUILD_MODE="${BUILD_MODE:-Release}"
11+
export CMAKE_ARGS="${CMAKE_ARGS:-}"
12+
13+
# Source tarball path (NFS is nullfs-mounted from host)
14+
SRC_TARBALL="/mnt/opensource/artifacts/dwarfs/cache/dwarfs-source-${GITHUB_RUN_NUMBER}.tar.zst"
15+
test -r "${SRC_TARBALL}"
16+
17+
cd "$HOME"
18+
rm -rf dwarfs dwarfs-*
19+
tar xf "${SRC_TARBALL}"
20+
ln -sfn dwarfs-* dwarfs
21+
22+
rm -rf "${RUNNER_TEMP}/build"
23+
cmake --fresh \
24+
-B"${RUNNER_TEMP}/build" \
25+
-S"${HOME}/dwarfs" \
26+
-DCMAKE_BUILD_TYPE="${BUILD_MODE}" \
27+
-DWITH_TESTS=ON \
28+
-DWITH_PXATTR=ON \
29+
${CMAKE_ARGS}
30+
31+
cmake --build "${RUNNER_TEMP}/build"
32+
ctest --test-dir "${RUNNER_TEMP}/build" --output-on-failure -j"$(sysctl -n hw.ncpu)"
33+
cmake --build "${RUNNER_TEMP}/build" --target realclean
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/bin/sh
2+
3+
set -eux
4+
5+
# ----------------------------
6+
# Config / Inputs (env-driven)
7+
# ----------------------------
8+
FREEBSD_VER_TAG="${FREEBSD_VERSION:-14_3}"
9+
SNAP_LABEL="${FREEBSD_SNAPSHOT:-base-20250809}"
10+
ZPOOL="${ZPOOL:-zroot}"
11+
JAILS_DS="${JAILS_DS:-${ZPOOL}/z/jails}"
12+
JAILS_MP="${JAILS_MP:-/z/jails}"
13+
14+
GITHUB_RUN_ID="${GITHUB_RUN_ID:-localrun}"
15+
GITHUB_RUN_ATTEMPT="${GITHUB_RUN_ATTEMPT:-1}"
16+
17+
BUILD_MODE="${BUILD_MODE:-Release}"
18+
CMAKE_ARGS="${CMAKE_ARGS:-}"
19+
20+
BASE_DS="${JAILS_DS}/${FREEBSD_VER_TAG}"
21+
RUN_DS="${JAILS_DS}/ci-${FREEBSD_VER_TAG}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
22+
RUN_MP="${JAILS_MP}/ci-${FREEBSD_VER_TAG}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
23+
JAIL="ci_${FREEBSD_VER_TAG}_${GITHUB_RUN_ID}_${GITHUB_RUN_ATTEMPT}"
24+
25+
# ----------------------------
26+
# Helpers
27+
# ----------------------------
28+
log() { printf '%s %s\n' "[freebsd-jail]" "$*" >&2; }
29+
30+
# Stop a jail if it's running; kill any lingering processes by JID if needed
31+
stop_stale_jail() {
32+
jname="$1"
33+
if jls -j "$jname" >/dev/null 2>&1; then
34+
log "Stopping stale jail: $jname"
35+
if ! sudo jail -r "$jname" 2>/dev/null; then
36+
JID="$(jls -j "$jname" jid -h 2>/dev/null || true)"
37+
if [ -n "$JID" ]; then
38+
sudo killall -j "$JID" -TERM 2>/dev/null || true
39+
sleep 1
40+
sudo killall -j "$JID" -KILL 2>/dev/null || true
41+
fi
42+
sudo jail -r "$jname" 2>/dev/null || true
43+
fi
44+
fi
45+
}
46+
47+
# Unmount everything under a mountpoint (deepest-first)
48+
umount_tree() {
49+
rootmp="$1"
50+
# List mounted paths under $rootmp, deepest-first
51+
# shellcheck disable=SC2016
52+
for m in $(mount | awk -v p="$rootmp" '$3 ~ ("^"p) { print length, $3 }' | sort -rn | cut -d" " -f2-); do
53+
sudo umount -f "$m" 2>/dev/null || true
54+
done
55+
}
56+
57+
# Destroy a cloned dataset (after umount)
58+
destroy_dataset() {
59+
ds="$1"
60+
if sudo zfs list -H "$ds" >/dev/null 2>&1; then
61+
mp="$(sudo zfs get -H -o value mountpoint "$ds" 2>/dev/null || echo "")"
62+
if [ -n "$mp" ] && [ "$mp" != "-" ]; then
63+
umount_tree "$mp"
64+
fi
65+
log "Destroying dataset: $ds"
66+
sudo zfs destroy -r "$ds"
67+
fi
68+
}
69+
70+
# Remove stale jail + dataset that match our run IDs
71+
cleanup_stale_before_start() {
72+
stop_stale_jail "$JAIL"
73+
destroy_dataset "$RUN_DS"
74+
}
75+
76+
# Full cleanup for traps: stop jail, unmount, destroy dataset
77+
cleanup_on_exit() {
78+
# Be idempotent; ignore errors
79+
stop_stale_jail "$JAIL"
80+
destroy_dataset "$RUN_DS"
81+
}
82+
83+
# Generate an env file inside jail that exports safe GitHub env vars
84+
write_gha_env() {
85+
out="$1"
86+
# Allow common CI vars; deny obvious secrets
87+
# Adjust allow/deny as needed for your org.
88+
ALLOW='GITHUB_* RUNNER_* CI ACTIONS_* INPUT_* MATRIX_* BUILD_MODE CMAKE_ARGS'
89+
DENY='*TOKEN* *SECRET* *PASSWORD* *PASS* *KEY* *CERT* AWS_* AZURE_* GCP_*'
90+
91+
# Function to test name against allow/deny (POSIX sh compatible inline)
92+
is_allowed() {
93+
name="$1"
94+
case "$name" in
95+
GITHUB_*|RUNNER_*|CI|ACTIONS_*|INPUT_*|MATRIX_*|BUILD_MODE|CMAKE_ARGS) : ;;
96+
*) return 1 ;;
97+
esac
98+
case "$name" in
99+
*TOKEN*|*SECRET*|*PASSWORD*|*PASS*|*KEY*|*CERT*|AWS_*|AZURE_*|GCP_* ) return 1 ;;
100+
esac
101+
return 0
102+
}
103+
104+
tmp="$(mktemp)"
105+
{
106+
echo "# Autogenerated; sourced by /root/build.sh"
107+
# Ensure our two common knobs are present even if not in env
108+
printf "export BUILD_MODE='%s'\n" "$BUILD_MODE"
109+
# Escape single quotes in CMAKE_ARGS
110+
esc_ca=$(printf "%s" "$CMAKE_ARGS" | sed "s/'/'\"'\"'/g")
111+
printf "export CMAKE_ARGS='%s'\n" "$esc_ca"
112+
113+
env | while IFS='=' read -r name value; do
114+
if is_allowed "$name"; then
115+
esc=$(printf "%s" "$value" | sed "s/'/'\"'\"'/g")
116+
printf "export %s='%s'\n" "$name" "$esc"
117+
fi
118+
done
119+
} > "$tmp"
120+
sudo mkdir -p "$(dirname "$out")"
121+
sudo cp "$tmp" "$out"
122+
sudo chmod 0644 "$out"
123+
rm -f "$tmp"
124+
}
125+
126+
# ----------------------------
127+
# Trap: ensure cleanup on any exit
128+
# ----------------------------
129+
trap cleanup_on_exit EXIT INT TERM HUP
130+
131+
# ----------------------------
132+
# Prep: nuke stale, then clone snapshot
133+
# ----------------------------
134+
cleanup_stale_before_start
135+
136+
log "Cloning ${BASE_DS}@${SNAP_LABEL} -> ${RUN_DS}"
137+
sudo zfs clone "${BASE_DS}@${SNAP_LABEL}" "${RUN_DS}"
138+
139+
# ----------------------------
140+
# Bootstrapping jail root: DNS + mounts
141+
# ----------------------------
142+
# DNS for networking inside jail
143+
sudo mkdir -p "${RUN_MP}/etc"
144+
sudo cp /etc/resolv.conf "${RUN_MP}/etc/resolv.conf"
145+
[ -f /etc/hosts ] && sudo cp /etc/hosts "${RUN_MP}/etc/hosts"
146+
[ -f /etc/nsswitch.conf ] && sudo cp /etc/nsswitch.conf "${RUN_MP}/etc/nsswitch.conf"
147+
148+
# Core mounts
149+
sudo mount -t devfs devfs "${RUN_MP}/dev"
150+
sudo mount -t fdescfs fdesc "${RUN_MP}/dev/fd"
151+
sudo mount -t procfs proc "${RUN_MP}/proc"
152+
sudo mount -t tmpfs tmpfs "${RUN_MP}/tmp"
153+
154+
# Workspace / temp / ccache / NFS from host
155+
RUNNER_WORKSPACE="${RUNNER_WORKSPACE:-$PWD}"
156+
RUNNER_TEMP="${RUNNER_TEMP:-/tmp/runner_temp}"
157+
mkdir -p "${RUNNER_TEMP}" "${HOME}/.ccache"
158+
159+
sudo mkdir -p "${RUN_MP}/work" "${RUN_MP}/runner_temp" "${RUN_MP}/ccache" "${RUN_MP}/mnt/opensource"
160+
sudo mount -t nullfs -o rw "${RUNNER_WORKSPACE}" "${RUN_MP}/work"
161+
sudo mount -t nullfs -o rw "${RUNNER_TEMP}" "${RUN_MP}/runner_temp"
162+
sudo mount -t nullfs -o rw "${HOME}/github-ccache" "${RUN_MP}/ccache"
163+
sudo mount -t nullfs -o rw "/mnt/opensource" "${RUN_MP}/mnt/opensource"
164+
165+
# ----------------------------
166+
# Start jail (FUSE enabled)
167+
# ----------------------------
168+
log "Starting jail: ${JAIL}"
169+
sudo jail -c name="${JAIL}" host.hostname="${JAIL}" \
170+
path="${RUN_MP}" persist \
171+
mount.devfs devfs_ruleset=5 enforce_statfs=1 \
172+
allow.mount allow.mount.fusefs \
173+
allow.raw_sockets \
174+
ip4=inherit ip6=inherit
175+
176+
# ----------------------------
177+
# Inject env + build script, then run it
178+
# ----------------------------
179+
write_gha_env "${RUN_MP}/root/gha_env.sh"
180+
181+
sudo cp ".docker/build-freebsd.sh" "${RUN_MP}/root/build.sh"
182+
sudo chmod +x "${RUN_MP}/root/build.sh"
183+
184+
# Run inside the jail with env sourced
185+
log "Executing build inside jail…"
186+
sudo jexec "${JAIL}" /bin/sh -lc '. /root/gha_env.sh; exec /root/build.sh'
187+
188+
log "Build finished successfully."
189+
# Cleanup happens automatically via trap on EXIT.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/bin/sh
2+
set -euo pipefail
3+
4+
# ===== Config =====
5+
FREEBSD_REL="${FREEBSD_REL:-14.3-RELEASE}"
6+
FREEBSD_VER_TAG="${FREEBSD_VER_TAG:-14_3}"
7+
8+
SNAP_LABEL="${SNAP_LABEL:-base-$(date +%Y%m%d)}"
9+
10+
ZPOOL="${ZPOOL:-zroot}"
11+
JAILS_DS="${JAILS_DS:-${ZPOOL}/z/jails}"
12+
JAILS_MP="${JAILS_MP:-/z/jails}"
13+
14+
PKG_REPO_URL='pkg+http://pkg.FreeBSD.org/${ABI}/latest'
15+
16+
PKGS="boost-all brotli ccache cmake date double-conversion flac fuse fusefs-libs fusefs-libs3 glog gnulibiberty libarchive liblz4 mold ninja nlohmann-json openssl parallel-hashmap pkgconf range-v3 utf8cpp xxhash zstd ca_root_nss git"
17+
18+
# ===== Layout =====
19+
sudo zfs list -H "${ZPOOL}" >/dev/null 2>&1 || { echo "No pool ${ZPOOL}"; exit 1; }
20+
sudo zfs create -o mountpoint=/z "${ZPOOL}/z" >/dev/null 2>&1 || true
21+
sudo zfs create -o mountpoint=/z/jails "${JAILS_DS}" >/dev/null 2>&1 || true
22+
23+
BASE_DS="${JAILS_DS}/${FREEBSD_VER_TAG}"
24+
BASE_MP="${JAILS_MP}/${FREEBSD_VER_TAG}"
25+
26+
if ! sudo zfs list -H "${BASE_DS}" >/dev/null 2>&1; then
27+
sudo zfs create -o mountpoint="${BASE_MP}" "${BASE_DS}"
28+
fi
29+
30+
# ===== Fetch & extract base.txz =====
31+
if [ ! -f "${BASE_MP}/.seeded" ]; then
32+
TMPDIR="$(mktemp -d)"
33+
trap 'rm -rf "$TMPDIR"' EXIT
34+
fetch -o "${TMPDIR}/base.txz" "https://download.freebsd.org/releases/amd64/${FREEBSD_REL}/base.txz"
35+
sudo tar -xpf "${TMPDIR}/base.txz" -C "${BASE_MP}"
36+
sudo touch "${BASE_MP}/.seeded"
37+
fi
38+
39+
# ===== Provide networking config to the chroot =====
40+
sudo mkdir -p "${BASE_MP}/etc"
41+
# copy DNS + name service config from host so pkg can resolve names
42+
sudo cp /etc/resolv.conf "${BASE_MP}/etc/resolv.conf"
43+
[ -f /etc/hosts ] && sudo cp /etc/hosts "${BASE_MP}/etc/hosts"
44+
[ -f /etc/nsswitch.conf ] && sudo cp /etc/nsswitch.conf "${BASE_MP}/etc/nsswitch.conf"
45+
46+
# ===== Preinstall deps inside the tree =====
47+
sudo mount -t devfs devfs "${BASE_MP}/dev"
48+
sudo mount -t fdescfs fdesc "${BASE_MP}/dev/fd"
49+
sudo mount -t procfs proc "${BASE_MP}/proc"
50+
51+
sudo chroot "${BASE_MP}" /bin/sh -lc "
52+
set -e
53+
env ASSUME_ALWAYS_YES=yes pkg bootstrap -f
54+
mkdir -p /usr/local/etc/pkg/repos
55+
echo 'FreeBSD: { url: \"${PKG_REPO_URL}\" }' > /usr/local/etc/pkg/repos/FreeBSD.conf
56+
pkg update
57+
pkg install -y ${PKGS}
58+
mkdir -p /root/.ccache
59+
"
60+
61+
sudo umount -f "${BASE_MP}/proc" || true
62+
sudo umount -f "${BASE_MP}/dev/fd" || true
63+
sudo umount -f "${BASE_MP}/dev" || true
64+
65+
# ===== Snapshot =====
66+
sudo zfs snapshot "${BASE_DS}@${SNAP_LABEL}"
67+
echo "Snapshot created: ${BASE_DS}@${SNAP_LABEL}"

0 commit comments

Comments
 (0)