diff --git a/build.sh b/build.sh index c561437684..eaa530622e 100755 --- a/build.sh +++ b/build.sh @@ -164,7 +164,12 @@ write_archive_info() { patch_osbuild() { # A few patches that either haven't made it into a release or # that will be obsoleted with other work that will be done soon. - cat /usr/lib/coreos-assembler/*.patch | patch -p1 -d /usr/lib/python3.12/site-packages/ + cat /usr/lib/coreos-assembler/0001-Mount-boot-from-host-in-host-builder-case.patch \ + /usr/lib/coreos-assembler/0001-osbuild-util-fscache-calculate-actual-size-of-files.patch \ + | patch -p1 -d /usr/lib/python3.12/site-packages/ + # shellcheck disable=SC2002 + cat /usr/lib/coreos-assembler/0001-stages-add-kernel-cmdline.bls-append-stage.patch \ + | patch -p1 -d /usr/lib/osbuild/ } if [ $# -ne 0 ]; then diff --git a/src/0002-Mount-boot-from-host-in-host-builder-case.patch b/src/0001-Mount-boot-from-host-in-host-builder-case.patch similarity index 100% rename from src/0002-Mount-boot-from-host-in-host-builder-case.patch rename to src/0001-Mount-boot-from-host-in-host-builder-case.patch diff --git a/src/0001-objectstore-also-mount-etc-containers-for-host-build.patch b/src/0001-objectstore-also-mount-etc-containers-for-host-build.patch deleted file mode 100644 index 6bc1689a2a..0000000000 --- a/src/0001-objectstore-also-mount-etc-containers-for-host-build.patch +++ /dev/null @@ -1,92 +0,0 @@ -From d4b3e3655deb7d55792e52fe6a11c609fb24e3b8 Mon Sep 17 00:00:00 2001 -From: Dusty Mabe -Date: Tue, 24 Oct 2023 14:08:44 -0400 -Subject: [PATCH] objectstore: also mount /etc/containers for "host" buildroot - -In the case we are not using a buildroot (i.e. we are using -the host as the buildroot) let's also mount in /etc/containers -into the environment. There are sometimes where software running -from /usr can't operate without configuration in /etc and this -will allow it to work. - -An example of software hitting this problem is skopeo. With a -simple config like: - -``` -version: '2' -mpp-vars: - release: 38 -pipelines: - - name: skopeo-tree - # build: name:build - source-epoch: 1659397331 - stages: - - type: org.osbuild.skopeo - inputs: - images: - type: org.osbuild.containers - origin: org.osbuild.source - mpp-resolve-images: - images: - - source: quay.io/fedora/fedora-coreos - tag: stable - name: localhost/fcos - options: - destination: - type: containers-storage - storage-path: /usr/share/containers/storage -``` - -We end up hitting an error like this: - -``` -time="2023-10-24T18:27:14Z" level=fatal msg="Error loading trust policy: open /etc/containers/policy.json: no such file or directory" -Traceback (most recent call last): - File "/run/osbuild/bin/org.osbuild.skopeo", line 90, in - r = main(args["inputs"], args["tree"], args["options"]) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "/run/osbuild/bin/org.osbuild.skopeo", line 73, in main - subprocess.run(["skopeo", "copy", image_source, dest], check=True) - File "/usr/lib64/python3.11/subprocess.py", line 571, in run - raise CalledProcessError(retcode, process.args, -subprocess.CalledProcessError: Command '['skopeo', 'copy', 'dir:/tmp/tmp5_qcng99/image', 'containers-storage:[overlay@/run/osbuild/tree/usr/share/containers/storage+/run/containers/storage]localhost/fcos']' returned non-zero exit status 1. -``` - -This PR adds in a mount for /etc/containers from the host so that -/etc/containers/policy.json can be accessed. ---- - osbuild/objectstore.py | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/osbuild/objectstore.py b/osbuild/objectstore.py -index 4a19ce9..922d5ee 100644 ---- a/osbuild/objectstore.py -+++ b/osbuild/objectstore.py -@@ -283,14 +283,22 @@ class HostTree: - self._root = self.store.tempdir(prefix="host") - - root = self._root.name -- # Create a bare bones root file system -- # with just /usr mounted from the host -+ # Create a bare bones root file system. Starting with just -+ # /usr mounted from the host. - usr = os.path.join(root, "usr") - os.makedirs(usr) -+ # Also add in /etc/containers, which will allow us to access -+ # /etc/containers/policy.json and enable moving containers -+ # (skopeo): https://github.com/osbuild/osbuild/pull/1410 -+ # If https://github.com/containers/image/issues/2157 ever gets -+ # fixed we can probably remove this bind mount. -+ etc_containers = os.path.join(root, "etc", "containers") -+ os.makedirs(etc_containers) - - # ensure / is read-only - mount(root, root) - mount("/usr", usr) -+ mount("/etc/containers", etc_containers) - - @property - def tree(self) -> os.PathLike: --- -2.41.0 - diff --git a/src/0001-osbuild-util-fscache-calculate-actual-size-of-files.patch b/src/0001-osbuild-util-fscache-calculate-actual-size-of-files.patch new file mode 100644 index 0000000000..8260b9207a --- /dev/null +++ b/src/0001-osbuild-util-fscache-calculate-actual-size-of-files.patch @@ -0,0 +1,33 @@ +From 178f2a859a0ec068e38a82639cabf764f6264863 Mon Sep 17 00:00:00 2001 +From: Dusty Mabe +Date: Wed, 15 Nov 2023 16:48:24 -0500 +Subject: [PATCH] osbuild/util/fscache: calculate actual size of files + +In OSBuild we'll often be operating on sparse files. Let's make the +tabulation of the size of files on disk used when determining cache +size for pruning consider the actual size of the file usage on disk +rather than the size the file reports to be. + +This means using os.lstat().st_blocks * 512 versus os.lstat().st_size. + +See https://stackoverflow.com/a/55203604 +--- + osbuild/util/fscache.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/osbuild/util/fscache.py b/osbuild/util/fscache.py +index 29b3ce9..95860da 100644 +--- a/osbuild/util/fscache.py ++++ b/osbuild/util/fscache.py +@@ -288,7 +288,7 @@ class FsCache(contextlib.AbstractContextManager, os.PathLike): + return sum( + os.lstat( + os.path.join(path, f) +- ).st_size for path, dirs, files in os.walk( ++ ).st_blocks * 512 for path, dirs, files in os.walk( + path_target + ) for f in files + ) +-- +2.41.0 + diff --git a/src/0001-stages-add-kernel-cmdline.bls-append-stage.patch b/src/0001-stages-add-kernel-cmdline.bls-append-stage.patch new file mode 100644 index 0000000000..f04270e804 --- /dev/null +++ b/src/0001-stages-add-kernel-cmdline.bls-append-stage.patch @@ -0,0 +1,111 @@ +From 38e4e719b7378055465e42873194823138422dde Mon Sep 17 00:00:00 2001 +From: Dusty Mabe +Date: Mon, 6 Nov 2023 20:01:39 -0500 +Subject: [PATCH] stages: add kernel-cmdline.bls-append stage + +This adds a stage to be able to add kernel arguments on a system by +appending to the BLS [1] config directly either in the tree or in +a mount. This is useful on say systems that don't use `grubby` and +thus can't use the org.osbuild.kernel-cmdline stage. + +[1] https://freedesktop.org/wiki/Specifications/BootLoaderSpec/ +--- + stages/org.osbuild.kernel-cmdline.bls-append | 86 ++++++++++++++++++++ + 1 file changed, 86 insertions(+) + create mode 100755 stages/org.osbuild.kernel-cmdline.bls-append + +diff --git a/stages/org.osbuild.kernel-cmdline.bls-append b/stages/org.osbuild.kernel-cmdline.bls-append +new file mode 100755 +index 0000000..dd16662 +--- /dev/null ++++ b/stages/org.osbuild.kernel-cmdline.bls-append +@@ -0,0 +1,86 @@ ++#!/usr/bin/python3 ++""" ++Add kernel command line parameters to a BLS [1] config either in ++the tree or in a mount. ++ ++[1] https://freedesktop.org/wiki/Specifications/BootLoaderSpec/ ++""" ++ ++ ++import glob ++import sys ++from urllib.parse import urlparse ++ ++import osbuild.api ++ ++SCHEMA_2 = r""" ++"options": { ++ "additionalProperties": false, ++ "required": ["kernel_opts"], ++ "properties": { ++ "kernel_opts": { ++ "description": "Additional kernel command line options", ++ "type": "array", ++ "items": { ++ "description": "A single kernel command line option", ++ "type": "string" ++ } ++ }, ++ "bootpath": { ++ "type": "string", ++ "description": "The mounted location of the boot filesystem tree where the BLS entries will be under ./loader/entries/*.conf", ++ "pattern": "^(mount|tree):\/\/\/", ++ "examples": ["tree:///boot", "mount:///", "mount:///boot"], ++ "default": "tree:///boot" ++ } ++ } ++}, ++"devices": { ++ "type": "object", ++ "additionalProperties": true ++}, ++"mounts": { ++ "type": "array" ++} ++""" ++ ++ ++def main(paths, tree, options): ++ kopts = options.get("kernel_opts", []) ++ bootpath = options.get("bootpath", "tree:///boot") ++ ++ url = urlparse(bootpath) ++ scheme = url.scheme ++ if scheme == "tree": ++ root = tree ++ elif scheme == "mount": ++ root = paths["mounts"] ++ else: ++ raise ValueError(f"Unsupported scheme '{scheme}'") ++ ++ assert url.path.startswith("/") ++ bootroot = root + url.path ++ ++ # There is unlikely to be more than one bls config, but just ++ # in case we'll iterate over them. ++ entries = [] ++ for entry in glob.glob(f"{bootroot}/loader/entries/*.conf"): ++ entries.append(entry) ++ # Read in the file and then append to the options line. ++ with open(entry, encoding="utf8") as f: ++ lines = f.read().splitlines() ++ with open(entry, "w", encoding="utf8") as f: ++ for line in lines: ++ if line.startswith('options '): ++ f.write(f"{line} {' '.join(kopts)}\n") ++ else: ++ f.write(f"{line}\n") ++ assert len(entries) != 0 ++ print(f"Added {','.join(kopts)} to: {','.join(entries)}") ++ return 0 ++ ++ ++if __name__ == '__main__': ++ args = osbuild.api.arguments() ++ r = main(args["paths"], args["tree"], args["options"]) ++ sys.exit(r) +-- +2.41.0 + diff --git a/src/cmd-buildextend-metal b/src/cmd-buildextend-metal index 990210bf57..804314d552 100755 --- a/src/cmd-buildextend-metal +++ b/src/cmd-buildextend-metal @@ -262,9 +262,15 @@ cat "${image_json}" image-dynamic.json | jq -s add > image-for-disk.json platforms_json="${workdir}/tmp/platforms.json" yaml2json "${configdir}/platforms.yaml" "${platforms_json}" -if [ "${image_type}" == "qemu" ] && [ "${COSA_USE_OSBUILD:-}" != "" ]; then - runvm -- /usr/lib/coreos-assembler/runvm-osbuild \ - "${ostree_repo}" "${ref}" \ +# Currently we only support OSBuild for qemu and metal disk images +if [ "${image_type}" == "qemu" ] || [ "${image_type}" == "metal" ]; then + OSBUILD_SUPPORTED=1 +fi + +# Run with OSBuild if it's supported and requested, otherwise use create_disk +if [ "${OSBUILD_SUPPORTED:-}" != "" ] && [ "${COSA_USE_OSBUILD:-}" != "" ]; then + runvm_with_cache -- /usr/lib/coreos-assembler/runvm-osbuild \ + "${ostree_repo}" "${ref}" ${image_type} \ /usr/lib/coreos-assembler/coreos.osbuild.mpp.yaml \ "${path}.tmp" else diff --git a/src/cmdlib.sh b/src/cmdlib.sh index cccf7c0d46..bdaf1d639e 100755 --- a/src/cmdlib.sh +++ b/src/cmdlib.sh @@ -706,6 +706,11 @@ runvm() { # include COSA in the image find /usr/lib/coreos-assembler/ -type f > "${vmpreparedir}/hostfiles" + # include new patched in osbuild stage in the image. + # can drop this once osbuild v100 is out. + # https://github.com/osbuild/osbuild/pull/1429 + echo /usr/lib/osbuild/stages/org.osbuild.kernel-cmdline.bls-append >> "${vmpreparedir}/hostfiles" + # and include all GPG keys find /etc/pki/rpm-gpg/ -type f >> "${vmpreparedir}/hostfiles" diff --git a/src/coreos.osbuild.mpp.yaml b/src/coreos.osbuild.mpp.yaml index 3b825ce591..e04e01ed34 100644 --- a/src/coreos.osbuild.mpp.yaml +++ b/src/coreos.osbuild.mpp.yaml @@ -1,6 +1,6 @@ version: '2' mpp-vars: - release: 38 + filename: $filename mpp-define-image: id: image #10G @@ -28,7 +28,7 @@ mpp-define-image: type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 uuid: CA7D7CCB-63ED-4C53-861C-1742536059CC pipelines: - - name: image-tree + - name: tree source-epoch: 1659397331 stages: - type: org.osbuild.ostree.init-fs @@ -57,9 +57,6 @@ pipelines: - /boot/efi kernel_opts: - rw - - console=tty0 - - console=ttyS0 - - ignition.platform.id=qemu - '$ignition_firstboot' inputs: commits: @@ -88,7 +85,7 @@ pipelines: write_defaults: false greenboot: false ignition: true - - name: image + - name: raw-image stages: - type: org.osbuild.truncate options: @@ -151,7 +148,7 @@ pipelines: type: org.osbuild.tree origin: org.osbuild.pipeline references: - - name:image-tree + - name:tree options: paths: - from: input://tree/ @@ -211,7 +208,87 @@ pipelines: number: mpp-format-int: '{image.layout[''boot''].index}' path: /grub2 - - name: qcow2 + - name: raw-metal-image + stages: + - type: org.osbuild.copy + inputs: + tree: + type: org.osbuild.tree + origin: org.osbuild.pipeline + references: + - name:raw-image + options: + paths: + - from: input://tree/disk.img + to: tree:///disk.img + - type: org.osbuild.kernel-cmdline.bls-append + options: + bootpath: mount:/// + kernel_opts: + - ignition.platform.id=metal + devices: + boot: + type: org.osbuild.loopback + options: + filename: disk.img + start: + mpp-format-int: '{image.layout[''boot''].start}' + size: + mpp-format-int: '{image.layout[''boot''].size}' + mounts: + - name: boot + type: org.osbuild.ext4 + source: boot + target: / + - name: raw-qemu-image + stages: + - type: org.osbuild.copy + inputs: + tree: + type: org.osbuild.tree + origin: org.osbuild.pipeline + references: + - name:raw-image + options: + paths: + - from: input://tree/disk.img + to: tree:///disk.img + - type: org.osbuild.kernel-cmdline.bls-append + options: + bootpath: mount:/// + kernel_opts: + - console=tty0 + - console=ttyS0,115200n8 + - ignition.platform.id=qemu + devices: + boot: + type: org.osbuild.loopback + options: + filename: disk.img + start: + mpp-format-int: '{image.layout[''boot''].start}' + size: + mpp-format-int: '{image.layout[''boot''].size}' + mounts: + - name: boot + type: org.osbuild.ext4 + source: boot + target: / + - name: metal + stages: + - type: org.osbuild.copy + inputs: + tree: + type: org.osbuild.tree + origin: org.osbuild.pipeline + references: + - name:raw-metal-image + options: + paths: + - from: input://tree/disk.img + to: + mpp-format-string: 'tree:///{filename}' + - name: qemu stages: - type: org.osbuild.qemu inputs: @@ -219,10 +296,11 @@ pipelines: type: org.osbuild.files origin: org.osbuild.pipeline references: - name:image: + name:raw-qemu-image: file: disk.img options: - filename: disk.qcow2 + filename: + mpp-format-string: '{filename}' format: type: qcow2 compat: '1.1' diff --git a/src/runvm-osbuild b/src/runvm-osbuild index 92328a7551..42c71957a9 100755 --- a/src/runvm-osbuild +++ b/src/runvm-osbuild @@ -3,28 +3,36 @@ set -eux -o pipefail repo=$1 ref=$2 -mppyaml=$3 -path=$4 +platform=$3 +mppyaml=$4 +path=$5 +filename=$(basename "$path") # Since it doesn't exist create loop-control mknod /dev/loop-control c 10 237 -# get away from the virtiofs share because the xattrs that -# are written out by the ostree deploy will cause SELinux denials. -mkdir /root/osbuild && cd /root/osbuild +# Tell osbuild to write out artifacts into a file in the root +# filesystem of the supermin VM, which is ephemeral. +mkdir /var/osbuild +outdir=/var/osbuild/out # Run through the preprocessor osbuild-mpp \ -D ref=\""${ref}"\" \ -D repourl=\""file://${repo}"\" \ + -D filename=\""${filename}"\" \ "${mppyaml}" \ processed.json # Build the image -osbuild --store store/ \ - --output-directory out/ \ - --export qcow2 processed.json +osbuild \ + --out "$outdir" \ + --store cache/osbuild/store/ \ + --cache-max-size 9GiB \ + --checkpoint tree \ + --checkpoint raw-image \ + --export "$platform" processed.json # Copy it out to the specified location -cp out/qcow2/disk.qcow2 "${path}" +cp "${outdir}/${platform}/${filename}" "${path}"