| 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 |
set -euo pipefail |
| 40 |
|
| 41 |
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
| 42 |
|
| 43 |
|
| 44 |
|
| 45 |
|
| 46 |
. "$REPO_ROOT/build/privilege.sh" |
| 47 |
|
| 48 |
|
| 49 |
|
| 50 |
|
| 51 |
. "$REPO_ROOT/build/build-stamp.sh" |
| 52 |
|
| 53 |
|
| 54 |
|
| 55 |
|
| 56 |
. "$REPO_ROOT/build/host-recipe.sh" |
| 57 |
|
| 58 |
|
| 59 |
|
| 60 |
|
| 61 |
. "$REPO_ROOT/build/preflight-gate.sh" |
| 62 |
|
| 63 |
IMAGE="localhost/alloy:local" |
| 64 |
BIB_IMAGE="quay.io/centos-bootc/bootc-image-builder:latest" |
| 65 |
DEF="$REPO_ROOT/build/bib-defs.yaml" |
| 66 |
OUTPUT="$REPO_ROOT/output" |
| 67 |
|
| 68 |
|
| 69 |
|
| 70 |
|
| 71 |
|
| 72 |
|
| 73 |
DEF_VERSION="$(sed -n 's/^VERSION_ID="\{0,1\}\([^"]*\)"\{0,1\}$/\1/p' \ |
| 74 |
"$REPO_ROOT/usr/lib/os-release")" |
| 75 |
[ -n "$DEF_VERSION" ] || { echo "error: no VERSION_ID in usr/lib/os-release" >&2; exit 1; } |
| 76 |
DEF_NAME="alloy-${DEF_VERSION}.yaml" |
| 77 |
|
| 78 |
TYPE="raw" |
| 79 |
WRITE_DEV="" |
| 80 |
|
| 81 |
|
| 82 |
HOST="" |
| 83 |
SKIP_BUILD=0 |
| 84 |
|
| 85 |
NO_PREFLIGHT=0 |
| 86 |
SKIP_BIB=0 |
| 87 |
|
| 88 |
BUILD_ARGS=() |
| 89 |
|
| 90 |
die() { printf 'error: %s\n' "$*" >&2; exit 1; } |
| 91 |
|
| 92 |
|
| 93 |
|
| 94 |
|
| 95 |
|
| 96 |
usage() { |
| 97 |
awk 'NR==1 {next} !/^#/ {exit} {sub(/^# ?/, ""); print}' "${BASH_SOURCE[0]}" |
| 98 |
exit "${1:-0}" |
| 99 |
} |
| 100 |
|
| 101 |
while [ $# -gt 0 ]; do |
| 102 |
case "$1" in |
| 103 |
--type) TYPE="${2:?--type needs a value}"; shift 2 ;; |
| 104 |
--write) WRITE_DEV="${2:?--write needs a device path}"; shift 2 ;; |
| 105 |
--skip-build) SKIP_BUILD=1; shift ;; |
| 106 |
|
| 107 |
|
| 108 |
--no-preflight) NO_PREFLIGHT=1; shift ;; |
| 109 |
|
| 110 |
|
| 111 |
|
| 112 |
--write-only|--skip-bib) SKIP_BIB=1; SKIP_BUILD=1; shift ;; |
| 113 |
|
| 114 |
|
| 115 |
|
| 116 |
|
| 117 |
--build-arg) BUILD_ARGS+=(--build-arg "${2:?--build-arg needs KEY=VALUE}"); shift 2 ;; |
| 118 |
|
| 119 |
|
| 120 |
|
| 121 |
--host) HOST="${2:?--host needs a machine name}"; shift 2 ;; |
| 122 |
-h|--help) usage 0 ;; |
| 123 |
*) die "unknown argument: $1 (see --help)" ;; |
| 124 |
esac |
| 125 |
done |
| 126 |
|
| 127 |
[ -z "$HOST" ] || host_recipe_args "$HOST" BUILD_ARGS |
| 128 |
|
| 129 |
|
| 130 |
|
| 131 |
|
| 132 |
case "$TYPE" in |
| 133 |
iso|bootc-installer) |
| 134 |
die "$TYPE builds an Anaconda ISO, which installs an unloginable machine; use build/build-iso.sh for the Alloy installer ISO" ;; |
| 135 |
esac |
| 136 |
|
| 137 |
command -v podman >/dev/null || die "podman not found" |
| 138 |
[ -f "$DEF" ] || die "missing distro def: $DEF" |
| 139 |
[ -f "$REPO_ROOT/Containerfile" ] || die "no Containerfile at $REPO_ROOT" |
| 140 |
|
| 141 |
|
| 142 |
|
| 143 |
|
| 144 |
|
| 145 |
if [ "$SKIP_BIB" -eq 1 ]; then |
| 146 |
echo "==> Skipping image build and bib; using the artifact already in $OUTPUT" |
| 147 |
[ -n "$WRITE_DEV" ] || die "--write-only only makes sense with --write" |
| 148 |
fi |
| 149 |
|
| 150 |
|
| 151 |
if [ "$SKIP_BIB" -eq 1 ]; then |
| 152 |
: |
| 153 |
elif [ "$SKIP_BUILD" -eq 0 ]; then |
| 154 |
|
| 155 |
|
| 156 |
|
| 157 |
|
| 158 |
|
| 159 |
preflight_gate "$HOST" "$HOST_ARCH" "$NO_PREFLIGHT" |
| 160 |
echo "==> Building $IMAGE (rootful)" |
| 161 |
|
| 162 |
|
| 163 |
stamp_build_args BUILD_ARGS |
| 164 |
priv podman build --jobs 2 "${BUILD_ARGS[@]}" -t "$IMAGE" "$REPO_ROOT" |
| 165 |
else |
| 166 |
echo "==> Skipping image build; reusing $IMAGE" |
| 167 |
privc podman image exists "$IMAGE" || die "$IMAGE not in the root store; drop --skip-build" |
| 168 |
fi |
| 169 |
|
| 170 |
if [ "$SKIP_BIB" -eq 0 ]; then |
| 171 |
|
| 172 |
privc podman image exists "$BIB_IMAGE" || { |
| 173 |
echo "==> Pulling $BIB_IMAGE" |
| 174 |
priv podman pull "$BIB_IMAGE" |
| 175 |
} |
| 176 |
|
| 177 |
|
| 178 |
|
| 179 |
|
| 180 |
echo "==> Building --type $TYPE into $OUTPUT" |
| 181 |
|
| 182 |
|
| 183 |
|
| 184 |
|
| 185 |
|
| 186 |
|
| 187 |
if [ -d "$OUTPUT" ] && [ -n "$(privc ls -A "$OUTPUT" 2>/dev/null)" ]; then |
| 188 |
echo "==> Rotating previous output to ${OUTPUT}.prev" |
| 189 |
privc rm -rf "${OUTPUT:?}.prev" |
| 190 |
privc mv "$OUTPUT" "${OUTPUT}.prev" |
| 191 |
fi |
| 192 |
mkdir -p "$OUTPUT" |
| 193 |
|
| 194 |
priv podman run --rm --privileged \ |
| 195 |
--security-opt label=type:unconfined_t \ |
| 196 |
-v /var/lib/containers/storage:/var/lib/containers/storage \ |
| 197 |
-v "$OUTPUT":/output \ |
| 198 |
-v "$DEF":"/usr/share/bootc-image-builder/defs/$DEF_NAME":ro \ |
| 199 |
"$BIB_IMAGE" \ |
| 200 |
--type "$TYPE" \ |
| 201 |
--log-level info \ |
| 202 |
"$IMAGE" |
| 203 |
fi |
| 204 |
|
| 205 |
|
| 206 |
case "$TYPE" in |
| 207 |
raw) ARTIFACT="$OUTPUT/image/disk.raw" ;; |
| 208 |
qcow2) ARTIFACT="$OUTPUT/qcow2/disk.qcow2" ;; |
| 209 |
*) ARTIFACT="$(privc find "$OUTPUT" -type f ! -name '*.json' | head -1)" ;; |
| 210 |
esac |
| 211 |
[ -n "$ARTIFACT" ] && privc test -f "$ARTIFACT" || die "expected artifact not found for type $TYPE" |
| 212 |
echo "==> Built: $ARTIFACT ($(privc du -h "$ARTIFACT" | cut -f1))" |
| 213 |
|
| 214 |
|
| 215 |
|
| 216 |
|
| 217 |
if [ -n "$WRITE_DEV" ]; then |
| 218 |
"$REPO_ROOT/build/write-device.sh" "$ARTIFACT" "$WRITE_DEV" "$TYPE" |
| 219 |
else |
| 220 |
echo "==> To write it to a USB stick:" |
| 221 |
echo " $PRIV_NAME dd if=$ARTIFACT of=/dev/sdX bs=4M oflag=direct conv=fsync status=progress" |
| 222 |
echo " (or re-run with --write /dev/sdX to rebuild and write in one step)" |
| 223 |
fi |
| 224 |
|