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
This commit is contained in:
Andrew J. Hesford 2022-11-23 13:49:52 -05:00
parent 087892c37c
commit 5427883f17
7 changed files with 316 additions and 214 deletions

View File

@ -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

View File

@ -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

View File

@ -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 When running a container from the ZFSBootMenu builder image, it is generally
expected that some compatible volume (generally, a local directory) will be 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 bind-mounted as a volume at the path `/build` inside the container. The volume
may either be empty or contain a pre-existing ZFSBootMenu source tree. may either be empty or contain a custom ZFSBootMenu configuration and will
Specifically, if the volume is not empty, it must contain the following contain build products (a UEFI bundle, separate kernel and initramfs
components of the ZFSBootMenu repository: components, or both) in a `build` subdirectory.
- `dracut`, the Dracut module that populates an image with ZFSBootMenu; The container entrypoint expects to run `generate-zbm` directly from a
ZFSBootMenu source repository that is available at `/zbm` within the container.
- `zfsbootmenu`, the core ZFSBootMenu components; 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,
- `bin/generate-zbm`, the executable script that creates ZFSBootMenu images; 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
If the build script finds the volume mounted at `/zbm` empty, it will fetch an `/zbm` within the container must contain a copy of the source repository. This
archive of the official ZFSBootMenu repository on github.com. This makes the is useful, *e.g.*, to bind-mount a local clone of the repository into the
image capable of producing default images without needing a local clone of the container.
repository. The specific commit, tag or branch to fetch can be specified at
container run time.
## Command-Line Arguments and Environment Variables ## 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: options. The options are:
- `$BUILDROOT` specifies a default root for image builds. The build root is - `$BUILDROOT` specifies a default root for image builds. The build root is
expected to hold a default default configuration file and output directory, expected to hold configuration files and, optionally, an output directory,
as well as optional hostid and pool cache files. If an output directory, hostid and pool cache files. The value of `$BUILDROOT` is `/build` by
specific configuration and (when appropriate) hostid or pool cache are default.
specified, then `$BUILDROOT` is not relevant.
The environment variable or default can be overridden with the `-b` option. The environment variable or default can be overridden with the `-b` option.
- `$ZBMCONF` specifies the in-container path to a specific configuration file. - `$ZBMOUTPUT` specifies an alternative output directory for ZFSBootMenu build
The build script will override any `ImageDir` paths and remove any products. The container *always* overrides configurations to store build
`Global.BootMountPoint` option but otherwise uses the configuration as-is.A products (UEFI bundles and kernel components, as configured) in a temporary
directory; these products will be copied to `$ZBMOUTPUT` after successful
The environment variable or default can be overridded with the `-c` option. image creation. The value of `$ZBMOUTPUT` is `${BUILDROOT}/build` by default.
- `$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`.
The environment variable or default can be overridded with the `-o` option. 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 - `$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 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, 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. The environment variable or default can be overridded with the `-t` option.
An additional command-line argument, `-e`, allows the ZFSBootMenu configuration A couple of additional arguments may only be set from the command line:
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, - `-e <statement>` provides a statement that will be evaluated via `yq-go eval`
what will happen! 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 <package>` 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 ## Build Examples
To use the previously created `zbm` image to produce ZFSBootMenu files from the To use the previously created `zbm` image to produce ZFSBootMenu files from the
default configuration using a local ZFSBootMenu repository `/sw/zfsbootmenu`, default configuration, simply run
simply run
```sh ```sh
podman run -v /sw/zfsbootmenu:/zbm zbm podman run -v .:/build zbm
``` ```
After some console output, the container should terminate and the directory After some console output, the container should terminate and the directory
`/sw/zfsbootmenu/releng/docker/build` should contain the UEFI bundle `./build` should contain the UEFI bundle `vmlinuz.EFI` as well as the
`vmlinuz.EFI` as well as the components `vmlinuz-bootmenu` (a stock Void Linux components `vmlinuz-bootmenu` (a stock Void Linux kernel) and corresponding
kernel) and corresponding ZFSBootMenu initramfs `initramfs-bootmenu.img`. ZFSBootMenu initramfs `initramfs-bootmenu.img`.
In the default configuration, the ZFSBootMenu images probably contain an To provide the hostid and pool cache files to the build container and run from
arbitrary `/etc/hostid` that likely does not agree with the corresponding file the `/etc/zfsbootmenu/build` directory, copy the desired files and run the
on the host. To make sure that the hostid within the images remains consistent container with the appropriate volume mount:
with the build host, first copy the file from the host to the `releng/docker`
directory:
```sh ```sh
cp /etc/hostid /sw/zfsbootmenu/releng/docker/hostid cp /etc/hostid /etc/zfs/zpool.cache /etc/zfsbootmenu/build
podman run -v /sw/zfsbootmenu:/zbm zbm podman run -v /etc/zfsbootmenu/build:/build zbm
``` ```
To create an image from the current `master` branch without having a local To create an image from a local repository available at `/sw/zfsbootmenu` and
repository, store the output images in `/boot/efi/EFI/zfsbootmenu` and include again use a build root of `/etc/zfsbootmenu/build`, run
the hostid of the current system, assuming a `zbm` builder container is tagged
locally:
```sh ```sh
mkdir -p /boot/efi/EFI/zfsbootmenu podman run -v /etc/zfsbootmenu/build:/build -v /sw/zfsbootmenu:/zbm:ro zbm
podman run -v /boot/efi/EFI/zfsbootmenu:/output \
-v /etc/hostid:/hostid:ro zbm -o /output -H /hostid
``` ```
# Using Docker Compose 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)
The file `docker-compose.yml` defines a Docker Compose service that will create without consequence.
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.

View File

@ -24,22 +24,10 @@ Usage: $0 [options]
Specify path for build root Specify path for build root
(Default: /build) (Default: /build)
-c <configuration>
Specify path to generate-zbm(5) configuration
(Default: \${BUILDROOT}/config.yaml or \${BUILDROOT}/config.yaml.default)
-o <output-directory> -o <output-directory>
Specify path to output directory Specify path to output directory
(Default: \${BUILDROOT}/build) (Default: \${BUILDROOT}/build)
-H <hostid>
Specify path to hostid file
(Default: \${BUILDROOT}/hostid)
-C <cache>
Specify path to zpool.cache file
(Default: \${BUILDROOT}/zpool.cache)
-p <package> -p <package>
Install the named Void Linux package in the container Install the named Void Linux package in the container
before building. May be specified more than once to before building. May be specified more than once to
@ -66,23 +54,14 @@ EOF
PACKAGES=() PACKAGES=()
CONFIGEVALS=() CONFIGEVALS=()
GENARGS=() 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 case "${opt}" in
c)
ZBMCONF="${OPTARG}"
;;
b) b)
BUILDROOT="${OPTARG}" BUILDROOT="${OPTARG}"
;; ;;
o) o)
ZBMOUTPUT="${OPTARG}" ZBMOUTPUT="${OPTARG}"
;; ;;
H)
HOSTID="${OPTARG}"
;;
C)
POOLCACHE="${OPTARG}"
;;
t) t)
ZBMTAG="${OPTARG}" ZBMTAG="${OPTARG}"
;; ;;
@ -175,18 +154,6 @@ mkdir -p /usr/lib/dracut/modules.d
ln -Tsf "${dracutmod}" /usr/lib/dracut/modules.d/90zfsbootmenu \ ln -Tsf "${dracutmod}" /usr/lib/dracut/modules.d/90zfsbootmenu \
|| error "unable to link dracut module" || 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 # Make sure the build root exists
: "${BUILDROOT:=/build}" : "${BUILDROOT:=/build}"
mkdir -p "${BUILDROOT}" || error "unable to create directory '${BUILDROOT}'" 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}" : "${ZBMOUTPUT:=${BUILDROOT}/build}"
mkdir -p "${ZBMOUTPUT}" || error "unable to create directory '${ZBMOUTPUT}'" 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 # Add forced overrides to the end of CONFIGEVALS
CONFIGEVALS+=( CONFIGEVALS+=(
".Global.ManageImages = true" ".Global.ManageImages = true"
".Components.ImageDir = \"${ZBMWORKDIR}/build/components\"" ".Components.ImageDir = \"${ZBMOUTPUT}\""
".EFI.ImageDir = \"${ZBMWORKDIR}/build\"" ".EFI.ImageDir = \"${ZBMOUTPUT}\""
"del(.Global.BootMountPoint)" "del(.Global.BootMountPoint)"
) )
mkdir -p "${ZBMWORKDIR}/build" || error "unable to create build directory" # Use provided hostid and zpool.cache files
if [ -r "${BUILDROOT}/hostid" ]; then
# Apply CONFIGEVALS to override configuration ln -Tsf "${BUILDROOT}/hostid" /etc/hostid \
for ceval in "${CONFIGEVALS[@]}"; do || error "failed to link hostid"
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"
else else
rm -f /etc/hostid rm -f /etc/hostid
fi fi
# Copy the pool cache in place if specified, otherwise remove any cache if [ -r "${BUILDROOT}/zpool.cache" ]; then
if [ -n "${POOLCACHE}" ]; then
mkdir -p /etc/zfs 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 else
rm -f /etc/zfs/zpool.cache rm -f /etc/zfs/zpool.cache
fi fi
# If a custom dracut.conf.d exists, link to its contents in the default location # Link all configuration files in standard location;
if [ -d "${BUILDROOT}/dracut.conf.d" ]; then # go from most generic to most specificj
for cfile in "${BUILDROOT}"/dracut.conf.d/*; do mkdir -p /etc/zfsbootmenu
[ -e "${cfile}" ] || continue confroots=(
ln -Tsf "${cfile}" "${dconfd}/${cfile##*/}" || error "unable to link ${cfile}" "/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 done
fi
/zbm/bin/generate-zbm "${GENARGS[@]}" || error "failed to build images" for confd in "dracut.conf.d" "mkinitcpio.conf.d"; do
mkdir -p "/etc/zfsbootmenu/${confd}"
for f in "${ZBMWORKDIR}"/build/*; do for cfile in "${confroot}/${confd}"/*; do
[ "${f}" != "${ZBMWORKDIR}/build/*" ] || error "no images to copy to output" [ -e "${cfile}" ] || continue
cp -R "${f}" "${ZBMOUTPUT}" ln -Tsf "${cfile}" "/etc/zfsbootmenu/${confd}/${cfile##*/}" \
|| error "unable to link ${cfile}"
done
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[@]}"

View File

@ -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

View File

@ -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"

View File

@ -11,6 +11,15 @@ sanitise_path() {
return 1 return 1
} }
boolean_enabled() {
local val="${1:-}"
case "${val}" in
[Yy][Ee][Ss]|[Yy]|[Oo][Nn]|1) return 0 ;;
*) return 1 ;;
esac
}
usage() { usage() {
cat << EOF cat << EOF
Build ZFSBootMenu images in an OCI container using podman or docker. 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) Build specific ZFSBootMenu commit or tag (e.g. v1.12.0, d5594589)
(Default: current upstream master) (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 -C Do not include host /etc/zfs/zpool.cache in image
(If ./zpool.cache exists, this switch will be ignored) (If ./zpool.cache exists, this switch will be ignored)
@ -63,6 +74,7 @@ EOF
SKIP_HOSTID= SKIP_HOSTID=
SKIP_CACHE= SKIP_CACHE=
REMOVE_HOST_FILES=
# By default, use the latest upstream build container image # By default, use the latest upstream build container image
BUILD_IMG="ghcr.io/zbm-dev/zbm-builder:latest" BUILD_IMG="ghcr.io/zbm-dev/zbm-builder:latest"
@ -80,24 +92,64 @@ BUILD_ARGS=()
# Volume mounts for the container manager # Volume mounts for the container manager
VOLUME_ARGS=() VOLUME_ARGS=()
# Optional configuration file
CONFIG=
if command -v podman >/dev/null 2>&1; then if command -v podman >/dev/null 2>&1; then
PODMAN="podman" PODMAN="podman"
else else
PODMAN="docker" PODMAN="docker"
fi 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 case "${opt}" in
b) b)
BUILD_DIRECTORY="${OPTARG}" BUILD_DIRECTORY="${OPTARG}"
;; ;;
d) c)
PODMAN=docker CONFIG="${OPTARG}"
;; ;;
h) h)
usage usage
exit 0 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) i)
BUILD_IMG="${OPTARG}" BUILD_IMG="${OPTARG}"
;; ;;
@ -113,6 +165,9 @@ while getopts "b:dhi:l:t:p:v:CH" opt; do
H) H)
SKIP_HOSTID="yes" SKIP_HOSTID="yes"
;; ;;
R)
REMOVE_HOST_FILES="yes"
;;
p) p)
BUILD_ARGS+=( "-p" "${OPTARG}" ) BUILD_ARGS+=( "-p" "${OPTARG}" )
;; ;;
@ -132,11 +187,6 @@ if ! command -v "${PODMAN}" >/dev/null 2>&1; then
fi fi
# Always mount a build directory at /build # 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" ) VOLUME_ARGS+=( "-v" "${BUILD_DIRECTORY}:/build" )
# Only mount a local repo at /zbm if specified # Only mount a local repo at /zbm if specified
@ -154,9 +204,21 @@ if [ -n "${BUILD_TAG}" ]; then
BUILD_ARGS+=( "-t" "${BUILD_TAG}" ) BUILD_ARGS+=( "-t" "${BUILD_TAG}" )
fi 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 no local hostid is available, copy the system hostid if desired
if ! [ -r "${BUILD_DIRECTORY}"/hostid ]; then 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 if ! cp /etc/hostid "${BUILD_DIRECTORY}"/hostid; then
echo "ERROR: unable to copy /etc/hostid" echo "ERROR: unable to copy /etc/hostid"
echo "Copy a hostid file to ./hostid or use -H to disable" 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 no local zpool.cache is available, copy the system cache if desired
if ! [ -r "${BUILD_DIRECTORY}"/zpool.cache ]; then 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 if ! cp /etc/zfs/zpool.cache "${BUILD_DIRECTORY}"/zpool.cache; then
echo "ERROR: unable to copy /etc/zfs/zpool.cache" echo "ERROR: unable to copy /etc/zfs/zpool.cache"
echo "Copy a zpool cache to ./zpool.cache or use -C to disable" 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 no config is specified, use in-tree default but force EFI and components
if ! [ -r "${BUILD_DIRECTORY}"/config.yaml ]; then if ! [ -r "${BUILD_DIRECTORY}"/config.yaml ]; then
BUILD_ARGS+=( "-c" "/zbm/etc/zfsbootmenu/config.yaml" )
BUILD_ARGS+=( "-e" ".EFI.Enabled=true" ) BUILD_ARGS+=( "-e" ".EFI.Enabled=true" )
BUILD_ARGS+=( "-e" ".Components.Enabled=true" ) BUILD_ARGS+=( "-e" ".Components.Enabled=true" )
fi fi