From 477a21043eeb55468b1f75a9574e46e77cb5fdef Mon Sep 17 00:00:00 2001 From: Luke Yang Date: Mon, 22 Jan 2024 10:28:01 -0500 Subject: [PATCH] Create stages/org.osbuild.chattr stage Add or remove the immutable bit to the specified mount directory. The need we have for this right now is for the CoreOS builds where the immutable bit being set on an OSTree deployment root doesn't survive the `cp -a --reflink=auto` in the org.osbuild.copy stage when being copied from the directory tree into the mounted XFS filesystem we created on the disk image. Thus we have to workaround this loss of attribute by applying the attribute directly on the mounted filesystem from the disk. --- stages/org.osbuild.chattr | 95 +++++++++++++++++++ .../manifests/fedora-coreos-container.json | 79 +++++++++++++++ .../fedora-coreos-container.mpp.yaml | 54 +++++++++++ 3 files changed, 228 insertions(+) create mode 100755 stages/org.osbuild.chattr diff --git a/stages/org.osbuild.chattr b/stages/org.osbuild.chattr new file mode 100755 index 00000000..0bc8aa0e --- /dev/null +++ b/stages/org.osbuild.chattr @@ -0,0 +1,95 @@ +#!/usr/bin/python3 +""" +Runs `chattr` to set file/directory attributes. +""" + +import os +import subprocess +import sys +from typing import Dict +from urllib.parse import ParseResult, urlparse + +import osbuild.api + +SCHEMA_2 = r""" +"options": { + "additionalProperties": false, + "properties": { + "items": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^mount:\/\/[^\/]+\/|^tree:\/\/\/": { + "type": "object", + "required": ["immutable"], + "properties": { + "immutable": { + "type": "boolean", + "description": "Make the file/directory immutable", + "default": true + } + } + } + } + } + } +}, +"devices": { + "type": "object", + "additionalProperties": true +}, +"mounts": { + "type": "array" +} +""" + + +def parse_mount(url: ParseResult, args: Dict): + name = url.netloc + if name: + root = args["mounts"].get(name, {}).get("path") + if not root: + raise ValueError(f"Unknown mount '{name}'") + else: + root = args["paths"]["mounts"] + + return root + + +def parse_location(location, args): + url = urlparse(location) + + scheme = url.scheme + if scheme == "tree": + root = args["tree"] + elif scheme == "mount": + root = parse_mount(url, args) + else: + raise ValueError(f"Unsupported scheme '{scheme}'") + + assert url.path.startswith("/") + + path = os.path.relpath(url.path, "/") + path = os.path.join(root, path) + path = os.path.normpath(path) + + if url.path.endswith("/"): + path = os.path.join(path, ".") + + return path + + +def main(args, options): + for path, cmdargs in options["items"].items(): + immutable = cmdargs["immutable"] + dst = parse_location(path, args) + op = '+' if immutable else '-' + subprocess.run(["chattr", f"{op}i", dst], check=True) + + return 0 + + +if __name__ == '__main__': + _args = osbuild.api.arguments() + r = main(_args, _args["options"]) + sys.exit(r) diff --git a/test/data/manifests/fedora-coreos-container.json b/test/data/manifests/fedora-coreos-container.json index ad9a2461..fb56b861 100644 --- a/test/data/manifests/fedora-coreos-container.json +++ b/test/data/manifests/fedora-coreos-container.json @@ -736,6 +736,45 @@ "target": "/boot/efi" } ] + }, + { + "type": "org.osbuild.chattr", + "options": { + "items": { + "mount://root/": { + "immutable": true + } + } + }, + "devices": { + "disk": { + "type": "org.osbuild.loopback", + "options": { + "filename": "disk.img", + "partscan": true + } + } + }, + "mounts": [ + { + "name": "root", + "type": "org.osbuild.xfs", + "source": "disk", + "partition": 4, + "target": "/" + }, + { + "name": "ostree.deployment", + "type": "org.osbuild.ostree.deployment", + "options": { + "source": "mount", + "deployment": { + "ref": "ostree/1/1/0", + "osname": "fedora-coreos" + } + } + } + ] } ] }, @@ -945,6 +984,46 @@ "target": "/boot/efi" } ] + }, + { + "type": "org.osbuild.chattr", + "options": { + "items": { + "mount://root/": { + "immutable": true + } + } + }, + "devices": { + "disk": { + "type": "org.osbuild.loopback", + "options": { + "filename": "disk.img", + "partscan": true, + "sector-size": 4096 + } + } + }, + "mounts": [ + { + "name": "root", + "type": "org.osbuild.xfs", + "source": "disk", + "partition": 4, + "target": "/" + }, + { + "name": "ostree.deployment", + "type": "org.osbuild.ostree.deployment", + "options": { + "source": "mount", + "deployment": { + "ref": "ostree/1/1/0", + "osname": "fedora-coreos" + } + } + } + ] } ] }, diff --git a/test/data/manifests/fedora-coreos-container.mpp.yaml b/test/data/manifests/fedora-coreos-container.mpp.yaml index c50ab964..2494b867 100644 --- a/test/data/manifests/fedora-coreos-container.mpp.yaml +++ b/test/data/manifests/fedora-coreos-container.mpp.yaml @@ -265,6 +265,32 @@ pipelines: partition: mpp-format-int: '{image.layout[''EFI-SYSTEM''].partnum}' target: /boot/efi + - type: org.osbuild.chattr + options: + items: + mount://root/: + immutable: true + devices: + disk: + type: org.osbuild.loopback + options: + filename: disk.img + partscan: true + mounts: + - name: root + type: org.osbuild.xfs + source: disk + partition: + mpp-format-int: '{image.layout[''root''].partnum}' + target: / + - name: ostree.deployment + type: org.osbuild.ostree.deployment + options: + source: mount + deployment: + ref: ostree/1/1/0 + osname: + mpp-format-string: '{osname}' - name: raw-4k-image build: name:build stages: @@ -407,6 +433,34 @@ pipelines: partition: mpp-format-int: '{image4k.layout[''EFI-SYSTEM''].partnum}' target: /boot/efi + - type: org.osbuild.chattr + options: + items: + mount://root/: + immutable: true + devices: + disk: + type: org.osbuild.loopback + options: + filename: disk.img + partscan: true + sector-size: + mpp-format-int: "{four_k_sector_size}" + mounts: + - name: root + type: org.osbuild.xfs + source: disk + partition: + mpp-format-int: '{image4k.layout[''root''].partnum}' + target: / + - name: ostree.deployment + type: org.osbuild.ostree.deployment + options: + source: mount + deployment: + ref: ostree/1/1/0 + osname: + mpp-format-string: '{osname}' - name: raw-metal-image build: name:build stages: