From 270604bead50423697d6fabffa6bbd7c7b2fbe9e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 5 Dec 2023 22:02:56 +0400 Subject: [PATCH] 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 --- hack/release.toml | 6 +++ .../v1alpha1/v1alpha1_sequencer_tasks.go | 54 +++++++++++++++---- pkg/provision/providers/qemu/launch.go | 10 +++- pkg/provision/providers/vm/disk.go | 23 ++------ 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/hack/release.toml b/hack/release.toml index 03e397e9f..c09930ddc 100644 --- a/hack/release.toml +++ b/hack/release.toml @@ -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] diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index d91abdaf8..d9f4b2ca4 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -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 } diff --git a/pkg/provision/providers/qemu/launch.go b/pkg/provision/providers/qemu/launch.go index de8f01e4b..1671b73a4 100644 --- a/pkg/provision/providers/qemu/launch.go +++ b/pkg/provision/providers/qemu/launch.go @@ -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 diff --git a/pkg/provision/providers/vm/disk.go b/pkg/provision/providers/vm/disk.go index 3838717b8..f0bcc82f5 100644 --- a/pkg/provision/providers/vm/disk.go +++ b/pkg/provision/providers/vm/disk.go @@ -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.