Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -192,25 +192,30 @@ write_archive_info() {
}

patch_osbuild() {
# Add 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.
return 0

# # To make it easier to apply patches we'll move around the osbuild
# # code on the system first:
# rmdir /usr/lib/osbuild/osbuild
# mv /usr/lib/python3.13/site-packages/osbuild /usr/lib/osbuild/
# mkdir /usr/lib/osbuild/tools
# mv /usr/bin/osbuild-mpp /usr/lib/osbuild/tools/

# # Now all the software is under the /usr/lib/osbuild dir and we can patch
# patch -d /usr/lib/osbuild -p1 < /usr/lib/coreos-assembler/src/my-git-commit.patch

# # And then move the files back; supermin appliance creation will need it back
# # in the places delivered by the RPM.
# mv /usr/lib/osbuild/tools/osbuild-mpp /usr/bin/osbuild-mpp
# mv /usr/lib/osbuild/osbuild /usr/lib/python3.13/site-packages/osbuild
# mkdir -p /usr/lib/osbuild/osbuild
# Add 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.

# To make it easier to apply patches we'll move around the osbuild
# code on the system first:
rmdir /usr/lib/osbuild/osbuild
mv /usr/lib/python3.13/site-packages/osbuild /usr/lib/osbuild/
mkdir -p /usr/lib/osbuild/tools
mv /usr/bin/osbuild-mpp /usr/lib/osbuild/tools/

# Now all the software is under the /usr/lib/osbuild dir and we can patch
cat \
/usr/lib/coreos-assembler/0001-osbuild-util-containers.py-add-container_mount-funct.patch \
/usr/lib/coreos-assembler/0002-osbuild-util-containers.py-rename-variable.patch \
/usr/lib/coreos-assembler/0003-osbuild-util-containers.py-drop-copy-when-using-cont.patch \
/usr/lib/coreos-assembler/0004-drop-remove_signatures-from-org.osbuild.container-de.patch \
/usr/lib/coreos-assembler/0005-tools-osbuild-mpp-support-mpp-resolve-for-org.osbuil.patch |
patch -d /usr/lib/osbuild -p1

# And then move the files back; supermin appliance creation will need it back
# in the places delivered by the RPM.
mv /usr/lib/osbuild/tools/osbuild-mpp /usr/bin/osbuild-mpp
mv /usr/lib/osbuild/osbuild /usr/lib/python3.13/site-packages/osbuild
mkdir -p /usr/lib/osbuild/osbuild
}

if [ $# -ne 0 ]; then
Expand Down
145 changes: 145 additions & 0 deletions src/0001-osbuild-util-containers.py-add-container_mount-funct.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
From 701fa40dfce9a70c1dafdee32907a154463a1a44 Mon Sep 17 00:00:00 2001
From: Dusty Mabe <[email protected]>
Date: Thu, 9 Oct 2025 22:05:44 -0400
Subject: [PATCH 1/5] osbuild/util/containers.py: add container_mount()
functionality

As prep for a later patch this moves the container image mounting code
from stages/org.osbuild.container-deploy into the containers library.

This commit also removes the associated unit test since it wasn't doing
much and also there doesn't seem to be a place for unit testing
osbuild/util/containers.py.
---
osbuild/util/containers.py | 42 ++++++++++++++++++++++++++-
stages/org.osbuild.container-deploy | 45 ++---------------------------
2 files changed, 43 insertions(+), 44 deletions(-)

diff --git a/osbuild/util/containers.py b/osbuild/util/containers.py
index 49eceee2..352c5c8e 100644
--- a/osbuild/util/containers.py
+++ b/osbuild/util/containers.py
@@ -1,8 +1,10 @@
import json
import os
+import random
+import string
import subprocess
import tempfile
-from contextlib import contextmanager
+from contextlib import ExitStack, contextmanager

from osbuild.util.mnt import MountGuard, MountPermissions

@@ -184,3 +186,41 @@ def container_source(image):
# that the inner ctx manager won't be cleaned up until the execution returns to this ctx manager.
with container_source_fn(image, image_filepath, container_format) as image_source:
yield image_name, image_source
+
+
+@contextmanager
+def container_mount(image, remove_signatures=False):
+ # Helper function for doing the `podman image mount`
+ @contextmanager
+ def _mount_container(image_tag):
+ cmd = ["podman", "image", "mount", image_tag],
+ result = subprocess.run(cmd, encoding="utf-8", check=False,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if result.returncode != 0:
+ code = result.returncode
+ msg = result.stderr.strip()
+ raise RuntimeError(f"Failed to mount image ({code}): {msg}")
+ try:
+ yield result.stdout.strip()
+ finally:
+ cmd = ["podman", "image", "umount", image_tag],
+ subprocess.run(cmd, check=True)
+
+ # We cannot use a tmpdir as storage here because of
+ # https://github.com/containers/storage/issues/1779 so instead
+ # just pick a random suffix. This runs inside bwrap which gives a
+ # tmp /var so it does not really matter much.
+ tmp_image_tag = "tmp-container-mount-" + "".join(random.choices(string.digits, k=14))
+ with container_source(image) as (_, source):
+ with ExitStack() as cm:
+ cm.callback(subprocess.run, ["podman", "rmi", tmp_image_tag], check=True)
+ # skopeo needs /var/tmp but the bwrap env is minimal and may not have it
+ os.makedirs("/var/tmp", mode=0o1777, exist_ok=True)
+ cmd = ["skopeo", "copy"]
+ if remove_signatures:
+ cmd.append("--remove-signatures")
+ cmd.extend([source, f"containers-storage:{tmp_image_tag}"])
+ subprocess.run(cmd, check=True)
+
+ with _mount_container(tmp_image_tag) as container_mountpoint:
+ yield container_mountpoint
diff --git a/stages/org.osbuild.container-deploy b/stages/org.osbuild.container-deploy
index 29fe7b97..f933ac73 100755
--- a/stages/org.osbuild.container-deploy
+++ b/stages/org.osbuild.container-deploy
@@ -1,8 +1,4 @@
#!/usr/bin/python3
-import contextlib
-import os
-import random
-import string
import subprocess
import sys

@@ -10,51 +6,14 @@ import osbuild.api
from osbuild.util import containers


[email protected]
-def mount_container(image_tag):
- result = subprocess.run(
- ["podman", "image", "mount", image_tag],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- encoding="utf-8",
- check=False,
- )
- if result.returncode != 0:
- code = result.returncode
- msg = result.stderr.strip()
- raise RuntimeError(f"Failed to mount image ({code}): {msg}")
- try:
- yield result.stdout.strip()
- finally:
- subprocess.run(
- ["podman", "image", "umount", image_tag],
- check=True,
- )
-
-
def main(inputs, tree, options):
images = containers.parse_containers_input(inputs)
assert len(images) == 1
image = list(images.values())[0]
remove_signatures = options.get("remove-signatures")

- # skopeo needs /var/tmp but the bwrap env is minimal and may not have it
- os.makedirs("/var/tmp", mode=0o1777, exist_ok=True)
- # We cannot use a tmpdir as storage here because of
- # https://github.com/containers/storage/issues/1779 so instead
- # just pick a random suffix. This runs inside bwrap which gives a
- # tmp /var so it does not really matter much.
- image_tag = "tmp-container-deploy-" + "".join(random.choices(string.digits, k=14))
- with contextlib.ExitStack() as cm:
- cm.callback(subprocess.run, ["podman", "rmi", image_tag], check=True)
- with containers.container_source(image) as (_, source):
- cmd = ["skopeo", "copy"]
- if remove_signatures:
- cmd.append("--remove-signatures")
- cmd.extend([source, f"containers-storage:{image_tag}"])
- subprocess.run(cmd, check=True)
- with mount_container(image_tag) as img:
- subprocess.run(["cp", "-a", f"{img}/.", f"{tree}/"], check=True)
+ with containers.container_mount(image, remove_signatures) as container_mountpoint:
+ subprocess.run(["cp", "-a", f"{container_mountpoint}/.", f"{tree}/"], check=True)
# postprocess the tree, would be nicer to filter before already
for exclude in options.get("exclude", []):
subprocess.run(["rm", "-rf", f"{tree}/{exclude}"], check=True)
--
2.51.0

40 changes: 40 additions & 0 deletions src/0002-osbuild-util-containers.py-rename-variable.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
From 81b9bd29075c004c48a5de685904328f657f33bd Mon Sep 17 00:00:00 2001
From: Dusty Mabe <[email protected]>
Date: Fri, 10 Oct 2025 09:04:21 -0400
Subject: [PATCH 2/5] osbuild/util/containers.py: rename variable

This is really a name and not a tag (it doesn't include :tag) so let's
rename the variable to be a little more clear.
---
osbuild/util/containers.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/osbuild/util/containers.py b/osbuild/util/containers.py
index 352c5c8e..9e321315 100644
--- a/osbuild/util/containers.py
+++ b/osbuild/util/containers.py
@@ -210,17 +210,17 @@ def container_mount(image, remove_signatures=False):
# https://github.com/containers/storage/issues/1779 so instead
# just pick a random suffix. This runs inside bwrap which gives a
# tmp /var so it does not really matter much.
- tmp_image_tag = "tmp-container-mount-" + "".join(random.choices(string.digits, k=14))
+ tmp_image_name = "tmp-container-mount-" + "".join(random.choices(string.digits, k=14))
with container_source(image) as (_, source):
with ExitStack() as cm:
- cm.callback(subprocess.run, ["podman", "rmi", tmp_image_tag], check=True)
+ cm.callback(subprocess.run, ["podman", "rmi", tmp_image_name], check=True)
# skopeo needs /var/tmp but the bwrap env is minimal and may not have it
os.makedirs("/var/tmp", mode=0o1777, exist_ok=True)
cmd = ["skopeo", "copy"]
if remove_signatures:
cmd.append("--remove-signatures")
- cmd.extend([source, f"containers-storage:{tmp_image_tag}"])
+ cmd.extend([source, f"containers-storage:{tmp_image_name}"])
subprocess.run(cmd, check=True)

- with _mount_container(tmp_image_tag) as container_mountpoint:
+ with _mount_container(tmp_image_name) as container_mountpoint:
yield container_mountpoint
--
2.51.0

110 changes: 110 additions & 0 deletions src/0003-osbuild-util-containers.py-drop-copy-when-using-cont.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
From dd484a371b04bb384d6d189b038d6c7997a3da44 Mon Sep 17 00:00:00 2001
From: Dusty Mabe <[email protected]>
Date: Wed, 15 Oct 2025 15:13:38 -0400
Subject: [PATCH 3/5] osbuild/util/containers.py: drop copy when using
containers-storage input

If we are just mounting the container then there's really no reason
we can't just `podman mount` it directly rather than copying it from
one local containers-storage to another.
---
osbuild/util/containers.py | 62 ++++++++++++++++++++++----------------
1 file changed, 36 insertions(+), 26 deletions(-)

diff --git a/osbuild/util/containers.py b/osbuild/util/containers.py
index 9e321315..06a47a0d 100644
--- a/osbuild/util/containers.py
+++ b/osbuild/util/containers.py
@@ -8,6 +8,9 @@ from contextlib import ExitStack, contextmanager

from osbuild.util.mnt import MountGuard, MountPermissions

+# use `/run/osbuild/containers/storage` for the host's containers-storage bind mount
+HOST_CONTAINERS_STORAGE = os.path.join(os.sep, "run", "osbuild", "containers", "storage")
+

def is_manifest_list(data):
"""Inspect a manifest determine if it's a multi-image manifest-list."""
@@ -118,10 +121,7 @@ def containers_storage_source(image, image_filepath, container_format):
storage_conf = image["data"]["storage"]
driver = storage_conf.get("driver", "overlay")

- # use `/run/osbuild/containers/storage` for the containers-storage bind mount
- # since this ostree-compatible and the stage that uses this will be run
- # inside a ostree-based build-root in `bootc-image-builder`
- storage_path = os.path.join(os.sep, "run", "osbuild", "containers", "storage")
+ storage_path = HOST_CONTAINERS_STORAGE
os.makedirs(storage_path, exist_ok=True)

with MountGuard() as mg:
@@ -192,10 +192,10 @@ def container_source(image):
def container_mount(image, remove_signatures=False):
# Helper function for doing the `podman image mount`
@contextmanager
- def _mount_container(image_tag):
- cmd = ["podman", "image", "mount", image_tag],
- result = subprocess.run(cmd, encoding="utf-8", check=False,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ def _mount_container(img, imagestore=None):
+ cmd = ["podman", f"--imagestore={imagestore}"] if imagestore else ["podman"]
+ result = subprocess.run(cmd + ["image", "mount", img], encoding="utf-8",
+ check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0:
code = result.returncode
msg = result.stderr.strip()
@@ -203,24 +203,34 @@ def container_mount(image, remove_signatures=False):
try:
yield result.stdout.strip()
finally:
- cmd = ["podman", "image", "umount", image_tag],
- subprocess.run(cmd, check=True)
-
- # We cannot use a tmpdir as storage here because of
- # https://github.com/containers/storage/issues/1779 so instead
- # just pick a random suffix. This runs inside bwrap which gives a
- # tmp /var so it does not really matter much.
- tmp_image_name = "tmp-container-mount-" + "".join(random.choices(string.digits, k=14))
+ subprocess.run(cmd + ["image", "umount", img], check=True)
+
with container_source(image) as (_, source):
with ExitStack() as cm:
- cm.callback(subprocess.run, ["podman", "rmi", tmp_image_name], check=True)
- # skopeo needs /var/tmp but the bwrap env is minimal and may not have it
- os.makedirs("/var/tmp", mode=0o1777, exist_ok=True)
- cmd = ["skopeo", "copy"]
- if remove_signatures:
- cmd.append("--remove-signatures")
- cmd.extend([source, f"containers-storage:{tmp_image_name}"])
- subprocess.run(cmd, check=True)
-
- with _mount_container(tmp_image_name) as container_mountpoint:
+ img = ""
+ imagestore = None
+ if image["data"]["format"] == 'containers-storage':
+ # In the case where we are container storage we don't need to
+ # skopeo copy. We already have access to a mounted container storage
+ # that has the image ready to use.
+ image_id = image["checksum"].split(":")[1]
+ img = image_id
+ imagestore = HOST_CONTAINERS_STORAGE
+ else:
+ # We cannot use a tmpdir as storage here because of
+ # https://github.com/containers/storage/issues/1779 so instead
+ # just pick a random suffix. This runs inside bwrap which gives a
+ # tmp /var so it does not really matter much.
+ tmp_image_name = "tmp-container-mount-" + "".join(random.choices(string.digits, k=14))
+ cm.callback(subprocess.run, ["podman", "rmi", tmp_image_name], check=True)
+ # skopeo needs /var/tmp but the bwrap env is minimal and may not have it
+ os.makedirs("/var/tmp", mode=0o1777, exist_ok=True)
+ cmd = ["skopeo", "copy"]
+ if remove_signatures:
+ cmd.append("--remove-signatures")
+ cmd.extend([source, f"containers-storage:{tmp_image_name}"])
+ subprocess.run(cmd, check=True)
+ img = tmp_image_name
+
+ with _mount_container(img, imagestore) as container_mountpoint:
yield container_mountpoint
--
2.51.0

Loading
Loading