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.
This commit is contained in:
Luke Yang 2024-01-22 10:28:01 -05:00 committed by Dusty Mabe
parent bd6b8ffb83
commit 477a21043e
3 changed files with 228 additions and 0 deletions

95
stages/org.osbuild.chattr Executable file
View file

@ -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)

View file

@ -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"
}
}
}
]
}
]
},

View file

@ -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: