Andrey Smirnov f07b79f4a8
feat: provide disk detection based on new blockdevices
Uses go-siderolabs/go-blockdevice/v2 for all the hard parts,
provides new resource `Disk` which describes all disks in the system.

Additional resource `SystemDisk` always point to the system disk (based
on the location of `META` partition).

The `Disks` API (and `talosctl disks`) provides a view now into the
`talosctl get disks` to keep backwards compatibility.

QEMU provisioner can now create extra disks of various types: IDE, AHCI,
SCSI, NVME, this allows to test detection properly.

The new resource will be the foundation for volume provisioning (to pick
up the disk to provision the volume on).

Example:

```
talosctl -n 172.20.0.5 get disks
NODE         NAMESPACE   TYPE   ID        VERSION   SIZE          READ ONLY   TRANSPORT   ROTATIONAL   WWID                                                               MODEL            SERIAL
172.20.0.5   runtime     Disk   loop0     1         65568768      true
172.20.0.5   runtime     Disk   nvme0n1   1         10485760000   false       nvme                     nvme.1b36-6465616462656566-51454d55204e564d65204374726c-00000001   QEMU NVMe Ctrl   deadbeef
172.20.0.5   runtime     Disk   sda       1         10485760000   false       virtio      true                                                                            QEMU HARDDISK
172.20.0.5   runtime     Disk   sdb       1         10485760000   false       sata        true         t10.ATA     QEMU HARDDISK                           QM00013        QEMU HARDDISK
172.20.0.5   runtime     Disk   sdc       1         10485760000   false       sata        true         t10.ATA     QEMU HARDDISK                           QM00001        QEMU HARDDISK
172.20.0.5   runtime     Disk   vda       1         12884901888   false       virtio      true
```

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
2024-06-07 20:18:32 +04:00

84 lines
2.4 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package internal contains server implementation.
package internal
import (
"context"
"path/filepath"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/cosi-project/runtime/pkg/state"
"google.golang.org/protobuf/types/known/emptypb"
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
"github.com/siderolabs/talos/pkg/machinery/api/storage"
"github.com/siderolabs/talos/pkg/machinery/resources/block"
)
// Server implements storage.StorageService.
//
// It is only kept here for compatibility purposes, proper API is to query `block.Disk` resources.
type Server struct {
storage.UnimplementedStorageServiceServer
Controller runtime.Controller
}
// Disks implements storage.StorageService.
func (s *Server) Disks(ctx context.Context, in *emptypb.Empty) (reply *storage.DisksResponse, err error) {
st := s.Controller.Runtime().State().V1Alpha2().Resources()
systemDisk, err := safe.StateGetByID[*block.SystemDisk](ctx, st, block.SystemDiskID)
if err != nil && !state.IsNotFoundError(err) {
return nil, err
}
disks, err := safe.StateListAll[*block.Disk](ctx, st)
if err != nil {
return nil, err
}
diskConv := func(d *block.Disk) (*storage.Disk, error) {
var diskType storage.Disk_DiskType
switch {
case d.TypedSpec().Transport == "nvme":
diskType = storage.Disk_NVME
case d.TypedSpec().Transport == "mmc":
diskType = storage.Disk_SD
case d.TypedSpec().Rotational:
diskType = storage.Disk_HDD
case d.TypedSpec().Transport != "":
diskType = storage.Disk_SSD
}
return &storage.Disk{
DeviceName: filepath.Join("/dev", d.Metadata().ID()),
Model: d.TypedSpec().Model,
Size: d.TypedSpec().Size,
Serial: d.TypedSpec().Serial,
Modalias: d.TypedSpec().Modalias,
Wwid: d.TypedSpec().WWID,
Type: diskType,
BusPath: d.TypedSpec().BusPath,
SystemDisk: systemDisk != nil && d.Metadata().ID() == systemDisk.TypedSpec().DiskID,
Subsystem: d.TypedSpec().SubSystem,
Readonly: d.TypedSpec().Readonly,
}, nil
}
diskList, _ := safe.Map(disks, diskConv) //nolint:errcheck
reply = &storage.DisksResponse{
Messages: []*storage.Disks{
{
Disks: diskList,
},
},
}
return reply, nil
}