-
Notifications
You must be signed in to change notification settings - Fork 178
Expand file tree
/
Copy pathJustfile
More file actions
384 lines (331 loc) · 14.7 KB
/
Justfile
File metadata and controls
384 lines (331 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# The default entrypoint to working on this project.
# Run `just --list` to see available targets organized by group.
#
# See also `Makefile` and `xtask.rs`. Commands which end in `-local`
# skip containerization or virtualization (and typically just proxy `make`).
#
# By default the layering is:
# Github Actions -> Justfile -> podman -> make -> rustc
# -> podman -> package manager
# -> cargo xtask
# --------------------------------------------------------------------
# Configuration variables (override via environment or command line)
# Example: BOOTC_base=quay.io/fedora/fedora-bootc:42 just build
# Output image name
base_img := "localhost/bootc"
# Synthetic upgrade image for testing
upgrade_img := base_img + "-upgrade"
# Build variant: ostree (default) or composefs
variant := env("BOOTC_variant", "ostree")
bootloader := env("BOOTC_bootloader", "grub")
# Only used for composefs tests
filesystem := env("BOOTC_filesystem", "ext4")
# Only used for composefs tests
boot_type := env("BOOTC_boot_type", "bls")
# Only used for composefs tests
seal_state := env("BOOTC_seal_state", "unsealed")
# Base container image to build from
base := env("BOOTC_base", "quay.io/centos-bootc/centos-bootc:stream10")
# Buildroot base image
buildroot_base := env("BOOTC_buildroot_base", "quay.io/centos/centos:stream10")
# Optional: path to extra source (e.g. composefs-rs) for local development
# DEPRECATED: Use [patch] sections in Cargo.toml instead, which are auto-detected
extra_src := env("BOOTC_extra_src", "")
# Set to "1" to disable auto-detection of local Rust dependencies
no_auto_local_deps := env("BOOTC_no_auto_local_deps", "")
# Internal variables
nocache := env("BOOTC_nocache", "")
_nocache_arg := if nocache != "" { "--no-cache" } else { "" }
testimage_label := "bootc.testimage=1"
lbi_images := "quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.access.redhat.com/ubi9/podman:latest"
fedora-coreos := "quay.io/fedora/fedora-coreos:testing-devel"
generic_buildargs := ""
_extra_src_args := if extra_src != "" { "-v " + extra_src + ":/run/extra-src:ro --security-opt=label=disable" } else { "" }
base_buildargs := generic_buildargs + " " + _extra_src_args \
+ " --build-arg=base=" + base \
+ " --build-arg=variant=" + variant \
+ " --build-arg=bootloader=" + bootloader \
+ " --build-arg=boot_type=" + boot_type \
+ " --build-arg=seal_state=" + seal_state \
+ " --build-arg=filesystem=" + filesystem # required for bootc container ukify to allow missing fsverity
buildargs := base_buildargs \
+ " --cap-add=all --security-opt=label=type:container_runtime_t --device /dev/fuse" \
+ " --secret=id=secureboot_key,src=target/test-secureboot/db.key --secret=id=secureboot_cert,src=target/test-secureboot/db.crt"
# ============================================================================
# Core workflows - the main targets most developers will use
# ============================================================================
# Build container image from current sources (default target)
[group('core')]
build: package _keygen && _pull-lbi-images
#!/bin/bash
set -xeuo pipefail
test -d target/packages
pkg_path=$(realpath target/packages)
podman build {{_nocache_arg}} --build-context "packages=${pkg_path}" -t {{base_img}} {{buildargs}} .
# Show available build variants and current configuration
[group('core')]
list-variants:
#!/bin/bash
cat <<'EOF'
Build Variants (set via BOOTC_variant= or variant=)
====================================================
ostree (default)
Standard bootc image using ostree backend.
This is the traditional, production-ready configuration.
composefs (bootloader, filesystem, boot_type, seal_state)
Build Composefs image with:
- The specified bootloader (grub/systemd)
- The specified filesystem (ext4,btrfs,xfs)
- The specified boot type (BLS/UKI)
- The specified seal state (sealed/unsealed) determining whether we sign the UKI and
use secure boot or not
Use `just build-sealed` as shortcut to build a sealed composefs image with systemd-boot as the bootloader
Current Configuration
=====================
EOF
echo " BOOTC_variant={{variant}}"
echo " BOOTC_base={{base}}"
echo " BOOTC_extra_src={{extra_src}}"
echo ""
# Build a sealed composefs image (alias for variant=composefs-sealeduki-sdboot)
[group('core')]
build-sealed:
@just --justfile {{justfile()}} variant=composefs bootloader=systemd boot_type=uki seal_state=sealed build
# Run tmt integration tests in VMs (e.g. `just test-tmt readonly`)
[group('core')]
test-tmt *ARGS: build
@just _build-upgrade-image
@just test-tmt-nobuild {{ARGS}}
# Run containerized unit and integration tests
[group('core')]
test-container: build build-units
podman run --rm --read-only localhost/bootc-units /usr/bin/bootc-units
podman run --rm --env=BOOTC_variant={{variant}} --env=BOOTC_base={{base}} --env=BOOTC_boot_type={{boot_type}} --mount=type=image,source={{base_img}},target=/run/target {{base_img}} bootc-integration-tests container
[group('core')]
test-composefs bootloader filesystem boot_type seal_state *ARGS:
@if [ "{{seal_state}}" = "sealed" ] && [ "{{filesystem}}" = "xfs" ]; then \
echo "Invalid combination: sealed requires filesystem that supports fs-verity (ext4, btrfs)"; \
exit 1; \
fi
@if [ "{{seal_state}}" = "sealed" ] && [ "{{boot_type}}" != "uki" ]; then \
echo "Invalid combination: sealed requires boot_type=uki"; \
exit 1; \
fi
just variant=composefs \
bootloader={{bootloader}} \
filesystem={{filesystem}} \
boot_type={{boot_type}} \
seal_state={{seal_state}} \
test-tmt --composefs-backend \
--bootloader={{bootloader}} \
--filesystem={{filesystem}} \
--seal-state={{seal_state}} \
--boot-type={{boot_type}} \
{{ARGS}} \
$(if [ "{{boot_type}}" = "uki" ]; then echo "readonly"; else echo "integration"; fi)
# Run cargo fmt and clippy checks in container
[group('core')]
validate:
podman build {{base_buildargs}} --target validate .
# Test container export via Anaconda liveimg install in a QEMU VM
[group('testing')]
test-container-export: build
#!/bin/bash
set -xeuo pipefail
iso=target/anaconda-test/boot.iso
if [ ! -f "$iso" ]; then
# Determine the ISO download URL from the base image's os-release
eval $(podman run --rm {{base_img}} bash -c '. /etc/os-release && echo "ID=$ID VERSION_ID=$VERSION_ID"')
case "${ID}-${VERSION_ID}" in
centos-10)
url="https://mirror.stream.centos.org/10-stream/BaseOS/x86_64/iso/CentOS-Stream-10-latest-x86_64-boot.iso" ;;
fedora-*)
url="https://download.fedoraproject.org/pub/fedora/linux/releases/${VERSION_ID}/Everything/x86_64/iso/Fedora-Everything-netinst-x86_64-${VERSION_ID}-1.1.iso" ;;
*)
echo "Unsupported OS: ${ID}-${VERSION_ID}" >&2; exit 1 ;;
esac
mkdir -p target/anaconda-test
curl -L --retry 3 --progress-bar -o "$iso" "$url"
fi
cargo run -p tests-integration -- anaconda-test --iso "$iso" {{base_img}}
# ============================================================================
# Testing variants and utilities
# ============================================================================
# Run tmt tests without rebuilding (for fast iteration)
[group('testing')]
test-tmt-nobuild *ARGS:
cargo xtask run-tmt --env=BOOTC_variant={{variant}} --upgrade-image={{upgrade_img}} {{base_img}} {{ARGS}}
# Run tmt tests on Fedora CoreOS
[group('testing')]
test-tmt-on-coreos *ARGS:
cargo xtask run-tmt --env=BOOTC_variant={{variant}} --env=BOOTC_target={{base_img}}-coreos:latest {{fedora-coreos}} {{ARGS}}
# Run external container tests against localhost/bootc
[group('testing')]
run-container-external-tests:
./tests/container/run {{base_img}}
# Remove all test VMs created by tmt tests
[group('testing')]
tmt-vm-cleanup:
bcvk libvirt rm --stop --force --label bootc.test=1
# Build test image for Fedora CoreOS testing
[group('testing')]
build-testimage-coreos PATH: _keygen
#!/bin/bash
set -xeuo pipefail
pkg_path=$(realpath "{{PATH}}")
podman build --build-context "packages=${pkg_path}" \
--build-arg SKIP_CONFIGS=1 \
-t {{base_img}}-coreos {{buildargs}} .
# Build test image for install tests (used by CI)
[group('testing')]
build-install-test-image: build
cd hack && podman build {{base_buildargs}} -t {{base_img}}-install -f Containerfile.drop-lbis
# ============================================================================
# Documentation
# ============================================================================
# Serve docs locally (prints URL)
[group('docs')]
mdbook-serve: build-mdbook
#!/bin/bash
set -xeuo pipefail
podman run --init --replace -d --name bootc-mdbook --rm --publish 127.0.0.1::8000 localhost/bootc-mdbook
echo http://$(podman port bootc-mdbook 8000/tcp)
# Build the documentation (mdbook)
[group('docs')]
build-mdbook:
#!/bin/bash
set -xeuo pipefail
secret_arg=""
if test -n "${GH_TOKEN:-}"; then
secret_arg="--secret=id=GH_TOKEN,env=GH_TOKEN"
fi
podman build {{generic_buildargs}} ${secret_arg} -t localhost/bootc-mdbook -f docs/Dockerfile.mdbook .
# Build docs and extract to DIR
[group('docs')]
build-mdbook-to DIR: build-mdbook
#!/bin/bash
set -xeuo pipefail
container_id=$(podman create localhost/bootc-mdbook)
podman cp ${container_id}:/src/docs/book {{DIR}}
podman rm -f ${container_id}
# ============================================================================
# Debugging and validation
# ============================================================================
# Validate composefs digests match between build and install views
[group('debugging')]
validate-composefs-digest:
cargo xtask validate-composefs-digest {{base_img}}
# Verify reproducible builds (runs package twice, compares output)
[group('debugging')]
check-buildsys:
cargo run -p xtask check-buildsys
# Get container image pullspec for a given OS (e.g. `pullspec-for-os base fedora-42`)
[group('debugging')]
pullspec-for-os TYPE NAME:
@jq -r --arg v "{{NAME}}" '."{{TYPE}}"[$v]' < hack/os-image-map.json
# ============================================================================
# Maintenance
# ============================================================================
# Update generated files (man pages, JSON schemas)
[group('maintenance')]
update-generated:
cargo run -p xtask update-generated
# Remove all locally-built test container images
[group('maintenance')]
clean-local-images:
podman images --filter "label={{testimage_label}}"
podman images --filter "label={{testimage_label}}" --format "{{{{.ID}}" | xargs -r podman rmi -f
podman image prune -f
podman rmi {{fedora-coreos}} -f
# Build packages (RPM) into target/packages/
[group('maintenance')]
package:
#!/bin/bash
set -xeuo pipefail
packages=target/packages
if test -n "${BOOTC_SKIP_PACKAGE:-}"; then
if test '!' -d "${packages}"; then
echo "BOOTC_SKIP_PACKAGE is set, but missing ${packages}" 1>&2; exit 1
fi
exit 0
fi
eval $(just _git-build-vars)
echo "Building RPM with version: ${VERSION}"
# Auto-detect local Rust path dependencies (e.g., from [patch] sections)
local_deps_args=""
if [[ -z "{{no_auto_local_deps}}" ]]; then
local_deps_args=$(cargo xtask local-rust-deps)
fi
podman build {{base_buildargs}} --build-arg=SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} --build-arg=pkgversion=${VERSION} -t localhost/bootc-pkg --target=build $local_deps_args .
mkdir -p "${packages}"
rm -vf "${packages}"/*.rpm
podman run --rm localhost/bootc-pkg tar -C /out/ -cf - . | tar -C "${packages}"/ -xvf -
chmod a+rx target "${packages}"
chmod a+r "${packages}"/*.rpm
# Build unit tests into a container image
[group('maintenance')]
build-units:
#!/bin/bash
set -xeuo pipefail
eval $(just _git-build-vars)
podman build {{base_buildargs}} --build-arg=SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} --build-arg=pkgversion=${VERSION} --target units -t localhost/bootc-units .
# ============================================================================
# Internal helpers (prefixed with _)
# ============================================================================
_pull-lbi-images:
podman pull -q --retry 5 --retry-delay 5s {{lbi_images}}
_git-build-vars:
#!/bin/bash
set -euo pipefail
SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
if VERSION=$(git describe --tags --exact-match 2>/dev/null); then
VERSION="${VERSION#v}"
VERSION="${VERSION//-/.}"
else
COMMIT=$(git rev-parse HEAD | cut -c1-10)
COMMIT_TS=$(git show -s --format=%ct)
TIMESTAMP=$(date -u -d @${COMMIT_TS} +%Y%m%d%H%M)
VERSION="${TIMESTAMP}.g${COMMIT}"
fi
echo "SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}"
echo "VERSION=${VERSION}"
_keygen:
./hack/generate-secureboot-keys
_build-upgrade-image:
cat tmt/tests/Dockerfile.upgrade | podman build -t {{upgrade_img}} --from={{base_img}} -
# Copy an image from user podman storage to root's podman storage
# This allows building as regular user then running privileged tests
[group('testing')]
copy-to-rootful $image:
#!/bin/bash
set -euxo pipefail
# If already running as root, nothing to do
if [[ "${UID}" -eq "0" ]]; then
echo "Already root, no need to copy image"
exit 0
fi
# Check if the image exists in user storage
if ! podman image exists "${image}"; then
echo "Image ${image} not found in user podman storage" >&2
exit 1
fi
# Get the image ID from user storage
USER_IMG_ID=$(podman images --filter reference="${image}" --format '{{{{.ID}}')
# Check if the same image ID exists in root storage
ROOT_IMG_ID=$(sudo podman images --filter reference="${image}" --format '{{{{.ID}}' 2>/dev/null || true)
if [[ "${USER_IMG_ID}" == "${ROOT_IMG_ID}" ]] && [[ -n "${ROOT_IMG_ID}" ]]; then
echo "Image ${image} already exists in root storage with same ID"
exit 0
fi
# Copy the image from user to root storage
# Use podman save/load via pipe (works on systems without machinectl)
podman save "${image}" | sudo podman load
echo "Copied ${image} to root podman storage"
# Copy all LBI (bound) images to root's podman storage
[group('testing')]
copy-lbi-to-rootful:
#!/bin/bash
set -euxo pipefail
for img in {{lbi_images}}; do
just copy-to-rootful "$img"
done