From 5427883f178cdb86d6215959ed6c9f2e41ea4d5a Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" Date: Wed, 23 Nov 2022 13:49:52 -0500 Subject: [PATCH] Improve containerized builds - "Tiered" configuration simplifies management and allows more targeted overrides, symlinking configs in `/etc/zfsbootmenu` in the container: 1. First tier comes from `etc/zfsbootmenu` (global defaults) 2. Second tier comes from `etc/zbm-builder` (container defaults) 3. Third tier comes from the build root (build specific) Configurations in later tiers override those with conflicting names in earlier tiers. - Tiered configuration now includes mkinitcpio configuration, allowing containers to build mkinitcpio images - Container configuration for mkinitcpio supports dracut-style snippets in `mkinitcpio.conf.d` - The builder now looks for an `rc.d` subdirectory in the build root and will invoke every executable file therein before generating images to provide a means to "terraform" the build container - The `zbm-builder.sh` wrapper now supports a configuration file to allow defaults to be specified; this requires a two-pass getopts to find and load the configuration file before parsing remaining options - A new option to `zbm-builder.sh`, `-R`, will remove any existing host files (`hostid` and `zpool.cache`) from the build root to make sure they are always up to date with the host versions - The container entrypoint now configures `generate-zbm` to write its output directly to the desired output directory rather than staging in a temporary output directory, allowing `generate-zbm` to manage version rollovers as it does in host installations - Remove superfluous arguments from container entrypoint to manage `hostid`, `zpool.cache` and `config.yaml`; the files either exist in the build root or the container will use defaults - Drop `docker-compose.yml` and now-obsolete `config.yaml.default` - Update documentation to better reflect current build procedure --- etc/zbm-builder/config.yaml | 17 +++ etc/zbm-builder/mkinitcpio.conf | 42 ++++++ releng/docker/README.md | 214 +++++++++++++++++++----------- releng/docker/build-init.sh | 143 ++++++++------------ releng/docker/config.yaml.default | 22 --- releng/docker/docker-compose.yml | 9 -- zbm-builder.sh | 83 ++++++++++-- 7 files changed, 316 insertions(+), 214 deletions(-) create mode 100644 etc/zbm-builder/config.yaml create mode 100644 etc/zbm-builder/mkinitcpio.conf delete mode 100644 releng/docker/config.yaml.default delete mode 100644 releng/docker/docker-compose.yml diff --git a/etc/zbm-builder/config.yaml b/etc/zbm-builder/config.yaml new file mode 100644 index 0000000..41226d6 --- /dev/null +++ b/etc/zbm-builder/config.yaml @@ -0,0 +1,17 @@ +Global: + # Set InitCPIO to true to use mkinitcpio for ZBM images + #InitCPIO: true + # The build container *forces* Global.ManageImages +Components: + # Enable only current kernel/initramfs components and a backup + Enabled: true + Versions: false + # The ZBM build container *forces* Components.ImageDir +EFI: + # Enable only current EFI executable and a backup file + Enabled: true + Versions: false + # The ZBM build container *forces* EFI.ImageDir +Kernel: + # Set ZBM command-line options for the EFI bundle here + CommandLine: zfsbootmenu ro quiet loglevel=4 nomodeset diff --git a/etc/zbm-builder/mkinitcpio.conf b/etc/zbm-builder/mkinitcpio.conf new file mode 100644 index 0000000..6a6447a --- /dev/null +++ b/etc/zbm-builder/mkinitcpio.conf @@ -0,0 +1,42 @@ +# This is a specialization of the ZFSBootMenu mkinitcpio.conf file for use in +# the ghcr.io/zbm-dev/zbm-builder container. Most documentation has been +# omitted. For a description of this file, see the manual pages +# +# - zfsbootmenu(7) +# - mkinitcpio(5) +# +# As well as a more thoroughly commented version at the location +# etc/zfsbootmenu/mkinitcpio.conf in the zfsbootmenu git repository. + +# No specific customizations for container builds +MODULES=() +BINARIES=() +FILES=() + +# Because generate-zbm adds the required 'zfsbootmenu' hook, omit it here. +HOOKS=(base udev autodetect modconf block filesystems keyboard) + +# In containers, it is helpful to allow some dynamic configuration. In +# particular, the zbm-builder.sh helper script that configures and runs the +# build container will automatically create configuration entries in the +# subdirectories +# +# dracut.conf.d +# mkinitcpio.conf.d +# +# of the build directory for any hook found in the subdirectories +# +# hooks.early_setup.d +# hooks.setup.d +# hooks.teardown.d +# +# of the same build directory. Support for mkinitcpio.conf.d mimics similar +# support for dracut.conf.d built directly into dracut. +# +# Note that, inside the container, the build directory will be mounted at +# /build, so reference those paths here. +for _zbm_hook in /build/mkinitcpio.conf.d/*; do + [ -r "${_zbm_hook}" ] || continue + . "${_zbm_hook}" +done +unset _zbm_hook diff --git a/releng/docker/README.md b/releng/docker/README.md index 94e76d6..f5e6634 100644 --- a/releng/docker/README.md +++ b/releng/docker/README.md @@ -63,22 +63,20 @@ specific commit based on the contents of `/etc/zbm-commit-hash`. When running a container from the ZFSBootMenu builder image, it is generally expected that some compatible volume (generally, a local directory) will be -bind-mounted as a volume at the path `/zbm` inside the container. This volume -may either be empty or contain a pre-existing ZFSBootMenu source tree. -Specifically, if the volume is not empty, it must contain the following -components of the ZFSBootMenu repository: +bind-mounted as a volume at the path `/build` inside the container. The volume +may either be empty or contain a custom ZFSBootMenu configuration and will +contain build products (a UEFI bundle, separate kernel and initramfs +components, or both) in a `build` subdirectory. -- `dracut`, the Dracut module that populates an image with ZFSBootMenu; - -- `zfsbootmenu`, the core ZFSBootMenu components; - -- `bin/generate-zbm`, the executable script that creates ZFSBootMenu images; - -If the build script finds the volume mounted at `/zbm` empty, it will fetch an -archive of the official ZFSBootMenu repository on github.com. This makes the -image capable of producing default images without needing a local clone of the -repository. The specific commit, tag or branch to fetch can be specified at -container run time. +The container entrypoint expects to run `generate-zbm` directly from a +ZFSBootMenu source repository that is available at `/zbm` within the container. +If the entrypoint finds `/zbm` nonexistent or devoid of files, it will fetch a +copy of the upstream source repository and unpack it where expected. (The tag, +commit or branch to fetch can be specified at runtime or a default will be +chosen as encoded in the container image.) Any pre-existing and non-empty +`/zbm` within the container must contain a copy of the source repository. This +is useful, *e.g.*, to bind-mount a local clone of the repository into the +container. ## Command-Line Arguments and Environment Variables @@ -88,43 +86,20 @@ command-line argument to see a summary of build options and their default options. The options are: - `$BUILDROOT` specifies a default root for image builds. The build root is - expected to hold a default default configuration file and output directory, - as well as optional hostid and pool cache files. If an output directory, - specific configuration and (when appropriate) hostid or pool cache are - specified, then `$BUILDROOT` is not relevant. + expected to hold configuration files and, optionally, an output directory, + hostid and pool cache files. The value of `$BUILDROOT` is `/build` by + default. The environment variable or default can be overridden with the `-b` option. -- `$ZBMCONF` specifies the in-container path to a specific configuration file. - The build script will override any `ImageDir` paths and remove any - `Global.BootMountPoint` option but otherwise uses the configuration as-is.A - - The environment variable or default can be overridded with the `-c` option. - -- `$ZBMOUTPUT` specifies the in-container path to an output directory. As noted - above, the build script overrides any `ImageDir` path in a configuration, - pointing it instead to a temporary output directory. After the script - successfully runs `generate-zbm`, it will copy any artifacts from the - temporary build directory to `$ZBMOUTPUT`. +- `$ZBMOUTPUT` specifies an alternative output directory for ZFSBootMenu build + products. The container *always* overrides configurations to store build + products (UEFI bundles and kernel components, as configured) in a temporary + directory; these products will be copied to `$ZBMOUTPUT` after successful + image creation. The value of `$ZBMOUTPUT` is `${BUILDROOT}/build` by default. The environment variable or default can be overridded with the `-o` option. -- `$HOSTID` specifies the in-container path to a hostid file. If this file is - specified, it will be copied to `/etc/hostid` inside the container for - inclusion in ZFSBootMenu images. If not, any `/etc/hostid` in the container - will be removed. (Note: unless the `zfsbootmenu` dracut module is configured - with `release_mode=1`, the module may still create an `/etc/hostid` with - potentially arbitrary contents in output images. - - The environment variable or default can be overridded with the `-H` option. - -- `$POOLCACHE` specifies the in-container path to a ZFS pool cache file. If - this file is specified, it will be copied to `/etc/zfs/zpool.cache` inside - the container for inclusion in ZFSBootMenu images. If not, any - `/etc/zfs/zpool.cache` in the container will be removed. - - The environment variable or default can be overridded with the `-C` option. - - `$ZBMTAG` specifies any "commit-ish" label recognized by `git` as a pointer to a specific git commit. This can be a branch name (to grab the head of that branch), tag or commit hash. If `/zbm` in the container is not pre-populated, @@ -136,56 +111,133 @@ options. The options are: The environment variable or default can be overridded with the `-t` option. -An additional command-line argument, `-e`, allows the ZFSBootMenu configuration -to be modified with `yq-go eval` statements at container run time. Do not use -this unless you review the build script and understand, without documentation, -what will happen! +A couple of additional arguments may only be set from the command line: + +- `-e ` provides a statement that will be evaluated via `yq-go eval` + to modify the `generate-zbm` configuration file immediately before an image + is built. This option may be specified more than once. + + > Do not use this unless you review the build script and understand, without + > documentation, what will happen! + +- `-p ` specifies a Void Linux package to install in the container + before images are generated. This option may be specified more than once. + +## ZFSBootMenu Configuration and Execution + +After the ZFSBootMenu container entrypoint fetches (or identifies) a copy of +the ZFSBootMenu source repository, it "installs" the copy into the container by +symlinking key components of the source repository into the container +filesystem: + +- If the source repository is sufficiently new, a symbolic link + + /usr/share/zfsbootmenu -> /zbm/zfsbootmenu + + will point to the core ZFSBootMenu library. + +- For newer versions of ZFSBootMenu, the symbolic link + + /usr/lib/dracut/modules.d/90zfsbootmenu -> /zbm/dracut + + will point to the dracut module; for older versions, the link + + /usr/lib/dracut/modules.d/90zfsbootmenu -> /zbm/90zfsbootmenu + + will serve the same purpose. + +- If the ZFSBootMenu repository contains a mkinitcpio module, a family of links + + /usr/lib/initcpio/hooks/* -> /zbm/initcpio/hooks/* + /usr/lib/initcpio/install/* -> /zbm/initcpio/install/* + + for each file in `/zbm/initcpio/{hooks,install}` will be made to make + `mkinitcpio` aware of the ZFSBootMenu module. + +Configuration files are handled in a multi-pass approach that synthesizes a +composite configuration from increasingly specific sources. In the first pass, +generic upstream configurations are linked *if the source exists*: + + /etc/zfsbootmenu/config.yaml -> /zbm/etc/zfsbootmenu/config.yaml + /etc/zfsbootmenu/mkinitcpio.conf -> /zbm/etc/zfsbootmenu/mkinitcpio.conf + /etc/zfsbootmenu/dracut.conf.d/* -> /zbm/etc/zfsbootmenu/dracut.conf.d/* + /etc/zfsbootmenu/mkinitcpio.conf.d/* -> /zbm/etc/zfsbootmenu/mkinitcpio.conf.d/* + +Next, container-specific defaults are linked *if the source exists*: + + /etc/zfsbootmenu/config.yaml -> /zbm/etc/zbm-builder/config.yaml + /etc/zfsbootmenu/mkinitcpio.conf -> /zbm/etc/zbm-builder/mkinitcpio.conf + /etc/zfsbootmenu/dracut.conf.d/* -> /zbm/etc/zbm-builder/dracut.conf.d/* + /etc/zfsbootmenu/mkinitcpio.conf.d/* -> /zbm/etc/zbm-builder/mkinitcpio.conf.d/* + +Finally, build-specific configurations are linked *if the source exists*: + + /etc/zfsbootmenu/config.yaml -> ${BUILDROOT}/config.yaml + /etc/zfsbootmenu/mkinitcpio.conf -> ${BUILDROOT}/mkinitcpio.conf + /etc/zfsbootmenu/dracut.conf.d/* -> ${BUILDROOT}/dracut.conf.d/* + /etc/zfsbootmenu/mkinitcpio.conf.d/* -> ${BUILDROOT}/mkinitcpio.conf.d/* + +Conflicting links will *replace* any links made by earlier passes. This allows +each level of configurations to mask or augment earlier defaults. + +> NOTE: `mkinitcpio` does not natively support configuration snippets in +> `/etc/zfsbootmenu/mkinitcpio.conf.d`. ZFSBootMenu includes a default +> `mkinitcpio.conf` that manually sources these snippets to emulate the +> standard configuration behavior of dracut. + +In addition, host-specific files are linked if each exists: + + /etc/hostid -> ${BUILDROOT}/hostid + /etc/zfs/zpool.cache -> ${BUILDROOT}/zfs/zpool.cache + +When launched, the container entrypoint will run any executable files it finds +in `${BUILDROOT}/rc.d`. This provides a means to "terraform" the build +container before running `generate-zbm` and can be a useful way to, *e.g.*: + +- Modify the `FONT` variable defined in `/etc/rc.conf`, which will be parsed by + `mkinitcpio` to set a default console font in ZFSBootMenu images. + +- Create additional links to directories in `$BUILDROOT`, such as + + /etc/initcpio -> ${BUILDROOT}/initcpio + + to provide additional `mkinitcpio` modules or + + /etc/dropbear -> ${BUILDROOT}/dropbear + + to provide host keys and configuration for the `dropbear` `mkinitcpio` + module. ## Build Examples To use the previously created `zbm` image to produce ZFSBootMenu files from the -default configuration using a local ZFSBootMenu repository `/sw/zfsbootmenu`, -simply run +default configuration, simply run ```sh -podman run -v /sw/zfsbootmenu:/zbm zbm +podman run -v .:/build zbm ``` After some console output, the container should terminate and the directory -`/sw/zfsbootmenu/releng/docker/build` should contain the UEFI bundle -`vmlinuz.EFI` as well as the components `vmlinuz-bootmenu` (a stock Void Linux -kernel) and corresponding ZFSBootMenu initramfs `initramfs-bootmenu.img`. +`./build` should contain the UEFI bundle `vmlinuz.EFI` as well as the +components `vmlinuz-bootmenu` (a stock Void Linux kernel) and corresponding +ZFSBootMenu initramfs `initramfs-bootmenu.img`. -In the default configuration, the ZFSBootMenu images probably contain an -arbitrary `/etc/hostid` that likely does not agree with the corresponding file -on the host. To make sure that the hostid within the images remains consistent -with the build host, first copy the file from the host to the `releng/docker` -directory: +To provide the hostid and pool cache files to the build container and run from +the `/etc/zfsbootmenu/build` directory, copy the desired files and run the +container with the appropriate volume mount: ```sh -cp /etc/hostid /sw/zfsbootmenu/releng/docker/hostid -podman run -v /sw/zfsbootmenu:/zbm zbm +cp /etc/hostid /etc/zfs/zpool.cache /etc/zfsbootmenu/build +podman run -v /etc/zfsbootmenu/build:/build zbm ``` -To create an image from the current `master` branch without having a local -repository, store the output images in `/boot/efi/EFI/zfsbootmenu` and include -the hostid of the current system, assuming a `zbm` builder container is tagged -locally: +To create an image from a local repository available at `/sw/zfsbootmenu` and +again use a build root of `/etc/zfsbootmenu/build`, run ```sh -mkdir -p /boot/efi/EFI/zfsbootmenu -podman run -v /boot/efi/EFI/zfsbootmenu:/output \ - -v /etc/hostid:/hostid:ro zbm -o /output -H /hostid +podman run -v /etc/zfsbootmenu/build:/build -v /sw/zfsbootmenu:/zbm:ro zbm ``` -# Using Docker Compose - -The file `docker-compose.yml` defines a Docker Compose service that will create -a ZFSBootMenu builder image and mount the parent repository (at path `../..`) -at `/zbm` in the build container. To use this service, simply run - -```sh -docker-compose up -``` - -from this directory. +Because the build container does not modify the repository found in `/zbm`, it +is possible to mount that volume read-only (as indicated by the `:ro` suffix) +without consequence. diff --git a/releng/docker/build-init.sh b/releng/docker/build-init.sh index 6bd0f39..d287829 100755 --- a/releng/docker/build-init.sh +++ b/releng/docker/build-init.sh @@ -24,22 +24,10 @@ Usage: $0 [options] Specify path for build root (Default: /build) - -c - Specify path to generate-zbm(5) configuration - (Default: \${BUILDROOT}/config.yaml or \${BUILDROOT}/config.yaml.default) - -o Specify path to output directory (Default: \${BUILDROOT}/build) - -H - Specify path to hostid file - (Default: \${BUILDROOT}/hostid) - - -C - Specify path to zpool.cache file - (Default: \${BUILDROOT}/zpool.cache) - -p Install the named Void Linux package in the container before building. May be specified more than once to @@ -66,23 +54,14 @@ EOF PACKAGES=() CONFIGEVALS=() GENARGS=() -while getopts "hc:b:o:H:C:t:e:p:" opt; do +while getopts "hb:o:t:e:p:" opt; do case "${opt}" in - c) - ZBMCONF="${OPTARG}" - ;; b) BUILDROOT="${OPTARG}" ;; o) ZBMOUTPUT="${OPTARG}" ;; - H) - HOSTID="${OPTARG}" - ;; - C) - POOLCACHE="${OPTARG}" - ;; t) ZBMTAG="${OPTARG}" ;; @@ -175,18 +154,6 @@ mkdir -p /usr/lib/dracut/modules.d ln -Tsf "${dracutmod}" /usr/lib/dracut/modules.d/90zfsbootmenu \ || error "unable to link dracut module" -# generate-zbm configures dracut to look in /etc/zfsbootmenu/dracut.conf.d. -# Rather than override the default, just link to the in-repo defaults -dconfd="/etc/zfsbootmenu/dracut.conf.d" -if [ ! -d "${dconfd}" ]; then - mkdir -p "${dconfd}" || error "unable to create dracut configuration directory" - - for cfile in /zbm/etc/zfsbootmenu/dracut.conf.d/*; do - [ -e "${cfile}" ] || continue - ln -Tsf "${cfile}" "${dconfd}/${cfile##*/}" || error "unable to link ${cfile}" - done -fi - # Make sure the build root exists : "${BUILDROOT:=/build}" mkdir -p "${BUILDROOT}" || error "unable to create directory '${BUILDROOT}'" @@ -195,78 +162,72 @@ mkdir -p "${BUILDROOT}" || error "unable to create directory '${BUILDROOT}'" : "${ZBMOUTPUT:=${BUILDROOT}/build}" mkdir -p "${ZBMOUTPUT}" || error "unable to create directory '${ZBMOUTPUT}'" -# Pick a default configuration if one was not provided -if [ -z "${ZBMCONF}" ]; then - if [ -r "${BUILDROOT}/config.yaml" ]; then - ZBMCONF="${BUILDROOT}/config.yaml" - else - ZBMCONF="${BUILDROOT}/config.yaml.default" - fi -fi - -# Configuration must exist -[ -r "${ZBMCONF}" ] || error "missing configuration '${ZBMCONF}'" -cp "${ZBMCONF}" "${ZBMWORKDIR}/config.yaml" - -# ZBMCONF now points to local copy -ZBMCONF="${ZBMWORKDIR}/config.yaml" - -GENARGS+=( "--config" "${ZBMCONF}" ) - # Add forced overrides to the end of CONFIGEVALS CONFIGEVALS+=( ".Global.ManageImages = true" - ".Components.ImageDir = \"${ZBMWORKDIR}/build/components\"" - ".EFI.ImageDir = \"${ZBMWORKDIR}/build\"" + ".Components.ImageDir = \"${ZBMOUTPUT}\"" + ".EFI.ImageDir = \"${ZBMOUTPUT}\"" "del(.Global.BootMountPoint)" ) -mkdir -p "${ZBMWORKDIR}/build" || error "unable to create build directory" - -# Apply CONFIGEVALS to override configuration -for ceval in "${CONFIGEVALS[@]}"; do - yq-go eval "${ceval}" -i "${ZBMCONF}" || error "failed to apply '${ceval}' to config" -done - -# Make sure a hostid and cache, if provided, exist -if [ -z "${HOSTID}" ]; then - [ -r "${BUILDROOT}/hostid" ] && HOSTID="${BUILDROOT}/hostid" -elif [ ! -r "${HOSTID}" ]; then - error "missing hostid '${HOSTID}'" -fi - -if [ -z "${POOLCACHE}" ]; then - [ -r "${BUILDROOT}/zpool.cache" ] && POOLCACHE="${BUILDROOT}/zpool.cache" -elif [ ! -r "${POOLCACHE}" ]; then - error "missing pool cache '${POOLCACHE}'" -fi - -# Copy the hostid in place if specified, otherwise remove any hostid -if [ -n "${HOSTID}" ]; then - cp "${HOSTID}" "/etc/hostid" || error "unable to copy hostid" +# Use provided hostid and zpool.cache files +if [ -r "${BUILDROOT}/hostid" ]; then + ln -Tsf "${BUILDROOT}/hostid" /etc/hostid \ + || error "failed to link hostid" else rm -f /etc/hostid fi -# Copy the pool cache in place if specified, otherwise remove any cache -if [ -n "${POOLCACHE}" ]; then +if [ -r "${BUILDROOT}/zpool.cache" ]; then mkdir -p /etc/zfs - cp "${POOLCACHE}" /etc/zfs/zpool.cache || error "unable to copy pool cache" + ln -Tsf "${BUILDROOT}/zpool.cache" /etc/zfs/zpool.cache \ + || error "failed to link zpool.cache" else rm -f /etc/zfs/zpool.cache fi -# If a custom dracut.conf.d exists, link to its contents in the default location -if [ -d "${BUILDROOT}/dracut.conf.d" ]; then - for cfile in "${BUILDROOT}"/dracut.conf.d/*; do - [ -e "${cfile}" ] || continue - ln -Tsf "${cfile}" "${dconfd}/${cfile##*/}" || error "unable to link ${cfile}" +# Link all configuration files in standard location; +# go from most generic to most specificj +mkdir -p /etc/zfsbootmenu +confroots=( + "/zbm/etc/zfsbootmenu" + "/zbm/etc/zbm-builder" + "${BUILDROOT}" +) +for confroot in "${confroots[@]}"; do + for cfile in "config.yaml" "mkinitcpio.conf"; do + [ -e "${confroot}/${cfile}" ] || continue + ln -Tsf "${confroot}/${cfile}" "/etc/zfsbootmenu/${cfile}" \ + || error "unable to link mkinitcpio.conf" done -fi -/zbm/bin/generate-zbm "${GENARGS[@]}" || error "failed to build images" - -for f in "${ZBMWORKDIR}"/build/*; do - [ "${f}" != "${ZBMWORKDIR}/build/*" ] || error "no images to copy to output" - cp -R "${f}" "${ZBMOUTPUT}" + for confd in "dracut.conf.d" "mkinitcpio.conf.d"; do + mkdir -p "/etc/zfsbootmenu/${confd}" + for cfile in "${confroot}/${confd}"/*; do + [ -e "${cfile}" ] || continue + ln -Tsf "${cfile}" "/etc/zfsbootmenu/${confd}/${cfile##*/}" \ + || error "unable to link ${cfile}" + done + done done + +# If a custom rc.d exists, run every executable file therein +for rfile in "${BUILDROOT}"/rc.d/*; do + [ -x "${rfile}" ] || continue + "${rfile}" || error "failed to run RC script ${rfile##*/}" +done + +# Copy default configuration to temporary directory for modifications +ZBMCONF="${ZBMWORKDIR}/config.yaml" +cp "/etc/zfsbootmenu/config.yaml" "${ZBMCONF}" \ + || error "failed to copy configuration to working directory" + +GENARGS+=( "--config" "${ZBMCONF}" ) + +# Apply CONFIGEVALS to override configuration in working directory +for ceval in "${CONFIGEVALS[@]}"; do + yq-go eval "${ceval}" -i "${ZBMCONF}" \ + || error "failed to apply '${ceval}' to config" +done + +exec /zbm/bin/generate-zbm "${GENARGS[@]}" diff --git a/releng/docker/config.yaml.default b/releng/docker/config.yaml.default deleted file mode 100644 index f0f574b..0000000 --- a/releng/docker/config.yaml.default +++ /dev/null @@ -1,22 +0,0 @@ -Global: - # Enable image creation - ManageImages: true - # Make sure to look for dracut configuration in the repo - DracutConfDir: /zbm/etc/zfsbootmenu/dracut.conf.d -Components: - # zbm-build.sh overwrites this anyway - ImageDir: /zbm/releng/docker/build - Enabled: true - # Disable versioning, this is usually a one-off creation - Versions: false - syslinux: - Enabled: false -EFI: - # zbm-build.sh overwrites this anyway - ImageDir: /zbm/releng/docker/build - Versions: false - Enabled: true -Kernel: - # For the EFI bundle, turn off modesetting to avoid initializing GPUs - # Also set loglevel=4 to provide some helpful warning output - CommandLine: zfsbootmenu ro loglevel=4 nomodeset diff --git a/releng/docker/docker-compose.yml b/releng/docker/docker-compose.yml deleted file mode 100644 index fefccf4..0000000 --- a/releng/docker/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -# This builds the ZFSBootMenu builder and then runs it to create images -version: "2" -services: - zfsbootmenu-compiler: - build: "." - # Mount the current repo (../..) where the builder expects it - # Outputs will be stored in ../../releng/docker/build - volumes: - - "../..:/zbm" diff --git a/zbm-builder.sh b/zbm-builder.sh index 66d5478..3ab0a9c 100755 --- a/zbm-builder.sh +++ b/zbm-builder.sh @@ -11,6 +11,15 @@ sanitise_path() { return 1 } +boolean_enabled() { + local val="${1:-}" + + case "${val}" in + [Yy][Ee][Ss]|[Yy]|[Oo][Nn]|1) return 0 ;; + *) return 1 ;; + esac +} + usage() { cat << EOF Build ZFSBootMenu images in an OCI container using podman or docker. @@ -39,6 +48,8 @@ OPTIONS: Build specific ZFSBootMenu commit or tag (e.g. v1.12.0, d5594589) (Default: current upstream master) + -R Remove any existing zpool.cache and hostid in the build directory + -C Do not include host /etc/zfs/zpool.cache in image (If ./zpool.cache exists, this switch will be ignored) @@ -63,6 +74,7 @@ EOF SKIP_HOSTID= SKIP_CACHE= +REMOVE_HOST_FILES= # By default, use the latest upstream build container image BUILD_IMG="ghcr.io/zbm-dev/zbm-builder:latest" @@ -80,24 +92,64 @@ BUILD_ARGS=() # Volume mounts for the container manager VOLUME_ARGS=() +# Optional configuration file +CONFIG= + if command -v podman >/dev/null 2>&1; then PODMAN="podman" else PODMAN="docker" fi -while getopts "b:dhi:l:t:p:v:CH" opt; do +CMDOPTS="b:dhi:l:t:p:v:c:CHR" + +# First pass to get build directory and configuration file +while getopts "${CMDOPTS}" opt; do case "${opt}" in b) BUILD_DIRECTORY="${OPTARG}" ;; - d) - PODMAN=docker + c) + CONFIG="${OPTARG}" ;; h) usage exit 0 ;; + esac +done + +# Make sure the build directory is identifiable +if ! BUILD_DIRECTORY="$( sanitise_path "${BUILD_DIRECTORY}" )"; then + echo "ERROR: build directory does not exist" + exit 1 +fi + +# If a configuration wasn't specified, use a default it one exists +if [ -z "${CONFIG}" ] && [ -r "${BUILD_DIRECTORY}/zbm-builder.conf" ]; then + CONFIG="${BUILD_DIRECTORY}/zbm-builder.conf" +fi + +# Read the optional configuration +if [ -n "${CONFIG}" ]; then + if [ -r "${CONFIG}" ]; then + # shellcheck disable=SC1090 + source "${CONFIG}" + else + echo "ERROR: non-existent configuration specified" + exit 1 + fi +fi + +OPTIND=1 +while getopts "${CMDOPTS}" opt; do + case "${opt}" in + # These have already been parsed in first pass + b|c|h) + ;; + d) + PODMAN=docker + ;; i) BUILD_IMG="${OPTARG}" ;; @@ -113,6 +165,9 @@ while getopts "b:dhi:l:t:p:v:CH" opt; do H) SKIP_HOSTID="yes" ;; + R) + REMOVE_HOST_FILES="yes" + ;; p) BUILD_ARGS+=( "-p" "${OPTARG}" ) ;; @@ -132,11 +187,6 @@ if ! command -v "${PODMAN}" >/dev/null 2>&1; then fi # Always mount a build directory at /build -if ! BUILD_DIRECTORY="$( sanitise_path "${BUILD_DIRECTORY}" )"; then - echo "ERROR: build directory does not exist" - exit 1 -fi - VOLUME_ARGS+=( "-v" "${BUILD_DIRECTORY}:/build" ) # Only mount a local repo at /zbm if specified @@ -154,9 +204,21 @@ if [ -n "${BUILD_TAG}" ]; then BUILD_ARGS+=( "-t" "${BUILD_TAG}" ) fi +if boolean_enabled "${REMOVE_HOST_FILES}"; then + # Remove existing host files + for host_file in "hostid" "zpool.cache"; do + [ -e "${BUILD_DIRECTORY}/${host_file}" ] || continue + if ! rm "${BUILD_DIRECTORY}/${host_file}"; then + echo "ERROR: failed to remove file '${host_file}' from build directory" + exit 1 + fi + echo "Removed file '${host_file}' by user request" + done +fi + # If no local hostid is available, copy the system hostid if desired if ! [ -r "${BUILD_DIRECTORY}"/hostid ]; then - if [ "${SKIP_HOSTID}" != "yes" ] && [ -r /etc/hostid ]; then + if ! boolean_enabled "${SKIP_HOSTID}" && [ -r /etc/hostid ]; then if ! cp /etc/hostid "${BUILD_DIRECTORY}"/hostid; then echo "ERROR: unable to copy /etc/hostid" echo "Copy a hostid file to ./hostid or use -H to disable" @@ -167,7 +229,7 @@ fi # If no local zpool.cache is available, copy the system cache if desired if ! [ -r "${BUILD_DIRECTORY}"/zpool.cache ]; then - if [ "${SKIP_CACHE}" != "yes" ] && [ -r /etc/zfs/zpool.cache ]; then + if ! boolean_enabled "${SKIP_CACHE}" && [ -r /etc/zfs/zpool.cache ]; then if ! cp /etc/zfs/zpool.cache "${BUILD_DIRECTORY}"/zpool.cache; then echo "ERROR: unable to copy /etc/zfs/zpool.cache" echo "Copy a zpool cache to ./zpool.cache or use -C to disable" @@ -178,7 +240,6 @@ fi # If no config is specified, use in-tree default but force EFI and components if ! [ -r "${BUILD_DIRECTORY}"/config.yaml ]; then - BUILD_ARGS+=( "-c" "/zbm/etc/zfsbootmenu/config.yaml" ) BUILD_ARGS+=( "-e" ".EFI.Enabled=true" ) BUILD_ARGS+=( "-e" ".Components.Enabled=true" ) fi