mounts: support mounting partitions

This allows us to map in a whole disk as a loopback device with parition
scanning rather than slicing up the disk and creating several loopback
devices. Something like this:

```
      - type: org.osbuild.copy
        inputs:
          tree:
            type: org.osbuild.tree
            origin: org.osbuild.pipeline
            references:
              - name:tree
        options:
          paths:
            - from: input://tree/
              to: mount://root/
        devices:
          efi:
            type: org.osbuild.loopback
            options:
              filename: disk.img
              start:
                mpp-format-int: '{image.layout[''EFI-SYSTEM''].start}'
              size:
                mpp-format-int: '{image.layout[''EFI-SYSTEM''].size}'
          boot:
            type: org.osbuild.loopback
            options:
              filename: disk.img
              start:
                mpp-format-int: '{image.layout[''boot''].start}'
              size:
                mpp-format-int: '{image.layout[''boot''].size}'
          root:
            type: org.osbuild.loopback
            options:
              filename: disk.img
              start:
                mpp-format-int: '{image.layout[''root''].start}'
              size:
                mpp-format-int: '{image.layout[''root''].size}'
        mounts:
          - name: root
            type: org.osbuild.xfs
            source: root
            target: /
          - name: boot
            type: org.osbuild.ext4
            source: boot
            target: /boot
          - name: efi
            type: org.osbuild.fat
            source: efi
            target: /boot/efi
```

now becomes a little more simple:

```
      - type: org.osbuild.copy
        inputs:
          tree:
            type: org.osbuild.tree
            origin: org.osbuild.pipeline
            references:
              - name:tree
        options:
          paths:
            - from: input://tree/
              to: mount://root/
        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: boot
            type: org.osbuild.ext4
            source: disk
            partition:
              mpp-format-int: '{image.layout[''boot''].partnum}'
            target: /boot
          - name: efi
            type: org.osbuild.fat
            source: disk
            partition:
              mpp-format-int: '{image.layout[''EFI-SYSTEM''].partnum}'
            target: /boot/efi
```

Fixes https://github.com/osbuild/osbuild/issues/1495
This commit is contained in:
Dusty Mabe 2023-12-12 22:34:12 -05:00
parent f6d0a4a9ac
commit ce8408a9c6
12 changed files with 72 additions and 102 deletions

View file

@ -21,6 +21,10 @@ SCHEMA_2 = """
"source": { "source": {
"type": "string" "type": "string"
}, },
"partition": {
"description": "If the source device has partitions, the partition number, starting at one",
"type": "number"
},
"target": { "target": {
"type": "string" "type": "string"
}, },

View file

@ -21,6 +21,10 @@ SCHEMA_2 = """
"source": { "source": {
"type": "string" "type": "string"
}, },
"partition": {
"description": "If the source device has partitions, the partition number, starting at one",
"type": "number"
},
"target": { "target": {
"type": "string" "type": "string"
}, },

View file

@ -24,6 +24,10 @@ SCHEMA_2 = """
"target": { "target": {
"type": "string" "type": "string"
}, },
"partition": {
"description": "If the source device has partitions, the partition number, starting at one",
"type": "number"
},
"options": { "options": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,

View file

@ -21,6 +21,9 @@ SCHEMA_2 = """
"source": { "source": {
"type": "string" "type": "string"
}, },
"partition": {
"type": "number"
},
"target": { "target": {
"type": "string" "type": "string"
}, },

View file

@ -24,6 +24,10 @@ SCHEMA_2 = """
"target": { "target": {
"type": "string" "type": "string"
}, },
"partition": {
"description": "If the source device has partitions, the partition number, starting at one",
"type": "number"
},
"options": { "options": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,

View file

@ -286,6 +286,7 @@ def load_mount(description: Dict, index: Index, stage: Stage):
raise ValueError(f"Duplicated mount '{name}'") raise ValueError(f"Duplicated mount '{name}'")
source = description.get("source") source = description.get("source")
partition = description.get("partition")
target = description.get("target") target = description.get("target")
options = description.get("options", {}) options = description.get("options", {})
@ -296,7 +297,7 @@ def load_mount(description: Dict, index: Index, stage: Stage):
if not device: if not device:
raise ValueError(f"Unknown device '{source}' for mount '{name}'") raise ValueError(f"Unknown device '{source}' for mount '{name}'")
stage.add_mount(name, info, device, target, options) stage.add_mount(name, info, device, partition, target, options)
def load_stage(description: Dict, index: Index, pipeline: Pipeline, manifest: Manifest, source_refs): def load_stage(description: Dict, index: Index, pipeline: Pipeline, manifest: Manifest, source_refs):

View file

@ -23,10 +23,11 @@ class Mount:
A single mount with its corresponding options A single mount with its corresponding options
""" """
def __init__(self, name, info, device, target, options: Dict): def __init__(self, name, info, device, partition, target, options: Dict):
self.name = name self.name = name
self.info = info self.info = info
self.device = device self.device = device
self.partition = partition
self.target = target self.target = target
self.options = options self.options = options
self.id = self.calc_id() self.id = self.calc_id()
@ -71,6 +72,11 @@ class MountManager:
if relpath and os.path.exists(os.path.join('/dev', relpath)): if relpath and os.path.exists(os.path.join('/dev', relpath)):
source = os.path.join('/dev', relpath) source = os.path.join('/dev', relpath)
# If the user specified a partition then the filesystem to
# mount is actually on a partition of the disk.
if source and mount.partition:
source = f"{source}p{mount.partition}"
root = os.fspath(self.root) root = os.fspath(self.root)
args = { args = {

View file

@ -111,8 +111,8 @@ class Stage:
self.devices[name] = dev self.devices[name] = dev
return dev return dev
def add_mount(self, name, info, device, target, options): def add_mount(self, name, info, device, partition, target, options):
mount = Mount(name, info, device, target, options) mount = Mount(name, info, device, partition, target, options)
self.mounts[name] = mount self.mounts[name] = mount
return mount return mount

View file

@ -82,6 +82,9 @@
"target": { "target": {
"type": "string" "type": "string"
}, },
"partition": {
"type": "number"
},
"options": { "options": {
"type": "object", "type": "object",
"additionalProperties": true "additionalProperties": true

View file

@ -682,28 +682,11 @@
] ]
}, },
"devices": { "devices": {
"efi": { "disk": {
"type": "org.osbuild.loopback", "type": "org.osbuild.loopback",
"options": { "options": {
"filename": "disk.img", "filename": "disk.img",
"start": 4096, "partscan": true
"size": 260096
}
},
"boot": {
"type": "org.osbuild.loopback",
"options": {
"filename": "disk.img",
"start": 264192,
"size": 786432
}
},
"root": {
"type": "org.osbuild.loopback",
"options": {
"filename": "disk.img",
"start": 1050624,
"size": 4194304
} }
} }
}, },
@ -711,19 +694,22 @@
{ {
"name": "root", "name": "root",
"type": "org.osbuild.xfs", "type": "org.osbuild.xfs",
"source": "root", "source": "disk",
"partition": 4,
"target": "/" "target": "/"
}, },
{ {
"name": "boot", "name": "boot",
"type": "org.osbuild.ext4", "type": "org.osbuild.ext4",
"source": "boot", "source": "disk",
"partition": 3,
"target": "/boot" "target": "/boot"
}, },
{ {
"name": "efi", "name": "efi",
"type": "org.osbuild.fat", "type": "org.osbuild.fat",
"source": "efi", "source": "disk",
"partition": 2,
"target": "/boot/efi" "target": "/boot/efi"
} }
] ]
@ -884,30 +870,11 @@
] ]
}, },
"devices": { "devices": {
"efi": { "disk": {
"type": "org.osbuild.loopback", "type": "org.osbuild.loopback",
"options": { "options": {
"filename": "disk.img", "filename": "disk.img",
"start": 512, "partscan": true,
"size": 32512,
"sector-size": 4096
}
},
"boot": {
"type": "org.osbuild.loopback",
"options": {
"filename": "disk.img",
"start": 33024,
"size": 98304,
"sector-size": 4096
}
},
"root": {
"type": "org.osbuild.loopback",
"options": {
"filename": "disk.img",
"start": 131328,
"size": 524288,
"sector-size": 4096 "sector-size": 4096
} }
} }
@ -916,19 +883,22 @@
{ {
"name": "root", "name": "root",
"type": "org.osbuild.xfs", "type": "org.osbuild.xfs",
"source": "root", "source": "disk",
"partition": 4,
"target": "/" "target": "/"
}, },
{ {
"name": "boot", "name": "boot",
"type": "org.osbuild.ext4", "type": "org.osbuild.ext4",
"source": "boot", "source": "disk",
"partition": 3,
"target": "/boot" "target": "/boot"
}, },
{ {
"name": "efi", "name": "efi",
"type": "org.osbuild.fat", "type": "org.osbuild.fat",
"source": "efi", "source": "disk",
"partition": 2,
"target": "/boot/efi" "target": "/boot/efi"
} }
] ]

View file

@ -207,42 +207,29 @@ pipelines:
- from: input://tree/ - from: input://tree/
to: mount://root/ to: mount://root/
devices: devices:
efi: disk:
type: org.osbuild.loopback type: org.osbuild.loopback
options: options:
filename: disk.img filename: disk.img
start: partscan: true
mpp-format-int: '{image.layout[''EFI-SYSTEM''].start}'
size:
mpp-format-int: '{image.layout[''EFI-SYSTEM''].size}'
boot:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-format-int: '{image.layout[''boot''].start}'
size:
mpp-format-int: '{image.layout[''boot''].size}'
root:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-format-int: '{image.layout[''root''].start}'
size:
mpp-format-int: '{image.layout[''root''].size}'
mounts: mounts:
- name: root - name: root
type: org.osbuild.xfs type: org.osbuild.xfs
source: root source: disk
partition:
mpp-format-int: '{image.layout[''root''].partnum}'
target: / target: /
- name: boot - name: boot
type: org.osbuild.ext4 type: org.osbuild.ext4
source: boot source: disk
partition:
mpp-format-int: '{image.layout[''boot''].partnum}'
target: /boot target: /boot
- name: efi - name: efi
type: org.osbuild.fat type: org.osbuild.fat
source: efi source: disk
partition:
mpp-format-int: '{image.layout[''EFI-SYSTEM''].partnum}'
target: /boot/efi target: /boot/efi
- type: org.osbuild.grub2.inst - type: org.osbuild.grub2.inst
options: options:
@ -339,48 +326,31 @@ pipelines:
- from: input://tree/ - from: input://tree/
to: mount://root/ to: mount://root/
devices: devices:
efi: disk:
type: org.osbuild.loopback type: org.osbuild.loopback
options: options:
filename: disk.img filename: disk.img
start: partscan: true
mpp-format-int: '{image4k.layout[''EFI-SYSTEM''].start}'
size:
mpp-format-int: '{image4k.layout[''EFI-SYSTEM''].size}'
sector-size:
mpp-format-int: "{four_k_sector_size}"
boot:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-format-int: '{image4k.layout[''boot''].start}'
size:
mpp-format-int: '{image4k.layout[''boot''].size}'
sector-size:
mpp-format-int: "{four_k_sector_size}"
root:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-format-int: '{image4k.layout[''root''].start}'
size:
mpp-format-int: '{image4k.layout[''root''].size}'
sector-size: sector-size:
mpp-format-int: "{four_k_sector_size}" mpp-format-int: "{four_k_sector_size}"
mounts: mounts:
- name: root - name: root
type: org.osbuild.xfs type: org.osbuild.xfs
source: root source: disk
partition:
mpp-format-int: '{image4k.layout[''root''].partnum}'
target: / target: /
- name: boot - name: boot
type: org.osbuild.ext4 type: org.osbuild.ext4
source: boot source: disk
partition:
mpp-format-int: '{image4k.layout[''boot''].partnum}'
target: /boot target: /boot
- name: efi - name: efi
type: org.osbuild.fat type: org.osbuild.fat
source: efi source: disk
partition:
mpp-format-int: '{image4k.layout[''EFI-SYSTEM''].partnum}'
target: /boot/efi target: /boot/efi
- name: raw-metal-image - name: raw-metal-image
build: name:build build: name:build

View file

@ -107,6 +107,7 @@ def mount(mgr, devpath, tree, size, mountpoint, options):
lpath, lpath,
index.get_module_info("Mount", "org.osbuild.fat"), index.get_module_info("Mount", "org.osbuild.fat"),
dev, dev,
None,
"/", "/",
options options
) )