#!/usr/bin/python3 """ OSTree deployment mount service This mount service will setup all needed bind mounts so that a given `tree` will look like an active OSTree deployment, very much as OSTree does during early boot. More specifically it will: - setup the sysroot bindmount to the deployment - setup the shared var directory - bind the boot directory into the deployment Host commands used: mount """ import os import sys import subprocess from typing import Dict from osbuild import mounts from osbuild.util import ostree SCHEMA_2 = """ "additionalProperties": false, "required": ["name", "type"], "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "options": { "type": "object", "required": ["deployment"], "properties": { "deployment": { "type": "object", "additionalProperties": false, "required": ["osname", "ref"], "properties": { "osname": { "description": "Name of the stateroot to be used in the deployment", "type": "string" }, "ref": { "description": "OStree ref to create and use for deployment", "type": "string" }, "serial": { "description": "The deployment serial (usually '0')", "type": "number", "default": 0 } } } } } } """ class OSTreeDeploymentMount(mounts.MountService): def __init__(self, args): super().__init__(args) self.mountpoint = None self.check = False @staticmethod def bind_mount(source, target): subprocess.run([ "mount", "--bind", "--make-private", source, target, ], check=True) def mount(self, args: Dict): tree = args["tree"] options = args["options"] deployment = options["deployment"] osname = deployment["osname"] ref = deployment["ref"] serial = deployment.get("serial", 0) root = ostree.deployment_path(tree, osname, ref, serial) print(f"Deployment root at '{os.path.relpath(root, tree)}'") var = os.path.join(tree, "ostree", "deploy", osname, "var") boot = os.path.join(tree, "boot") self.mountpoint = root self.bind_mount(root, root) # prepare to move it later self.bind_mount(tree, os.path.join(root, "sysroot")) self.bind_mount(var, os.path.join(root, "var")) self.bind_mount(boot, os.path.join(root, "boot")) subprocess.run([ "mount", "--move", root, tree, ], check=True) self.mountpoint = tree self.check = True return None def umount(self): if not self.mountpoint: return subprocess.run(["sync", "-f", self.mountpoint], check=self.check) subprocess.run(["umount", "-R", self.mountpoint], check=self.check) self.mountpoint = None def main(): service = OSTreeDeploymentMount.from_args(sys.argv[1:]) service.main() if __name__ == '__main__': main()