This repository has no description
4.1 kB
101 lines
1#!/usr/bin/env bash
2# Mounts a lazy /nix/store for building a machine (the machine jobs of
3# ci.yml): every store path the build would substitute from cache.nixos.org
4# or cache.lassul.us is registered as valid from its narinfo and served by
5# lazy-store (tools/lazy-store), which downloads a path's NAR only when a
6# file in it is opened first. What nix builds, and what neither cache has,
7# is built or substituted (also from hestia) as usual; writes go to the
8# real store dir below the mount.
9#
10# `closure FETCH` collects the closure of the paths in FETCH, those the
11# build would substitute (from the eval job's dry-run, .github/ci-shared.sh),
12# from the caches' narinfos; it needs no drvs and can run while they are
13# fetched. `mount` mounts it on /nix/store and registers the paths, after
14# `closure` and once the drvs are in the store.
15#
16# Needs sudo, /dev/fuse and LAZY_STORE, the lazy-store package's out path
17# (substitutable). If anything fails before the paths are registered, the
18# mount is undone and the build substitutes eagerly: this script always
19# exits 0. The FUSE log ends up in $RUNNER_TEMP/lazy-store/fuse.log.
20# Usage: lazy-store.sh closure FETCH
21# lazy-store.sh mount
22set -euo pipefail
23L=$RUNNER_TEMP/lazy-store
24mkdir -p "$L"
25
26fallback() {
27 set +e
28 echo "::error::lazy store: $1; the build substitutes eagerly instead"
29 rm -f "$L/ready"
30 if [ -s "$L/fuse.log" ]; then
31 tail -n 50 "$L/fuse.log"
32 fi
33 if mountpoint -q /nix/store; then
34 sudo umount /nix/store || sudo umount -l /nix/store
35 fi
36 if mountpoint -q /lazy/nix; then
37 sudo umount -l /lazy/nix
38 fi
39 exit 0
40}
41trap 'fallback "line $LINENO failed"' ERR
42
43lazy=$LAZY_STORE/bin/lazy-store
44
45if [ "$1" = closure ]; then
46 if [ ! -s "$2" ]; then
47 echo "lazy store: nothing to substitute"
48 exit 0
49 fi
50 nix-store --realise "$LAZY_STORE" >/dev/null || fallback "cannot get $LAZY_STORE"
51 "$lazy" closure "$L" <"$2" >/dev/null || fallback "closure failed"
52 jq -r '"lazy store: \(.paths) of the \(.roots) paths to substitute and their closure (\(.file_size / 1048576 | floor) MiB to download eagerly); \(.missing | length) not in the caches, \(.incomplete) referring to those"' \
53 "$L/closure.json"
54 if [ "$(jq length "$L/paths.json")" != 0 ]; then
55 touch "$L/ready"
56 fi
57 exit 0
58fi
59
60if [ ! -e "$L/ready" ]; then
61 exit 0
62fi
63n=$(jq length "$L/paths.json")
64nixbin=$(dirname "$(readlink -f "$(command -v nix-store)")")
65
66sudo modprobe fuse || true
67# The upper layer is the real store dir, reached through a private bind
68# mount of /nix, so that the mount on /nix/store doesn't show up there.
69sudo mkdir -p /lazy/nix
70sudo mount --bind /nix /lazy/nix || fallback "bind mount of /nix failed"
71sudo mount --make-private /lazy/nix || fallback "making /lazy/nix private failed"
72# shellcheck disable=SC2024 # the log is ours, only the mount needs root
73sudo "$lazy" mount "$L" /lazy/nix/store /nix/store >"$L/fuse.log" 2>&1 &
74fuse=$!
75# sudo runs as root (no kill -0) and stays a zombie until waited for
76fuse_alive() {
77 local s
78 s=$(ps -o stat= -p "$fuse") && [[ $s != Z* ]]
79}
80# it fetches all .ls listings before mounting
81until mountpoint -q /nix/store; do
82 fuse_alive || fallback "lazy-store exited before mounting /nix/store"
83 sleep 1
84done
85grep -m1 '^init: ' "$L/fuse.log" || true
86
87some=$(jq -r 'keys[0]' "$L/paths.json")
88[ -e "/nix/store/$some" ] || fallback "/nix/store/$some is not served"
89# shellcheck disable=SC2024 # db.dump is ours, only nix-store needs root
90sudo "$nixbin/nix-store" --load-db <"$L/db.dump" || fallback "registering the paths failed"
91# registered: the mount has to stay
92trap - ERR
93set +e
94echo "lazy store: mounted on /nix/store, $n paths registered"
95# niks3 and hestia leave out what cache.nixos.org signed by the signatures
96# in nix's database; without them they would upload (and so download)
97# those paths
98jq -r 'keys[] | "/nix/store/" + .' "$L/paths.json" |
99 sudo "$nixbin/nix" --extra-experimental-features nix-command \
100 store copy-sigs -s "file://$L/narinfo" --stdin ||
101 echo "::warning::lazy store: copying the signatures failed, uploads may download paths of cache.nixos.org"