osbuild.py: separate BuildRoot.run() from Stage.run()
Make BuildRoot.run() a method that bind-mounts a binary into the build root and runs it. It has the same API as subprocess.run(). Move stage- and assembler-specific code to Stage.run() and Assembler.run().
This commit is contained in:
parent
65151e22ff
commit
75aab4600c
1 changed files with 66 additions and 43 deletions
109
osbuild.py
109
osbuild.py
|
|
@ -9,11 +9,12 @@ import tempfile
|
|||
|
||||
|
||||
__all__ = [
|
||||
"StageFailed",
|
||||
"Assembler",
|
||||
"AssemblerFailed",
|
||||
"BuildRoot",
|
||||
"Pipeline",
|
||||
"Stage"
|
||||
"StageFailed",
|
||||
"tmpfs"
|
||||
]
|
||||
|
||||
|
|
@ -34,6 +35,13 @@ class StageFailed(Exception):
|
|||
self.output = output
|
||||
|
||||
|
||||
class AssemblerFailed(Exception):
|
||||
def __init__(self, assembler, returncode, output):
|
||||
self.assembler = assembler
|
||||
self.returncode = returncode
|
||||
self.output = output
|
||||
|
||||
|
||||
class tmpfs:
|
||||
def __init__(self, path="/run/osbuild"):
|
||||
self.root = tempfile.mkdtemp(prefix="osbuild-tmpfs-", dir=path)
|
||||
|
|
@ -88,37 +96,30 @@ class BuildRoot:
|
|||
os.rmdir(self.root)
|
||||
self.root = None
|
||||
|
||||
def run(self, name, args, binds=[], readonly_binds=[], interactive=False):
|
||||
try:
|
||||
r = subprocess.run([
|
||||
"systemd-nspawn",
|
||||
"--quiet",
|
||||
"--as-pid2",
|
||||
"--link-journal=no",
|
||||
"--volatile=yes",
|
||||
"--property=DeviceAllow=/dev/loop-control rw",
|
||||
"--property=DeviceAllow=block-loop rw",
|
||||
"--property=DeviceAllow=block-blkext rw",
|
||||
f"--machine={self.machine_name}",
|
||||
f"--directory={self.root}",
|
||||
f"--bind={libdir}/osbuild-run:/run/osbuild/osbuild-run",
|
||||
*[f"--bind={b}" for b in binds],
|
||||
*[f"--bind-ro={b}" for b in readonly_binds],
|
||||
"/run/osbuild/osbuild-run",
|
||||
f"/run/osbuild/{name}",
|
||||
],
|
||||
input=json.dumps(args),
|
||||
encoding="utf-8",
|
||||
stdout=subprocess.PIPE if not interactive else None,
|
||||
stderr=subprocess.STDOUT if not interactive else None,
|
||||
check=True)
|
||||
except subprocess.CalledProcessError as error:
|
||||
raise StageFailed(name, error.returncode, error.stdout)
|
||||
def run(self, argv, binds=[], readonly_binds=[], **kwargs):
|
||||
"""Runs a command in the buildroot.
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"output": r.stdout
|
||||
}
|
||||
Its arguments mean the same as those for subprocess.run().
|
||||
"""
|
||||
command = "/run/osbuild/" + os.path.basename(argv[0])
|
||||
return subprocess.run([
|
||||
"systemd-nspawn",
|
||||
"--quiet",
|
||||
"--as-pid2",
|
||||
"--link-journal=no",
|
||||
"--volatile=yes",
|
||||
"--property=DeviceAllow=/dev/loop-control rw",
|
||||
"--property=DeviceAllow=block-loop rw",
|
||||
"--property=DeviceAllow=block-blkext rw",
|
||||
f"--machine={self.machine_name}",
|
||||
f"--directory={self.root}",
|
||||
f"--bind={libdir}/osbuild-run:/run/osbuild/osbuild-run",
|
||||
*[f"--bind={b}" for b in binds],
|
||||
*[f"--bind-ro={b}" for b in [argv[0] + ":" + command, *readonly_binds]],
|
||||
"/run/osbuild/osbuild-run",
|
||||
command
|
||||
] + argv[1:], **kwargs
|
||||
)
|
||||
|
||||
def __del__(self):
|
||||
self.unmount()
|
||||
|
|
@ -170,12 +171,25 @@ class Stage:
|
|||
"options": self.options,
|
||||
}
|
||||
|
||||
robinds = [f"{libdir}/stages/{self.name}:/run/osbuild/{self.name}"]
|
||||
robinds.extend(_get_system_resources_from_etc(self.resources))
|
||||
r = buildroot.run(
|
||||
[f"{libdir}/stages/{self.name}"],
|
||||
binds=[
|
||||
f"{tree}:/run/osbuild/tree",
|
||||
"/dev:/dev"
|
||||
],
|
||||
readonly_binds=_get_system_resources_from_etc(self.resources),
|
||||
encoding="utf-8",
|
||||
input=json.dumps(args),
|
||||
stdout=None if interactive else subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
if r.returncode != 0:
|
||||
raise AssemblerFailed(self.name, r.returncode, r.stdout)
|
||||
|
||||
binds = [f"{tree}:/run/osbuild/tree", "/dev:/dev"]
|
||||
|
||||
return buildroot.run(self.name, args, binds, robinds, interactive)
|
||||
return {
|
||||
"name": self.name,
|
||||
"output": r.stdout
|
||||
}
|
||||
|
||||
|
||||
class Assembler:
|
||||
|
|
@ -196,18 +210,27 @@ class Assembler:
|
|||
"tree": "/run/osbuild/tree",
|
||||
"options": self.options,
|
||||
}
|
||||
robinds = [
|
||||
f"{tree}:/run/osbuild/tree",
|
||||
f"{libdir}/assemblers/{self.name}:/run/osbuild/{self.name}"
|
||||
]
|
||||
robinds.extend(_get_system_resources_from_etc(self.resources))
|
||||
binds = ["/dev:/dev"]
|
||||
|
||||
binds = ["/dev:/dev"]
|
||||
if output_dir:
|
||||
binds.append(f"{output_dir}:/run/osbuild/output")
|
||||
args["output_dir"] = "/run/osbuild/output"
|
||||
|
||||
return buildroot.run(self.name, args, binds, robinds, interactive)
|
||||
r = buildroot.run(
|
||||
[f"{libdir}/assemblers/{self.name}"],
|
||||
binds=binds,
|
||||
readonly_binds=[f"{tree}:/run/osbuild/tree"] + _get_system_resources_from_etc(self.resources),
|
||||
encoding="utf-8",
|
||||
input=json.dumps(args),
|
||||
stdout=None if interactive else subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
if r.returncode != 0:
|
||||
raise StageFailed(self.name, r.returncode, r.stdout)
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"output": r.stdout
|
||||
}
|
||||
|
||||
|
||||
class Pipeline:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue