From d67fa48c170a0093807b12d674f13b175ba9d59b Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 12 Sep 2024 16:43:45 +0200 Subject: [PATCH] stages: fix btrfs subvolume creation under subdirectories The code currently does not support btrfs subvolumes that are not directly under the root directory. This commit fixes this by adding `-p` to `btrfs subvolume create` and adding an integration test. Closes: https://github.com/osbuild/osbuild/issues/1882 --- stages/org.osbuild.btrfs.subvol | 2 +- stages/test/test_btrfs_subvol.py | 46 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 stages/test/test_btrfs_subvol.py diff --git a/stages/org.osbuild.btrfs.subvol b/stages/org.osbuild.btrfs.subvol index 20bb61b7..8259cea9 100755 --- a/stages/org.osbuild.btrfs.subvol +++ b/stages/org.osbuild.btrfs.subvol @@ -13,7 +13,7 @@ def main(paths, options): name = vol["name"].lstrip("/") subvol = os.path.join(volume, name) - cmd = ["btrfs", "subvolume", "create", subvol] + cmd = ["btrfs", "subvolume", "create", "-p", subvol] subprocess.run(cmd, encoding='utf-8', check=True) diff --git a/stages/test/test_btrfs_subvol.py b/stages/test/test_btrfs_subvol.py new file mode 100644 index 00000000..3733da47 --- /dev/null +++ b/stages/test/test_btrfs_subvol.py @@ -0,0 +1,46 @@ +#!/usr/bin/python3 + +import contextlib +import os +import subprocess + +import pytest + +from osbuild.testutil import has_executable + +STAGE_NAME = "org.osbuild.btrfs.subvol" + + +def make_btrfs_disk(tmp_path): + fake_disk_path = tmp_path / "fake.img" + with fake_disk_path.open("w") as fp: + fp.truncate(110 * 1024 * 1024) + subprocess.run(["mkfs.btrfs", fake_disk_path], check=True) + return fake_disk_path + + +@pytest.mark.skipif(os.getuid() != 0, reason="needs root") +@pytest.mark.skipif(not has_executable("mkfs.btrfs"), reason="need mkfs.btrfs") +def test_btrfs_subvol_integration(tmp_path, stage_module): + fake_disk_path = make_btrfs_disk(tmp_path) + fake_disk_mnt = tmp_path / "mnt" + fake_disk_mnt.mkdir() + with contextlib.ExitStack() as cm: + subprocess.run(["mount", fake_disk_path, fake_disk_mnt], check=True) + cm.callback(subprocess.run, ["umount", fake_disk_mnt], check=True) + + paths = { + "mounts": fake_disk_mnt, + } + options = { + "subvolumes": [ + {"name": "/asubvol"}, + {"name": "/subvols/root"}, + ], + } + stage_module.main(paths, options) + + output = subprocess.check_output([ + "btrfs", "subvolume", "list", fake_disk_mnt], encoding="utf-8") + assert "path asubvol\n" in output + assert "path subvols/root\n" in output