osbuild-worker: use the new ostree resolver API

This commit is contained in:
Lukas Zapletal 2024-10-31 15:31:16 +01:00 committed by Achilleas Koutsou
parent f291f41dbc
commit 64f479092d
27 changed files with 318 additions and 136 deletions

View file

@ -19,6 +19,7 @@ package disk
import (
"encoding/hex"
"fmt"
"io"
"math/rand"
"reflect"
@ -61,6 +62,54 @@ const (
DosFat16B = "06"
)
// FSType is the filesystem type enum.
//
// There should always be one value for each filesystem type supported by
// osbuild stages (stages/org.osbuild.mkfs.*) and the unset/none value.
type FSType uint64
const (
FS_NONE FSType = iota
FS_VFAT
FS_EXT4
FS_XFS
FS_BTRFS
)
func (f FSType) String() string {
switch f {
case FS_NONE:
return ""
case FS_VFAT:
return "vfat"
case FS_EXT4:
return "ext4"
case FS_XFS:
return "xfs"
case FS_BTRFS:
return "btrfs"
default:
panic(fmt.Sprintf("unknown or unsupported filesystem type with enum value %d", f))
}
}
func NewFSType(s string) (FSType, error) {
switch s {
case "":
return FS_NONE, nil
case "vfat":
return FS_VFAT, nil
case "ext4":
return FS_EXT4, nil
case "xfs":
return FS_XFS, nil
case "btrfs":
return FS_BTRFS, nil
default:
return FS_NONE, fmt.Errorf("unknown or unsupported filesystem type name: %s", s)
}
}
// Entity is the base interface for all disk-related entities.
type Entity interface {
// Clone returns a deep copy of the entity.
@ -205,3 +254,24 @@ func NewVolIDFromRand(r *rand.Rand) string {
}
return hex.EncodeToString(volid)
}
// genUniqueString returns a string based on base that does does not exist in
// the existing set. If the base itself does not exist, it is returned as is,
// otherwise a two digit number is added and incremented until a unique string
// is found.
// This function is mimicking what blivet does for avoiding name collisions.
// See blivet/blivet.py#L1060 commit 2eb4bd4
func genUniqueString(base string, existing map[string]bool) (string, error) {
if !existing[base] {
return base, nil
}
for i := 0; i < 100; i++ {
uniq := fmt.Sprintf("%s%02d", base, i)
if !existing[uniq] {
return uniq, nil
}
}
return "", fmt.Errorf("name collision: could not generate unique version of %q", base)
}

View file

@ -81,41 +81,49 @@ func (vg *LVMVolumeGroup) CreateMountpoint(mountpoint string, size uint64) (Enti
FSTabPassNo: 0,
}
return vg.CreateLogicalVolume(mountpoint, size, &filesystem)
// leave lv name empty to autogenerate based on mountpoint
return vg.CreateLogicalVolume("", size, &filesystem)
}
func (vg *LVMVolumeGroup) CreateLogicalVolume(lvName string, size uint64, payload Entity) (Entity, error) {
if vg == nil {
panic("LVMVolumeGroup.CreateLogicalVolume: nil entity")
}
// genLVName generates a valid logical volume name from a mountpoint or base
// that does not conflict with existing ones.
func (vg *LVMVolumeGroup) genLVName(base string) (string, error) {
names := make(map[string]bool, len(vg.LogicalVolumes))
for _, lv := range vg.LogicalVolumes {
names[lv.Name] = true
}
base := lvname(lvName)
var exists bool
name := base
base = lvname(base) // if the mountpoint is used (i.e. if the base contains /), sanitize it and append 'lv'
// Make sure that we don't collide with an existing volume, e.g. 'home/test'
// and /home/test_test would collide. We try 100 times and then give up. This
// is mimicking what blivet does. See blivet/blivet.py#L1060 commit 2eb4bd4
for i := 0; i < 100; i++ {
exists = names[name]
if !exists {
break
}
// Make sure that we don't collide with an existing volume, e.g.
// 'home/test' and /home_test would collide.
return genUniqueString(base, names)
}
name = fmt.Sprintf("%s%02d", base, i)
// CreateLogicalVolume creates a new logical volume on the volume group. If a
// name is not provided, a valid one is generated based on the payload
// mountpoint. If a name is provided, it is used directly without validating.
func (vg *LVMVolumeGroup) CreateLogicalVolume(lvName string, size uint64, payload Entity) (*LVMLogicalVolume, error) {
if vg == nil {
panic("LVMVolumeGroup.CreateLogicalVolume: nil entity")
}
if exists {
return nil, fmt.Errorf("could not create logical volume: name collision")
if lvName == "" {
// generate a name based on the payload's mountpoint
mntble, ok := payload.(Mountable)
if !ok {
return nil, fmt.Errorf("could not create logical volume: no name provided and payload is not mountable")
}
mountpoint := mntble.GetMountpoint()
autoName, err := vg.genLVName(mountpoint)
if err != nil {
return nil, err
}
lvName = autoName
}
lv := LVMLogicalVolume{
Name: name,
Name: lvName,
Size: vg.AlignUp(size),
Payload: payload,
}

View file

@ -715,7 +715,7 @@ func (pt *PartitionTable) ensureLVM() error {
// create root logical volume on the new volume group with the same
// size and filesystem as the previous root partition
_, err := vg.CreateLogicalVolume("root", part.Size, filesystem)
_, err := vg.CreateLogicalVolume("rootlv", part.Size, filesystem)
if err != nil {
panic(fmt.Sprintf("Could not create LV: %v", err))
}