fix: support user disks via symlinks

The core blockdevice library already supported resolving symlinks, we
just need to get the raw block device name from it, and use it
afterwards.

In QEMU provisioner, leave the first (system) disk as virtio (for
performance), and mount user disks as 'ata', which allows `udevd` to
pick up the disk IDs (not available for `virtio`), and use the symlink
path in the tests.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
Andrey Smirnov 2023-12-05 22:02:56 +04:00
parent 4f195dd271
commit 270604bead
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
4 changed files with 64 additions and 29 deletions

View File

@ -128,6 +128,12 @@ cluster:
extraArgs:
- --iface-can-reach=192.168.1.1
```
"""
[notes.user-disks]
title = "User Disks"
description = """\
Talos Linux now supports specifying user disks in `.machine.disks` machine configuration links via `udev` symlinks, e.g. `/dev/disk/by-id/XXXX`.
"""
[make_deps]

View File

@ -816,7 +816,7 @@ func MountUserDisks(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {
return err
}
return mountDisks(r)
return mountDisks(logger, r)
}, "mountUserDisks"
}
@ -838,6 +838,12 @@ func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error {
return err
}
deviceName := bd.Device().Name()
if disk.Device() != deviceName {
logger.Printf("using device name %q instead of %q", deviceName, disk.Device())
}
//nolint:errcheck
defer bd.Close()
@ -857,21 +863,21 @@ func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error {
if pt != nil {
if len(pt.Partitions().Items()) > 0 {
logger.Printf(("skipping setup of %q, found existing partitions"), disk.Device())
logger.Printf(("skipping setup of %q, found existing partitions"), deviceName)
return nil
}
}
m.Devices[disk.Device()] = installer.Device{
Device: disk.Device(),
m.Devices[deviceName] = installer.Device{
Device: deviceName,
ResetPartitionTable: true,
SkipOverlayMountsCheck: true,
}
for _, part := range disk.Partitions() {
extraTarget := &installer.Target{
Device: disk.Device(),
Device: deviceName,
FormatOptions: &partition.FormatOptions{
Force: true,
FileSystemType: partition.FilesystemTypeXFS,
@ -882,7 +888,7 @@ func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error {
},
}
m.Targets[disk.Device()] = append(m.Targets[disk.Device()], extraTarget)
m.Targets[deviceName] = append(m.Targets[deviceName], extraTarget)
}
return nil
@ -894,14 +900,29 @@ func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error {
return m.Execute()
}
func mountDisks(r runtime.Runtime) (err error) {
func mountDisks(logger *log.Logger, r runtime.Runtime) (err error) {
mountpoints := mount.NewMountPoints()
for _, disk := range r.Config().Machine().Disks() {
bd, err := blockdevice.Open(disk.Device(), blockdevice.WithMode(blockdevice.ReadonlyMode))
if err != nil {
return err
}
deviceName := bd.Device().Name()
if disk.Device() != deviceName {
logger.Printf("using device name %q instead of %q", deviceName, disk.Device())
}
if err = bd.Close(); err != nil {
return err
}
for i, part := range disk.Partitions() {
var partname string
partname, err = util.PartPath(disk.Device(), i+1)
partname, err = util.PartPath(deviceName, i+1)
if err != nil {
return err
}
@ -1137,10 +1158,25 @@ func UnmountUserDisks(runtime.Sequence, any) (runtime.TaskExecutionFunc, string)
mountpoints := mount.NewMountPoints()
for _, disk := range r.Config().Machine().Disks() {
bd, err := blockdevice.Open(disk.Device(), blockdevice.WithMode(blockdevice.ReadonlyMode))
if err != nil {
return err
}
deviceName := bd.Device().Name()
if deviceName != disk.Device() {
logger.Printf("using device name %q instead of %q", deviceName, disk.Device())
}
if err = bd.Close(); err != nil {
return err
}
for i, part := range disk.Partitions() {
var partname string
partname, err = util.PartPath(disk.Device(), i+1)
partname, err = util.PartPath(deviceName, i+1)
if err != nil {
return err
}

View File

@ -279,8 +279,14 @@ func launchVM(config *LaunchConfig) error {
"virtserialport,chardev=qga0,name=org.qemu.guest_agent.0",
}
for _, disk := range config.DiskPaths {
args = append(args, "-drive", fmt.Sprintf("format=raw,if=virtio,file=%s,cache=unsafe", disk))
for i, disk := range config.DiskPaths {
driver := "virtio"
if i > 0 {
driver = "ide"
}
args = append(args, "-drive", fmt.Sprintf("format=raw,if=%s,file=%s,cache=unsafe", driver, disk))
}
machineArg := config.MachineType

View File

@ -14,24 +14,11 @@ import (
// UserDiskName returns disk device path.
func (p *Provisioner) UserDiskName(index int) string {
res := "/dev/vd"
var convert func(i int) string
convert = func(i int) string {
remainder := i % 26
divider := i / 26
prefix := ""
if divider != 0 {
prefix = convert(divider - 1)
}
return fmt.Sprintf("%s%s", prefix, string(rune('a'+remainder)))
}
return res + convert(index)
// the disk IDs are assigned in the following way:
// * ata-QEMU_HARDDISK_QM00001
// * ata-QEMU_HARDDISK_QM00003
// * ata-QEMU_HARDDISK_QM00005
return fmt.Sprintf("/dev/disk/by-id/ata-QEMU_HARDDISK_QM%05d", (index-1)*2+1)
}
// CreateDisks creates empty disk files for each disk.