obsuild2: generalise mkfs stage device option generation
Refactor GenMkfsStages to work with entity based methods so that it is now able to handle all generic cases of arbitrarily nested devices. Co-Authored-By: Christian Kellner <christian@kellner.me>
This commit is contained in:
parent
8a73ab5980
commit
16a975fe6f
8 changed files with 122 additions and 38 deletions
|
|
@ -1,5 +1,12 @@
|
|||
package osbuild2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/disk"
|
||||
)
|
||||
|
||||
type Devices map[string]Device
|
||||
|
||||
type Device struct {
|
||||
|
|
@ -11,3 +18,72 @@ type Device struct {
|
|||
type DeviceOptions interface {
|
||||
isDeviceOptions()
|
||||
}
|
||||
|
||||
func deviceName(p disk.Entity) string {
|
||||
if p == nil {
|
||||
panic("device is nil; this is a programming error")
|
||||
}
|
||||
|
||||
switch payload := p.(type) {
|
||||
case disk.Mountable:
|
||||
return pathdot(payload.GetMountpoint())
|
||||
case *disk.LUKSContainer:
|
||||
return "luks-" + payload.UUID[:4]
|
||||
case *disk.LVMVolumeGroup:
|
||||
return payload.Name + "vg"
|
||||
case *disk.LVMLogicalVolume:
|
||||
return payload.Name
|
||||
}
|
||||
panic(fmt.Sprintf("unsupported device type in deviceName: '%T'", p))
|
||||
}
|
||||
|
||||
func getDevices(path []disk.Entity, filename string) (map[string]Device, string) {
|
||||
var pt *disk.PartitionTable
|
||||
|
||||
do := make(map[string]Device)
|
||||
parent := ""
|
||||
for _, elem := range path {
|
||||
switch e := elem.(type) {
|
||||
case *disk.PartitionTable:
|
||||
pt = e
|
||||
case *disk.Partition:
|
||||
if pt == nil {
|
||||
panic("path does not contain partition table; this is a programming error")
|
||||
}
|
||||
lbopt := LoopbackDeviceOptions{
|
||||
Filename: filename,
|
||||
Start: pt.BytesToSectors(e.Start),
|
||||
Size: pt.BytesToSectors(e.Size),
|
||||
SectorSize: nil,
|
||||
}
|
||||
name := deviceName(e.Payload)
|
||||
do[name] = *NewLoopbackDevice(&lbopt)
|
||||
parent = name
|
||||
case *disk.LUKSContainer:
|
||||
lo := LUKS2DeviceOptions{
|
||||
Passphrase: e.Passphrase,
|
||||
}
|
||||
name := deviceName(e.Payload)
|
||||
do[name] = *NewLUKS2Device(parent, &lo)
|
||||
parent = name
|
||||
case *disk.LVMLogicalVolume:
|
||||
lo := LVM2LVDeviceOptions{
|
||||
Volume: e.Name,
|
||||
}
|
||||
name := deviceName(e.Payload)
|
||||
do[name] = *NewLVM2LVDevice(parent, &lo)
|
||||
parent = name
|
||||
}
|
||||
}
|
||||
return do, parent
|
||||
}
|
||||
|
||||
func pathdot(path string) string {
|
||||
if path == "/" {
|
||||
return "root"
|
||||
}
|
||||
|
||||
path = strings.TrimLeft(path, "/")
|
||||
|
||||
return strings.ReplaceAll(path, "/", ".")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ type LUKS2DeviceOptions struct {
|
|||
|
||||
func (LUKS2DeviceOptions) isDeviceOptions() {}
|
||||
|
||||
func NewLUKS2Device(options *LUKS2DeviceOptions) *Device {
|
||||
func NewLUKS2Device(parent string, options *LUKS2DeviceOptions) *Device {
|
||||
return &Device{
|
||||
Type: "org.osbuild.luks2",
|
||||
Parent: parent,
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ type MkfsBtrfsStageOptions struct {
|
|||
|
||||
func (MkfsBtrfsStageOptions) isStageOptions() {}
|
||||
|
||||
func NewMkfsBtrfsStage(options *MkfsBtrfsStageOptions, device *Device) *Stage {
|
||||
func NewMkfsBtrfsStage(options *MkfsBtrfsStageOptions, devices map[string]Device) *Stage {
|
||||
return &Stage{
|
||||
Type: "org.osbuild.mkfs.btrfs",
|
||||
Options: options,
|
||||
Devices: Devices{"device": *device},
|
||||
Devices: devices,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ type MkfsExt4StageOptions struct {
|
|||
|
||||
func (MkfsExt4StageOptions) isStageOptions() {}
|
||||
|
||||
func NewMkfsExt4Stage(options *MkfsExt4StageOptions, device *Device) *Stage {
|
||||
func NewMkfsExt4Stage(options *MkfsExt4StageOptions, devices map[string]Device) *Stage {
|
||||
return &Stage{
|
||||
Type: "org.osbuild.mkfs.ext4",
|
||||
Options: options,
|
||||
Devices: Devices{"device": *device},
|
||||
Devices: devices,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ type MkfsFATStageOptions struct {
|
|||
|
||||
func (MkfsFATStageOptions) isStageOptions() {}
|
||||
|
||||
func NewMkfsFATStage(options *MkfsFATStageOptions, device *Device) *Stage {
|
||||
func NewMkfsFATStage(options *MkfsFATStageOptions, devices map[string]Device) *Stage {
|
||||
return &Stage{
|
||||
Type: "org.osbuild.mkfs.fat",
|
||||
Options: options,
|
||||
Devices: Devices{"device": *device},
|
||||
Devices: devices,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,47 +18,50 @@ func GenMkfsStages(pt *disk.PartitionTable, device *Device) []*Stage {
|
|||
panic("GenMkfsStages: failed to convert device options to loopback options")
|
||||
}
|
||||
|
||||
for _, p := range pt.Partitions {
|
||||
if p.Payload == nil {
|
||||
// no filesystem for partition (e.g., BIOS boot)
|
||||
continue
|
||||
}
|
||||
genStage := func(mnt disk.Mountable, path []disk.Entity) error {
|
||||
t := mnt.GetFSType()
|
||||
var stage *Stage
|
||||
stageDevice := NewLoopbackDevice(
|
||||
&LoopbackDeviceOptions{
|
||||
Filename: devOptions.Filename,
|
||||
Start: pt.BytesToSectors(p.Start),
|
||||
Size: pt.BytesToSectors(p.Size),
|
||||
},
|
||||
)
|
||||
switch p.Payload.Type {
|
||||
|
||||
stageDevices, lastName := getDevices(path, devOptions.Filename)
|
||||
|
||||
// the last device on the PartitionTable must be named "device"
|
||||
lastDevice := stageDevices[lastName]
|
||||
delete(stageDevices, lastName)
|
||||
stageDevices["device"] = lastDevice
|
||||
|
||||
fsSpec := mnt.GetFSSpec()
|
||||
switch t {
|
||||
case "xfs":
|
||||
options := &MkfsXfsStageOptions{
|
||||
UUID: p.Payload.UUID,
|
||||
Label: p.Payload.Label,
|
||||
UUID: fsSpec.UUID,
|
||||
Label: fsSpec.Label,
|
||||
}
|
||||
stage = NewMkfsXfsStage(options, stageDevice)
|
||||
stage = NewMkfsXfsStage(options, stageDevices)
|
||||
case "vfat":
|
||||
options := &MkfsFATStageOptions{
|
||||
VolID: strings.Replace(p.Payload.UUID, "-", "", -1),
|
||||
VolID: strings.Replace(fsSpec.UUID, "-", "", -1),
|
||||
}
|
||||
stage = NewMkfsFATStage(options, stageDevice)
|
||||
stage = NewMkfsFATStage(options, stageDevices)
|
||||
case "btrfs":
|
||||
options := &MkfsBtrfsStageOptions{
|
||||
UUID: p.Payload.UUID,
|
||||
Label: p.Payload.Label,
|
||||
UUID: fsSpec.UUID,
|
||||
Label: fsSpec.Label,
|
||||
}
|
||||
stage = NewMkfsBtrfsStage(options, stageDevice)
|
||||
stage = NewMkfsBtrfsStage(options, stageDevices)
|
||||
case "ext4":
|
||||
options := &MkfsExt4StageOptions{
|
||||
UUID: p.Payload.UUID,
|
||||
Label: p.Payload.Label,
|
||||
UUID: fsSpec.UUID,
|
||||
Label: fsSpec.Label,
|
||||
}
|
||||
stage = NewMkfsExt4Stage(options, stageDevice)
|
||||
stage = NewMkfsExt4Stage(options, stageDevices)
|
||||
default:
|
||||
panic("unknown fs type " + p.Type)
|
||||
panic("unknown fs type " + t)
|
||||
}
|
||||
stages = append(stages, stage)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = pt.ForEachMountable(genStage) // genStage always returns nil
|
||||
return stages
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@ func TestNewMkfsStage(t *testing.T) {
|
|||
}
|
||||
device := NewLoopbackDevice(&devOpts)
|
||||
|
||||
devices := map[string]Device{
|
||||
"device": *device,
|
||||
}
|
||||
|
||||
btrfsOptions := &MkfsBtrfsStageOptions{
|
||||
UUID: uuid.New().String(),
|
||||
Label: "test",
|
||||
}
|
||||
mkbtrfs := NewMkfsBtrfsStage(btrfsOptions, device)
|
||||
mkbtrfs := NewMkfsBtrfsStage(btrfsOptions, devices)
|
||||
mkbtrfsExpected := &Stage{
|
||||
Type: "org.osbuild.mkfs.btrfs",
|
||||
Options: btrfsOptions,
|
||||
|
|
@ -33,7 +37,7 @@ func TestNewMkfsStage(t *testing.T) {
|
|||
UUID: uuid.New().String(),
|
||||
Label: "test",
|
||||
}
|
||||
mkext4 := NewMkfsExt4Stage(ext4Options, device)
|
||||
mkext4 := NewMkfsExt4Stage(ext4Options, devices)
|
||||
mkext4Expected := &Stage{
|
||||
Type: "org.osbuild.mkfs.ext4",
|
||||
Options: ext4Options,
|
||||
|
|
@ -46,7 +50,7 @@ func TestNewMkfsStage(t *testing.T) {
|
|||
Label: "test",
|
||||
FATSize: common.IntToPtr(12),
|
||||
}
|
||||
mkfat := NewMkfsFATStage(fatOptions, device)
|
||||
mkfat := NewMkfsFATStage(fatOptions, devices)
|
||||
mkfatExpected := &Stage{
|
||||
Type: "org.osbuild.mkfs.fat",
|
||||
Options: fatOptions,
|
||||
|
|
@ -58,7 +62,7 @@ func TestNewMkfsStage(t *testing.T) {
|
|||
UUID: uuid.New().String(),
|
||||
Label: "test",
|
||||
}
|
||||
mkxfs := NewMkfsXfsStage(xfsOptions, device)
|
||||
mkxfs := NewMkfsXfsStage(xfsOptions, devices)
|
||||
mkxfsExpected := &Stage{
|
||||
Type: "org.osbuild.mkfs.xfs",
|
||||
Options: xfsOptions,
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ type MkfsXfsStageOptions struct {
|
|||
|
||||
func (MkfsXfsStageOptions) isStageOptions() {}
|
||||
|
||||
func NewMkfsXfsStage(options *MkfsXfsStageOptions, device *Device) *Stage {
|
||||
func NewMkfsXfsStage(options *MkfsXfsStageOptions, devices map[string]Device) *Stage {
|
||||
return &Stage{
|
||||
Type: "org.osbuild.mkfs.xfs",
|
||||
Options: options,
|
||||
Devices: Devices{"device": *device},
|
||||
Devices: devices,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue