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
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 <statement>` 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 <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
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.

View File

@ -24,22 +24,10 @@ Usage: $0 [options]
Specify path for build root
(Default: /build)
-c <configuration>
Specify path to generate-zbm(5) configuration
(Default: \${BUILDROOT}/config.yaml or \${BUILDROOT}/config.yaml.default)
-o <output-directory>
Specify path to output directory
(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>
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
# 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
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}" "${dconfd}/${cfile##*/}" || error "unable to link ${cfile}"
ln -Tsf "${cfile}" "/etc/zfsbootmenu/${confd}/${cfile##*/}" \
|| error "unable to link ${cfile}"
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}"
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
}
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