Skip to main content

max / alloy

3.7 KB · 86 lines History Blame Raw
1 #!/bin/sh
2 # alloy-layer-repos — fence the first boot's layering to the carried repo.
3 #
4 # alloy-layer-components.service installs the console and terminal from
5 # /usr/share/alloy/rpm, a file:// repo that ships on the medium precisely so an
6 # offline install produces a working machine (docs/STACK.md, Hotfixes). It did
7 # not. rpm-ostree refreshes metadata for every ENABLED repo before it
8 # depsolves, and the image leaves Fedora's own four enabled, so a first boot
9 # with no name resolution failed like this and left the machine with no
10 # console:
11 #
12 # error: Updating rpm-md repo 'fedora-cisco-openh264': Cannot prepare
13 # internal mirrorlist: Curl error (6): Could not resolve hostname for
14 # https://mirrors.fedoraproject.org/metalink?repo=fedora-cisco-openh264-43
15 #
16 # Measured 2026-08-25 on an installed server-profile machine in qemu, and
17 # reproduced by hand afterwards, so it is not a boot-ordering race.
18 #
19 # WHY THE FLAGS ARE NOT THE ANSWER. Both levers rpm-ostree offers are refused
20 # outside a container build, which docs/STACK.md already records for the first
21 # of them:
22 #
23 # # rpm-ostree install --enablerepo=alloy-local alloy
24 # error: --enablerepo currently only works in a container build
25 # # rpm-ostree install --disablerepo="*" alloy
26 # error: --disablerepo currently only works in a container build
27 #
28 # `--cache-only` is not the answer either: it reads cached metadata and
29 # refreshes none, so on a machine that has never refreshed anything it answers
30 # `error: Packages not found: alloy` with the packages sitting on the disk.
31 #
32 # So the repo set the daemon reads is the only lever, and this moves it for the
33 # length of one transaction. `off` disables everything but the carried repo;
34 # `on` puts /etc back. Both are idempotent.
35 #
36 # WHY `on` COPIES FROM /usr/etc RATHER THAN FROM A BACKUP. /usr/etc is the
37 # image's own /etc, so it is authoritative and it is always there. A backup in
38 # /run is not: a machine that loses power between `off` and `on` comes back
39 # with the repos disabled and the backup gone. The unit runs `on` before `off`
40 # for that reason as well as after, so an interrupted first boot heals itself
41 # on the next one rather than leaving a machine whose repos are quietly off.
42 #
43 # WHAT IT DOES NOT LEAK. The deployment the transaction stages does not inherit
44 # the disabled files: measured by rebooting into it, where the enabled set is
45 # alloy-local plus Fedora's four, as on any other machine. ostree's /etc merge
46 # reads the state /etc is left in, and `on` runs before the reboot.
47 #
48 # NOT A USER-FACING REPO POLICY. Which repos an installed Alloy leaves enabled
49 # is unchanged by this, deliberately: `alloy pkg` layers Fedora packages, and a
50 # machine that ships them disabled is a machine where that quietly finds
51 # nothing. The fence exists for one transaction on one boot.
52 #
53 # Deliberately dependency-free, and on the boot path in front of the only thing
54 # that gives the machine a console: sh, sed, cp, a glob. Same argument as
55 # alloy-layer-notice's.
56
57 set -eu
58
59 REPOS=/etc/yum.repos.d
60 SHIPPED=/usr/etc/yum.repos.d
61 CARRIED=alloy-local.repo
62
63 case "${1:-}" in
64 off)
65 [ -d "$REPOS" ] || exit 0
66 for repo in "$REPOS"/*.repo; do
67 [ -e "$repo" ] || continue
68 [ "${repo##*/}" != "$CARRIED" ] || continue
69 sed -i 's/^enabled[[:space:]]*=[[:space:]]*1$/enabled=0/' "$repo"
70 done
71 ;;
72 on)
73 # A missing /usr/etc means this is not an ostree deployment at all,
74 # which is a dev box running the script by hand. Nothing to put back.
75 [ -d "$SHIPPED" ] || exit 0
76 for repo in "$SHIPPED"/*.repo; do
77 [ -e "$repo" ] || continue
78 cp -f "$repo" "$REPOS/${repo##*/}"
79 done
80 ;;
81 *)
82 echo "usage: ${0##*/} off|on" >&2
83 exit 2
84 ;;
85 esac
86