osbuild.py: separate tree from build root

There's no reason to conflate the two. This allows us to build on
something other than a tmpfs.
This commit is contained in:
Lars Karlitski 2019-06-14 19:48:42 +02:00
parent d43fe388a0
commit bd87038210
2 changed files with 51 additions and 30 deletions

View file

@ -17,7 +17,7 @@ def run_interactive(pipeline_path, input_dir, output_dir):
with open(pipeline_path) as f:
pipeline = json.load(f)
with osbuild.BuildRoot("/run/osbuild") as buildroot:
with osbuild.BuildRoot() as buildroot, osbuild.tmpfs() as tree:
for i, stage in enumerate(pipeline["stages"], start=1):
name = stage["name"]
options = stage.get("options", {})
@ -26,7 +26,7 @@ def run_interactive(pipeline_path, input_dir, output_dir):
print("Inspect with:")
print(f"\t# nsenter -a --wd=/root -t `machinectl show {buildroot.machine_name} -p Leader --value`")
print()
buildroot.run_stage(name, options, input_dir)
buildroot.run_stage(name, tree, options, input_dir)
assembler = pipeline.get("assembler")
if assembler:
@ -37,7 +37,7 @@ def run_interactive(pipeline_path, input_dir, output_dir):
print("Inspect with:")
print(f"\t# nsenter -a --wd=/root -t `machinectl show {buildroot.machine_name} -p Leader --value`")
print()
buildroot.run_assembler(name, options, output_dir)
buildroot.run_assembler(name, tree, options, input_dir, output_dir)
if __name__ == "__main__":

View file

@ -8,7 +8,8 @@ import tempfile
__all__ = [
"StageFailed",
"BuildRoot"
"BuildRoot",
"tmpfs"
]
@ -23,17 +24,41 @@ class StageFailed(Exception):
self.returncode = returncode
class BuildRoot:
def __init__(self, path=None):
self.buildroot = tempfile.mkdtemp(prefix="osbuild-buildroot-", dir=path)
self.buildroot_mounted = False
self.tree = tempfile.mkdtemp(prefix="osbuild-tree-", dir=path)
self.tree_mounted = False
class tmpfs:
def __init__(self, path="/run/osbuild"):
self.root = tempfile.mkdtemp(prefix="osbuild-tmpfs-", dir=path)
self.mounted = False
try:
subprocess.run(["mount", "-o", "bind,ro", "/", self.buildroot], check=True)
self.tree_mounted = True
subprocess.run(["mount", "-t", "tmpfs", "tmpfs", self.tree], check=True)
self.buildroot_mounted = True
subprocess.run(["mount", "-t", "tmpfs", "tmpfs", self.root], check=True)
self.mounted = True
except subprocess.CalledProcessError:
self.unmount()
def unmount(self):
if not self.root:
return
if self.mounted:
subprocess.run(["umount", "--lazy", self.root], check=True)
os.rmdir(self.root)
self.root = None
def __del__(self):
self.unmount()
def __enter__(self):
return self.root
def __exit__(self, exc_type, exc_value, exc_tb):
self.unmount()
class BuildRoot:
def __init__(self, path="/run/osbuild"):
self.root = tempfile.mkdtemp(prefix="osbuild-buildroot-", dir=path)
self.mounted = False
try:
subprocess.run(["mount", "-o", "bind,ro", "/", self.root], check=True)
self.mounted = True
except subprocess.CalledProcessError:
self.unmount()
raise
@ -43,19 +68,15 @@ class BuildRoot:
# us is '_', because all other characters used by
# TemporaryDirectory() are allowed. Replace it with 'L's
# (TemporaryDirectory() only uses lower-case characters)
self.machine_name = os.path.basename(self.buildroot).replace("_", "L")
self.machine_name = os.path.basename(self.root).replace("_", "L")
def unmount(self):
if self.tree:
if self.tree_mounted:
subprocess.run(["umount", "--lazy", self.tree], check=True)
os.rmdir(self.tree)
self.tree = None
if self.buildroot:
if self.buildroot_mounted:
subprocess.run(["umount", "--lazy", self.buildroot], check=True)
os.rmdir(self.buildroot)
self.buildroot = None
if not self.root:
return
if self.mounted:
subprocess.run(["umount", "--lazy", self.root], check=True)
os.rmdir(self.root)
self.root = None
def run(self, argv, binds=[], readonly_binds=[], *args, **kwargs):
return subprocess.run([
@ -65,7 +86,7 @@ class BuildRoot:
"--link-journal=no",
"--volatile=yes",
f"--machine={self.machine_name}",
f"--directory={self.buildroot}",
f"--directory={self.root}",
f"--bind-ro=/etc/pki",
f"--bind={libdir}/osbuild-run:/run/osbuild/osbuild-run",
*[f"--bind={b}" for b in binds],
@ -73,7 +94,7 @@ class BuildRoot:
"/run/osbuild/osbuild-run",
] + argv, *args, **kwargs)
def run_stage(self, name, options={}, input_dir=None):
def run_stage(self, name, tree, options={}, input_dir=None):
options = {
**options,
"tree": "/run/osbuild/tree",
@ -81,7 +102,7 @@ class BuildRoot:
}
robinds = [f"{libdir}/stages/{name}:/run/osbuild/{name}"]
binds = [f"{self.tree}:/run/osbuild/tree"]
binds = [f"{tree}:/run/osbuild/tree"]
if input_dir:
robinds.append(f"{input_dir}:/run/osbuild/input")
options["input_dir"] = "/run/osbuild/input"
@ -91,7 +112,7 @@ class BuildRoot:
except subprocess.CalledProcessError as error:
raise StageFailed(name, error.returncode)
def run_assembler(self, name, options, input_dir=None, output_dir=None):
def run_assembler(self, name, tree, options={}, input_dir=None, output_dir=None):
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir)
@ -102,7 +123,7 @@ class BuildRoot:
"output_dir": None
}
robinds = [
f"{self.tree}:/run/osbuild/tree",
f"{tree}:/run/osbuild/tree",
f"{libdir}/assemblers/{name}:/run/osbuild/{name}"
]
binds = []