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>
This commit is contained in:
Andrey Smirnov 2024-06-07 19:48:41 +04:00
parent 8ee0872683
commit f07b79f4a8
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
23 changed files with 1621 additions and 54 deletions

View File

@ -36,3 +36,24 @@ message DiscoveredVolumeSpec {
string parent = 16;
}
// DiskSpec is the spec for Disks status.
message DiskSpec {
uint64 size = 1;
uint64 io_size = 2;
uint64 sector_size = 3;
bool readonly = 4;
string model = 5;
string serial = 6;
string modalias = 7;
string wwid = 8;
string bus_path = 9;
string sub_system = 10;
string transport = 11;
bool rotational = 12;
}
// SystemDiskSpec is the spec for SystemDisks status.
message SystemDiskSpec {
string disk_id = 1;
}

View File

@ -137,6 +137,7 @@ var (
clusterDisks []string
extraDisks int
extraDiskSize int
extraDisksDrivers []string
targetArch string
clusterWait bool
clusterWaitTimeout time.Duration
@ -832,10 +833,17 @@ func create(ctx context.Context) error {
}
// append extra disks
for range extraDisks {
for i := range extraDisks {
driver := "ide"
if i < len(extraDisksDrivers) {
driver = extraDisksDrivers[i]
}
disks = append(disks, &provision.Disk{
Size: uint64(extraDiskSize) * 1024 * 1024,
SkipPreallocate: !clusterDiskPreallocate,
Driver: driver,
})
}
@ -1045,6 +1053,7 @@ func getDisks() ([]*provision.Disk, error) {
{
Size: uint64(clusterDiskSize) * 1024 * 1024,
SkipPreallocate: !clusterDiskPreallocate,
Driver: "virtio",
},
}
@ -1092,6 +1101,7 @@ func getDisks() ([]*provision.Disk, error) {
Size: diskSize + 2*1024*1024,
Partitions: diskPartitions,
SkipPreallocate: !clusterDiskPreallocate,
Driver: "ide",
})
}
@ -1143,6 +1153,7 @@ func init() {
createCmd.Flags().BoolVar(&clusterDiskPreallocate, clusterDiskPreallocateFlag, true, "whether disk space should be preallocated")
createCmd.Flags().StringSliceVar(&clusterDisks, clusterDisksFlag, []string{}, "list of disks to create for each VM in format: <mount_point1>:<size1>:<mount_point2>:<size2>")
createCmd.Flags().IntVar(&extraDisks, "extra-disks", 0, "number of extra disks to create for each worker VM")
createCmd.Flags().StringSliceVar(&extraDisksDrivers, "extra-disks-drivers", nil, "driver for each extra disk (virtio, ide, ahci, scsi, nvme)")
createCmd.Flags().IntVar(&extraDiskSize, "extra-disks-size", 5*1024, "default limit on disk size in MB (each VM)")
createCmd.Flags().StringVar(&targetArch, "arch", stdruntime.GOARCH, "cluster architecture")
createCmd.Flags().BoolVar(&clusterWait, "wait", true, "wait for the cluster to be ready before returning")

2
go.mod
View File

@ -128,7 +128,7 @@ require (
github.com/siderolabs/gen v0.5.0
github.com/siderolabs/go-api-signature v0.3.2
github.com/siderolabs/go-blockdevice v0.4.7
github.com/siderolabs/go-blockdevice/v2 v2.0.0-20240604163945-81b69bf28eaa
github.com/siderolabs/go-blockdevice/v2 v2.0.0-20240607145058-1a51f162a09e
github.com/siderolabs/go-circular v0.2.0
github.com/siderolabs/go-cmd v0.1.1
github.com/siderolabs/go-copy v0.1.0

4
go.sum
View File

@ -661,8 +661,8 @@ github.com/siderolabs/go-api-signature v0.3.2 h1:blqrZF1GM7TWgq7mY7CsR+yQ93u6az0
github.com/siderolabs/go-api-signature v0.3.2/go.mod h1:punhUOaXa7LELYBRCUhfgUGH6ieVz68GrP98apCKXj8=
github.com/siderolabs/go-blockdevice v0.4.7 h1:2bk4WpEEflGxjrNwp57ye24Pr+cYgAiAeNMWiQOuWbQ=
github.com/siderolabs/go-blockdevice v0.4.7/go.mod h1:4PeOuk71pReJj1JQEXDE7kIIQJPVe8a+HZQa+qjxSEA=
github.com/siderolabs/go-blockdevice/v2 v2.0.0-20240604163945-81b69bf28eaa h1:OjQLrcis/GuqaqxnIw2dxp4ZzT/zk5p1GI3NxcMxkrA=
github.com/siderolabs/go-blockdevice/v2 v2.0.0-20240604163945-81b69bf28eaa/go.mod h1:5GnL7VLNp5/vgiwYP74fi6KuTUfqGcRxQxtto2tzD+I=
github.com/siderolabs/go-blockdevice/v2 v2.0.0-20240607145058-1a51f162a09e h1:PQhtHJj3zwaqehthq0fs2TyW8bW/mlOYoHfZIeSYQ3M=
github.com/siderolabs/go-blockdevice/v2 v2.0.0-20240607145058-1a51f162a09e/go.mod h1:5GnL7VLNp5/vgiwYP74fi6KuTUfqGcRxQxtto2tzD+I=
github.com/siderolabs/go-circular v0.2.0 h1:Xca8zrjF/YsujLbwDSojkKzJe7ngetnpuIJn8N78DJI=
github.com/siderolabs/go-circular v0.2.0/go.mod h1:rrYCwHLYWmxqrmZP+LjYtwB2a55lxzQi0Ztu1VpWZSc=
github.com/siderolabs/go-cmd v0.1.1 h1:nTouZUSxLeiiEe7hFexSVvaTsY/3O8k1s08BxPRrsps=

View File

@ -0,0 +1,167 @@
// 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 block
import (
"context"
"fmt"
"path/filepath"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/safe"
blkdev "github.com/siderolabs/go-blockdevice/v2/block"
"go.uber.org/zap"
"github.com/siderolabs/talos/pkg/machinery/resources/block"
)
// DisksController provides a detailed view of blockdevices of type 'disk'.
type DisksController struct{}
// Name implements controller.Controller interface.
func (ctrl *DisksController) Name() string {
return "block.DisksController"
}
// Inputs implements controller.Controller interface.
func (ctrl *DisksController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: block.NamespaceName,
Type: block.DeviceType,
Kind: controller.InputWeak,
},
}
}
// Outputs implements controller.Controller interface.
func (ctrl *DisksController) Outputs() []controller.Output {
return []controller.Output{
{
Type: block.DiskType,
Kind: controller.OutputExclusive,
},
}
}
// Run implements controller.Controller interface.
//
//nolint:gocyclo
func (ctrl *DisksController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
// lastObservedGenerations holds the last observed generation of each device.
//
// when the generation of a device changes, the device might have changed and might need to be re-probed.
lastObservedGenerations := map[string]int{}
for {
select {
case <-r.EventCh():
case <-ctx.Done():
return nil
}
blockdevices, err := safe.ReaderListAll[*block.Device](ctx, r)
if err != nil {
return fmt.Errorf("failed to list block devices: %w", err)
}
touchedDisks := map[string]struct{}{}
for iter := blockdevices.Iterator(); iter.Next(); {
device := iter.Value()
if device.TypedSpec().Type != "disk" {
continue
}
if lastObserved, ok := lastObservedGenerations[device.Metadata().ID()]; ok && device.TypedSpec().Generation == lastObserved {
// ignore disks which have some generation as before (don't query them once again)
touchedDisks[device.Metadata().ID()] = struct{}{}
continue
}
lastObservedGenerations[device.Metadata().ID()] = device.TypedSpec().Generation
if err = ctrl.analyzeBlockDevice(ctx, r, logger.With(zap.String("device", device.Metadata().ID())), device, touchedDisks); err != nil {
return fmt.Errorf("failed to analyze block device: %w", err)
}
}
disks, err := safe.ReaderListAll[*block.Disk](ctx, r)
if err != nil {
return fmt.Errorf("failed to list disks: %w", err)
}
for iter := disks.Iterator(); iter.Next(); {
disk := iter.Value()
if _, ok := touchedDisks[disk.Metadata().ID()]; ok {
continue
}
if err = r.Destroy(ctx, disk.Metadata()); err != nil {
return fmt.Errorf("failed to remove disk: %w", err)
}
delete(lastObservedGenerations, disk.Metadata().ID())
}
}
}
func (ctrl *DisksController) analyzeBlockDevice(ctx context.Context, r controller.Runtime, logger *zap.Logger, device *block.Device, touchedDisks map[string]struct{}) error {
bd, err := blkdev.NewFromPath(filepath.Join("/dev", device.Metadata().ID()))
if err != nil {
logger.Debug("failed to open blockdevice", zap.Error(err))
return nil
}
size, err := bd.GetSize()
if err != nil || size == 0 {
return nil //nolint:nilerr
}
if privateDM, _ := bd.IsPrivateDeviceMapper(); privateDM { //nolint:errcheck
return nil
}
ioSize, err := bd.GetIOSize()
if err != nil {
logger.Debug("failed to get io size", zap.Error(err))
}
sectorSize := bd.GetSectorSize()
readOnly, err := bd.IsReadOnly()
if err != nil {
logger.Debug("failed to get read only", zap.Error(err))
}
props, err := bd.GetProperties()
if err != nil {
logger.Debug("failed to get properties", zap.Error(err))
}
touchedDisks[device.Metadata().ID()] = struct{}{}
return safe.WriterModify(ctx, r, block.NewDisk(block.NamespaceName, device.Metadata().ID()), func(d *block.Disk) error {
d.TypedSpec().Size = size
d.TypedSpec().IOSize = ioSize
d.TypedSpec().SectorSize = sectorSize
d.TypedSpec().Readonly = readOnly
d.TypedSpec().Model = props.Model
d.TypedSpec().Serial = props.Serial
d.TypedSpec().Modalias = props.Modalias
d.TypedSpec().WWID = props.WWID
d.TypedSpec().BusPath = props.BusPath
d.TypedSpec().SubSystem = props.SubSystem
d.TypedSpec().Transport = props.Transport
d.TypedSpec().Rotational = props.Rotational
return nil
})
}

View File

@ -0,0 +1,91 @@
// 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 block
import (
"context"
"fmt"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/cosi-project/runtime/pkg/state"
"go.uber.org/zap"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/resources/block"
)
// SystemDiskController provides a detailed view of blockdevices of type 'disk'.
type SystemDiskController struct{}
// Name implements controller.Controller interface.
func (ctrl *SystemDiskController) Name() string {
return "block.SystemDiskController"
}
// Inputs implements controller.Controller interface.
func (ctrl *SystemDiskController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: block.NamespaceName,
Type: block.DiscoveredVolumeType,
Kind: controller.InputWeak,
},
}
}
// Outputs implements controller.Controller interface.
func (ctrl *SystemDiskController) Outputs() []controller.Output {
return []controller.Output{
{
Type: block.SystemDiskType,
Kind: controller.OutputExclusive,
},
}
}
// Run implements controller.Controller interface.
//
//nolint:gocyclo
func (ctrl *SystemDiskController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
for {
select {
case <-r.EventCh():
case <-ctx.Done():
return nil
}
discoveredVolumes, err := safe.ReaderListAll[*block.DiscoveredVolume](ctx, r)
if err != nil {
return fmt.Errorf("failed to list discovered volumes: %w", err)
}
var systemDiskID string
for iter := discoveredVolumes.Iterator(); iter.Next(); {
volume := iter.Value()
if volume.TypedSpec().PartitionLabel == constants.MetaPartitionLabel {
systemDiskID = volume.TypedSpec().Parent
break
}
}
if systemDiskID != "" {
if err = safe.WriterModify(ctx, r, block.NewSystemDisk(block.NamespaceName, block.SystemDiskID), func(d *block.SystemDisk) error {
d.TypedSpec().DiskID = systemDiskID
return nil
}); err != nil {
return fmt.Errorf("failed to write system disk: %w", err)
}
} else {
if err = r.Destroy(ctx, block.NewSystemDisk(block.NamespaceName, block.SystemDiskID).Metadata()); err != nil && !state.IsNotFoundError(err) {
return fmt.Errorf("failed to destroy system disk: %w", err)
}
}
}
}

View File

@ -92,6 +92,8 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},
&block.DiscoveryController{},
&block.DisksController{},
&block.SystemDiskController{},
&cluster.AffiliateMergeController{},
cluster.NewConfigController(),
&cluster.DiscoveryServiceController{},

View File

@ -97,6 +97,8 @@ func NewState() (*State, error) {
for _, r := range []meta.ResourceWithRD{
&block.Device{},
&block.DiscoveredVolume{},
&block.Disk{},
&block.SystemDisk{},
&cluster.Affiliate{},
&cluster.Config{},
&cluster.Identity{},

View File

@ -7,17 +7,20 @@ package internal
import (
"context"
"path/filepath"
"github.com/siderolabs/gen/xslices"
bddisk "github.com/siderolabs/go-blockdevice/blockdevice/util/disk"
"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.
// TODO: this is not a full blown service yet, it's used as the common base in the machine and the maintenance services.
//
// It is only kept here for compatibility purposes, proper API is to query `block.Disk` resources.
type Server struct {
storage.UnimplementedStorageServiceServer
Controller runtime.Controller
@ -25,32 +28,48 @@ type Server struct {
// Disks implements storage.StorageService.
func (s *Server) Disks(ctx context.Context, in *emptypb.Empty) (reply *storage.DisksResponse, err error) {
disks, err := bddisk.List()
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
}
systemDisk := s.Controller.Runtime().State().Machine().Disk()
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
}
diskConv := func(d *bddisk.Disk) *storage.Disk {
return &storage.Disk{
DeviceName: d.DeviceName,
Model: d.Model,
Size: d.Size,
Name: d.Name,
Serial: d.Serial,
Modalias: d.Modalias,
Uuid: d.UUID,
Wwid: d.WWID,
Type: storage.Disk_DiskType(d.Type),
BusPath: d.BusPath,
SystemDisk: systemDisk != nil && d.DeviceName == systemDisk.Device().Name(),
Subsystem: d.SubSystem,
Readonly: d.ReadOnly,
}
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 := xslices.Map(disks, diskConv)
diskList, _ := safe.Map(disks, diskConv) //nolint:errcheck
reply = &storage.DisksResponse{
Messages: []*storage.Disks{

View File

@ -32,6 +32,10 @@ func (suite *VolumesSuite) SuiteName() string {
// SetupTest ...
func (suite *VolumesSuite) SetupTest() {
if !suite.Capabilities().SupportsVolumes {
suite.T().Skip("cluster doesn't support volumes")
}
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), time.Minute)
}
@ -44,10 +48,6 @@ func (suite *VolumesSuite) TearDownTest() {
// TestDiscoveredVolumes verifies that standard Talos partitions are discovered.
func (suite *VolumesSuite) TestDiscoveredVolumes() {
if !suite.Capabilities().SupportsVolumes {
suite.T().Skip("cluster doesn't support volumes")
}
for _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {
suite.Run(node, func() {
suite.testDiscoveredVolumes(node)
@ -114,6 +114,60 @@ func (suite *VolumesSuite) testDiscoveredVolumes(node string) {
}
}
// TestSystemDisk verifies that Talos system disk is discovered.
func (suite *VolumesSuite) TestSystemDisk() {
for _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {
suite.Run(node, func() {
ctx := client.WithNode(suite.ctx, node)
systemDisk, err := safe.StateGetByID[*block.SystemDisk](ctx, suite.Client.COSI, block.SystemDiskID)
suite.Require().NoError(err)
suite.Assert().NotEmpty(systemDisk.TypedSpec().DiskID)
suite.T().Logf("system disk: %s", systemDisk.TypedSpec().DiskID)
})
}
}
// TestDisks verifies that Talos discovers disks.
func (suite *VolumesSuite) TestDisks() {
for _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {
suite.Run(node, func() {
ctx := client.WithNode(suite.ctx, node)
disks, err := safe.StateListAll[*block.Disk](ctx, suite.Client.COSI)
suite.Require().NoError(err)
// there should be at least two disks - loop0 for Talos squashfs and a system disk
suite.Assert().Greater(disks.Len(), 1)
var diskNames []string
for iter := disks.Iterator(); iter.Next(); {
disk := iter.Value()
if disk.TypedSpec().Readonly {
continue
}
suite.Assert().NotEmpty(disk.TypedSpec().Size, "disk: %s", disk.Metadata().ID())
suite.Assert().NotEmpty(disk.TypedSpec().IOSize, "disk: %s", disk.Metadata().ID())
suite.Assert().NotEmpty(disk.TypedSpec().SectorSize, "disk: %s", disk.Metadata().ID())
if suite.Cluster != nil {
// running on our own provider, transport should be always detected
suite.Assert().NotEmpty(disk.TypedSpec().Transport, "disk: %s", disk.Metadata().ID())
}
diskNames = append(diskNames, disk.Metadata().ID())
}
suite.T().Logf("disks: %v", diskNames)
})
}
}
func init() {
allSuites = append(allSuites, new(VolumesSuite))
}

View File

@ -22,6 +22,10 @@ func (suite *DisksSuite) SuiteName() string {
// TestSuccess runs comand with success.
func (suite *DisksSuite) TestSuccess() {
if suite.Cluster != nil && suite.Cluster.Provisioner() == "docker" {
suite.T().Skip("docker provisioner doesn't support disks command")
}
suite.RunCLI([]string{"disks", "--nodes", suite.RandomDiscoveredNodeInternalIP()})
}

View File

@ -293,6 +293,190 @@ func (x *DiscoveredVolumeSpec) GetParent() string {
return ""
}
// DiskSpec is the spec for Disks status.
type DiskSpec struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Size uint64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
IoSize uint64 `protobuf:"varint,2,opt,name=io_size,json=ioSize,proto3" json:"io_size,omitempty"`
SectorSize uint64 `protobuf:"varint,3,opt,name=sector_size,json=sectorSize,proto3" json:"sector_size,omitempty"`
Readonly bool `protobuf:"varint,4,opt,name=readonly,proto3" json:"readonly,omitempty"`
Model string `protobuf:"bytes,5,opt,name=model,proto3" json:"model,omitempty"`
Serial string `protobuf:"bytes,6,opt,name=serial,proto3" json:"serial,omitempty"`
Modalias string `protobuf:"bytes,7,opt,name=modalias,proto3" json:"modalias,omitempty"`
Wwid string `protobuf:"bytes,8,opt,name=wwid,proto3" json:"wwid,omitempty"`
BusPath string `protobuf:"bytes,9,opt,name=bus_path,json=busPath,proto3" json:"bus_path,omitempty"`
SubSystem string `protobuf:"bytes,10,opt,name=sub_system,json=subSystem,proto3" json:"sub_system,omitempty"`
Transport string `protobuf:"bytes,11,opt,name=transport,proto3" json:"transport,omitempty"`
Rotational bool `protobuf:"varint,12,opt,name=rotational,proto3" json:"rotational,omitempty"`
}
func (x *DiskSpec) Reset() {
*x = DiskSpec{}
if protoimpl.UnsafeEnabled {
mi := &file_resource_definitions_block_block_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DiskSpec) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DiskSpec) ProtoMessage() {}
func (x *DiskSpec) ProtoReflect() protoreflect.Message {
mi := &file_resource_definitions_block_block_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DiskSpec.ProtoReflect.Descriptor instead.
func (*DiskSpec) Descriptor() ([]byte, []int) {
return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{2}
}
func (x *DiskSpec) GetSize() uint64 {
if x != nil {
return x.Size
}
return 0
}
func (x *DiskSpec) GetIoSize() uint64 {
if x != nil {
return x.IoSize
}
return 0
}
func (x *DiskSpec) GetSectorSize() uint64 {
if x != nil {
return x.SectorSize
}
return 0
}
func (x *DiskSpec) GetReadonly() bool {
if x != nil {
return x.Readonly
}
return false
}
func (x *DiskSpec) GetModel() string {
if x != nil {
return x.Model
}
return ""
}
func (x *DiskSpec) GetSerial() string {
if x != nil {
return x.Serial
}
return ""
}
func (x *DiskSpec) GetModalias() string {
if x != nil {
return x.Modalias
}
return ""
}
func (x *DiskSpec) GetWwid() string {
if x != nil {
return x.Wwid
}
return ""
}
func (x *DiskSpec) GetBusPath() string {
if x != nil {
return x.BusPath
}
return ""
}
func (x *DiskSpec) GetSubSystem() string {
if x != nil {
return x.SubSystem
}
return ""
}
func (x *DiskSpec) GetTransport() string {
if x != nil {
return x.Transport
}
return ""
}
func (x *DiskSpec) GetRotational() bool {
if x != nil {
return x.Rotational
}
return false
}
// SystemDiskSpec is the spec for SystemDisks status.
type SystemDiskSpec struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
DiskId string `protobuf:"bytes,1,opt,name=disk_id,json=diskId,proto3" json:"disk_id,omitempty"`
}
func (x *SystemDiskSpec) Reset() {
*x = SystemDiskSpec{}
if protoimpl.UnsafeEnabled {
mi := &file_resource_definitions_block_block_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SystemDiskSpec) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SystemDiskSpec) ProtoMessage() {}
func (x *SystemDiskSpec) ProtoReflect() protoreflect.Message {
mi := &file_resource_definitions_block_block_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SystemDiskSpec.ProtoReflect.Descriptor instead.
func (*SystemDiskSpec) Descriptor() ([]byte, []int) {
return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{3}
}
func (x *SystemDiskSpec) GetDiskId() string {
if x != nil {
return x.DiskId
}
return ""
}
var File_resource_definitions_block_block_proto protoreflect.FileDescriptor
var file_resource_definitions_block_block_proto_rawDesc = []byte{
@ -348,12 +532,36 @@ var file_resource_definitions_block_block_proto_rawDesc = []byte{
0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68,
0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61,
0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x10, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c,
0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61,
0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x44,
0x69, 0x73, 0x6b, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x69,
0x6f, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x69, 0x6f,
0x53, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73,
0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x65, 0x63, 0x74, 0x6f,
0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c,
0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12,
0x1a, 0x0a, 0x08, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x77,
0x77, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x77, 0x69, 0x64, 0x12,
0x19, 0x0a, 0x08, 0x62, 0x75, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x62, 0x75, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75,
0x62, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x73, 0x75, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x6f, 0x74, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x6f, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x22, 0x29, 0x0a, 0x0e, 0x53, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x44, 0x69, 0x73, 0x6b, 0x53, 0x70, 0x65, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, 0x73,
0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x73, 0x6b,
0x49, 0x64, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f,
0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66,
0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -368,10 +576,12 @@ func file_resource_definitions_block_block_proto_rawDescGZIP() []byte {
return file_resource_definitions_block_block_proto_rawDescData
}
var file_resource_definitions_block_block_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_resource_definitions_block_block_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_resource_definitions_block_block_proto_goTypes = []interface{}{
(*DeviceSpec)(nil), // 0: talos.resource.definitions.block.DeviceSpec
(*DiscoveredVolumeSpec)(nil), // 1: talos.resource.definitions.block.DiscoveredVolumeSpec
(*DiskSpec)(nil), // 2: talos.resource.definitions.block.DiskSpec
(*SystemDiskSpec)(nil), // 3: talos.resource.definitions.block.SystemDiskSpec
}
var file_resource_definitions_block_block_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
@ -411,6 +621,30 @@ func file_resource_definitions_block_block_proto_init() {
return nil
}
}
file_resource_definitions_block_block_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DiskSpec); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_resource_definitions_block_block_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SystemDiskSpec); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@ -418,7 +652,7 @@ func file_resource_definitions_block_block_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_resource_definitions_block_block_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},

View File

@ -233,6 +233,163 @@ func (m *DiscoveredVolumeSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error)
return len(dAtA) - i, nil
}
func (m *DiskSpec) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *DiskSpec) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *DiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.Rotational {
i--
if m.Rotational {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x60
}
if len(m.Transport) > 0 {
i -= len(m.Transport)
copy(dAtA[i:], m.Transport)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Transport)))
i--
dAtA[i] = 0x5a
}
if len(m.SubSystem) > 0 {
i -= len(m.SubSystem)
copy(dAtA[i:], m.SubSystem)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SubSystem)))
i--
dAtA[i] = 0x52
}
if len(m.BusPath) > 0 {
i -= len(m.BusPath)
copy(dAtA[i:], m.BusPath)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BusPath)))
i--
dAtA[i] = 0x4a
}
if len(m.Wwid) > 0 {
i -= len(m.Wwid)
copy(dAtA[i:], m.Wwid)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Wwid)))
i--
dAtA[i] = 0x42
}
if len(m.Modalias) > 0 {
i -= len(m.Modalias)
copy(dAtA[i:], m.Modalias)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Modalias)))
i--
dAtA[i] = 0x3a
}
if len(m.Serial) > 0 {
i -= len(m.Serial)
copy(dAtA[i:], m.Serial)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Serial)))
i--
dAtA[i] = 0x32
}
if len(m.Model) > 0 {
i -= len(m.Model)
copy(dAtA[i:], m.Model)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Model)))
i--
dAtA[i] = 0x2a
}
if m.Readonly {
i--
if m.Readonly {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x20
}
if m.SectorSize != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.SectorSize))
i--
dAtA[i] = 0x18
}
if m.IoSize != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.IoSize))
i--
dAtA[i] = 0x10
}
if m.Size != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func (m *SystemDiskSpec) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *SystemDiskSpec) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *SystemDiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.DiskId) > 0 {
i -= len(m.DiskId)
copy(dAtA[i:], m.DiskId)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DiskId)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *DeviceSpec) SizeVT() (n int) {
if m == nil {
return 0
@ -338,6 +495,73 @@ func (m *DiscoveredVolumeSpec) SizeVT() (n int) {
return n
}
func (m *DiskSpec) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Size != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.Size))
}
if m.IoSize != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.IoSize))
}
if m.SectorSize != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.SectorSize))
}
if m.Readonly {
n += 2
}
l = len(m.Model)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Serial)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Modalias)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Wwid)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.BusPath)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.SubSystem)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Transport)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.Rotational {
n += 2
}
n += len(m.unknownFields)
return n
}
func (m *SystemDiskSpec) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.DiskId)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@ -1065,3 +1289,458 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error {
}
return nil
}
func (m *DiskSpec) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: DiskSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: DiskSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType)
}
m.Size = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Size |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field IoSize", wireType)
}
m.IoSize = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.IoSize |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SectorSize", wireType)
}
m.SectorSize = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SectorSize |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Readonly", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Readonly = bool(v != 0)
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Model", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Model = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Serial", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Serial = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 7:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Modalias", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Modalias = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Wwid", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Wwid = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field BusPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.BusPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 10:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SubSystem", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SubSystem = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 11:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Transport", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Transport = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 12:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Rotational", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Rotational = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *SystemDiskSpec) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: SystemDiskSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: SystemDiskSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field DiskId", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.DiskId = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}

View File

@ -11,7 +11,7 @@ import (
"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1"
)
//go:generate deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
//go:generate deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiskSpec -type SystemDiskSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
// NamespaceName contains configuration resources.
const NamespaceName resource.Namespace = v1alpha1.NamespaceName

View File

@ -27,6 +27,8 @@ func TestRegisterResource(t *testing.T) {
for _, resource := range []meta.ResourceWithRD{
&block.Device{},
&block.DiscoveredVolume{},
&block.Disk{},
&block.SystemDisk{},
} {
assert.NoError(t, resourceRegistry.Register(ctx, resource))
}

View File

@ -2,7 +2,7 @@
// 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/.
// Code generated by "deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
// Code generated by "deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiskSpec -type SystemDiskSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
package block
@ -17,3 +17,15 @@ func (o DiscoveredVolumeSpec) DeepCopy() DiscoveredVolumeSpec {
var cp DiscoveredVolumeSpec = o
return cp
}
// DeepCopy generates a deep copy of DiskSpec.
func (o DiskSpec) DeepCopy() DiskSpec {
var cp DiskSpec = o
return cp
}
// DeepCopy generates a deep copy of SystemDiskSpec.
func (o SystemDiskSpec) DeepCopy() SystemDiskSpec {
var cp SystemDiskSpec = o
return cp
}

View File

@ -0,0 +1,99 @@
// 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 block
import (
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/meta"
"github.com/cosi-project/runtime/pkg/resource/protobuf"
"github.com/cosi-project/runtime/pkg/resource/typed"
"github.com/siderolabs/talos/pkg/machinery/proto"
)
// DiskType is type of Disk resource.
const DiskType = resource.Type("Disks.block.talos.dev")
// Disk resource holds status of hardware disks.
type Disk = typed.Resource[DiskSpec, DiskExtension]
// DiskSpec is the spec for Disks status.
//
//gotagsrewrite:gen
type DiskSpec struct {
Size uint64 `yaml:"size" protobuf:"1"`
IOSize uint `yaml:"ioSize" protobuf:"2"`
SectorSize uint `yaml:"sectorSize" protobuf:"3"`
Readonly bool `yaml:"readonly" protobuf:"4"`
Model string `yaml:"model,omitempty" protobuf:"5"`
Serial string `yaml:"serial,omitempty" protobuf:"6"`
Modalias string `yaml:"modalias,omitempty" protobuf:"7"`
WWID string `yaml:"wwid,omitempty" protobuf:"8"`
BusPath string `yaml:"busPath,omitempty" protobuf:"9"`
SubSystem string `yaml:"subSystem,omitempty" protobuf:"10"`
Transport string `yaml:"transport,omitempty" protobuf:"11"`
Rotational bool `yaml:"rotational,omitempty" protobuf:"12"`
}
// NewDisk initializes a BlockDisk resource.
func NewDisk(namespace resource.Namespace, id resource.ID) *Disk {
return typed.NewResource[DiskSpec, DiskExtension](
resource.NewMetadata(namespace, DiskType, id, resource.VersionUndefined),
DiskSpec{},
)
}
// DiskExtension is auxiliary resource data for BlockDisk.
type DiskExtension struct{}
// ResourceDefinition implements meta.ResourceDefinitionProvider interface.
func (DiskExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
return meta.ResourceDefinitionSpec{
Type: DiskType,
Aliases: []resource.Type{},
DefaultNamespace: NamespaceName,
PrintColumns: []meta.PrintColumn{
{
Name: "Size",
JSONPath: `{.size}`,
},
{
Name: "Read Only",
JSONPath: `{.readonly}`,
},
{
Name: "Transport",
JSONPath: `{.transport}`,
},
{
Name: "Rotational",
JSONPath: `{.rotational}`,
},
{
Name: "WWID",
JSONPath: `{.wwid}`,
},
{
Name: "Model",
JSONPath: `{.model}`,
},
{
Name: "Serial",
JSONPath: `{.serial}`,
},
},
}
}
func init() {
proto.RegisterDefaultTypes()
err := protobuf.RegisterDynamic[DiskSpec](DiskType, &Disk{})
if err != nil {
panic(err)
}
}

View File

@ -0,0 +1,65 @@
// 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 block
import (
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/meta"
"github.com/cosi-project/runtime/pkg/resource/protobuf"
"github.com/cosi-project/runtime/pkg/resource/typed"
"github.com/siderolabs/talos/pkg/machinery/proto"
)
// SystemDiskType is type of SystemDisk resource.
const SystemDiskType = resource.Type("SystemDisks.block.talos.dev")
// SystemDisk resource holds ID of the disk which is the Talos system disk.
type SystemDisk = typed.Resource[SystemDiskSpec, SystemDiskExtension]
// SystemDiskID is the singleton resource ID.
const SystemDiskID resource.ID = "system-disk"
// SystemDiskSpec is the spec for SystemDisks status.
//
//gotagsrewrite:gen
type SystemDiskSpec struct {
DiskID string `yaml:"diskID" protobuf:"1"`
}
// NewSystemDisk initializes a BlockSystemDisk resource.
func NewSystemDisk(namespace resource.Namespace, id resource.ID) *SystemDisk {
return typed.NewResource[SystemDiskSpec, SystemDiskExtension](
resource.NewMetadata(namespace, SystemDiskType, id, resource.VersionUndefined),
SystemDiskSpec{},
)
}
// SystemDiskExtension is auxiliary resource data for BlockSystemDisk.
type SystemDiskExtension struct{}
// ResourceDefinition implements meta.ResourceDefinitionProvider interface.
func (SystemDiskExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
return meta.ResourceDefinitionSpec{
Type: SystemDiskType,
Aliases: []resource.Type{},
DefaultNamespace: NamespaceName,
PrintColumns: []meta.PrintColumn{
{
Name: "Disk",
JSONPath: `{.diskID}`,
},
},
}
}
func init() {
proto.RegisterDefaultTypes()
err := protobuf.RegisterDynamic[SystemDiskSpec](SystemDiskType, &SystemDisk{})
if err != nil {
panic(err)
}
}

View File

@ -40,6 +40,7 @@ type LaunchConfig struct {
// VM options
DiskPaths []string
DiskDrivers []string
VCPUCount int64
MemSize int64
QemuExecutable string
@ -327,26 +328,65 @@ func launchVM(config *LaunchConfig) error {
"-no-reboot",
"-boot", fmt.Sprintf("order=%s,reboot-timeout=5000", bootOrder),
"-smbios", fmt.Sprintf("type=1,uuid=%s", config.NodeUUID),
"-chardev",
fmt.Sprintf("socket,path=%s/%s.sock,server=on,wait=off,id=qga0", config.StatePath, config.Hostname),
"-device",
"virtio-serial",
"-device",
"virtserialport,chardev=qga0,name=org.qemu.guest_agent.0",
"-device",
"i6300esb,id=watchdog0",
"-chardev", fmt.Sprintf("socket,path=%s/%s.sock,server=on,wait=off,id=qga0", config.StatePath, config.Hostname),
"-device", "virtio-serial",
"-device", "virtserialport,chardev=qga0,name=org.qemu.guest_agent.0",
"-device", "i6300esb,id=watchdog0",
"-watchdog-action",
"pause",
}
for i, disk := range config.DiskPaths {
driver := "virtio"
var (
scsiAttached, ahciAttached, nvmeAttached bool
ahciBus int
)
if i > 0 {
driver = "ide"
for i, disk := range config.DiskPaths {
driver := config.DiskDrivers[i]
switch driver {
case "virtio":
args = append(args, "-drive", fmt.Sprintf("format=raw,if=virtio,file=%s,cache=none,", disk))
case "ide":
args = append(args, "-drive", fmt.Sprintf("format=raw,if=ide,file=%s,cache=none,", disk))
case "ahci":
if !ahciAttached {
args = append(args, "-device", "ahci,id=ahci0")
ahciAttached = true
}
args = append(args, "-drive", fmt.Sprintf("format=raw,if=%s,file=%s,cache=unsafe", driver, disk))
args = append(args,
"-drive", fmt.Sprintf("id=ide%d,format=raw,if=none,file=%s", i, disk),
"-device", fmt.Sprintf("ide-hd,drive=ide%d,bus=ahci0.%d", i, ahciBus),
)
ahciBus++
case "scsi":
if !scsiAttached {
args = append(args, "-device", "virtio-scsi-pci,id=scsi0")
scsiAttached = true
}
args = append(args,
"-drive", fmt.Sprintf("id=scsi%d,format=raw,if=none,file=%s,discard=unmap,aio=native,cache=none", i, disk),
"-device", fmt.Sprintf("scsi-hd,drive=scsi%d,bus=scsi0.0", i),
)
case "nvme":
if !nvmeAttached {
// [TODO]: once Talos is fixed, use multipath NVME: https://qemu-project.gitlab.io/qemu/system/devices/nvme.html
args = append(args,
"-device", "nvme,id=nvme-ctrl-0,serial=deadbeef",
)
nvmeAttached = true
}
args = append(args,
"-drive", fmt.Sprintf("id=nvme%d,format=raw,if=none,file=%s,discard=unmap,aio=native,cache=none", i, disk),
"-device", fmt.Sprintf("nvme-ns,drive=nvme%d", i),
)
default:
return fmt.Errorf("unsupported disk driver %q", driver)
}
}
machineArg := config.MachineType

View File

@ -19,6 +19,7 @@ import (
"github.com/google/uuid"
"github.com/hashicorp/go-multierror"
"github.com/siderolabs/gen/xslices"
"github.com/siderolabs/go-procfs/procfs"
"github.com/siderolabs/talos/pkg/machinery/constants"
@ -114,9 +115,25 @@ func (p *provisioner) createNode(state *vm.State, clusterReq provision.ClusterRe
defaultBootOrder = nodeReq.DefaultBootOrder
}
// backwards compatibility, set Driver if not set
for i := range nodeReq.Disks {
if nodeReq.Disks[i].Driver != "" {
continue
}
if i == 0 {
nodeReq.Disks[i].Driver = "virtio"
} else {
nodeReq.Disks[i].Driver = "ide"
}
}
launchConfig := LaunchConfig{
QemuExecutable: arch.QemuExecutable(),
DiskPaths: diskPaths,
DiskDrivers: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) string {
return disk.Driver
}),
VCPUCount: vcpuCount,
MemSize: memSize,
KernelArgs: cmdline.String(),

View File

@ -158,6 +158,10 @@ type Disk struct {
SkipPreallocate bool
// Partitions represents the list of partitions.
Partitions []*v1alpha1.DiskPartition
// Driver for the disk.
//
// Supported types: "virtio", "ide", "ahci", "scsi", "nvme".
Driver string
}
// NodeRequest describes a request for a node.

View File

@ -29,6 +29,8 @@ description: Talos gRPC API reference.
- [resource/definitions/block/block.proto](#resource/definitions/block/block.proto)
- [DeviceSpec](#talos.resource.definitions.block.DeviceSpec)
- [DiscoveredVolumeSpec](#talos.resource.definitions.block.DiscoveredVolumeSpec)
- [DiskSpec](#talos.resource.definitions.block.DiskSpec)
- [SystemDiskSpec](#talos.resource.definitions.block.SystemDiskSpec)
- [resource/definitions/cluster/cluster.proto](#resource/definitions/cluster/cluster.proto)
- [AffiliateSpec](#talos.resource.definitions.cluster.AffiliateSpec)
@ -813,6 +815,47 @@ DiscoveredVolumeSpec is the spec for DiscoveredVolumes status.
<a name="talos.resource.definitions.block.DiskSpec"></a>
### DiskSpec
DiskSpec is the spec for Disks status.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| size | [uint64](#uint64) | | |
| io_size | [uint64](#uint64) | | |
| sector_size | [uint64](#uint64) | | |
| readonly | [bool](#bool) | | |
| model | [string](#string) | | |
| serial | [string](#string) | | |
| modalias | [string](#string) | | |
| wwid | [string](#string) | | |
| bus_path | [string](#string) | | |
| sub_system | [string](#string) | | |
| transport | [string](#string) | | |
| rotational | [bool](#bool) | | |
<a name="talos.resource.definitions.block.SystemDiskSpec"></a>
### SystemDiskSpec
SystemDiskSpec is the spec for SystemDisks status.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| disk_id | [string](#string) | | |
<!-- end messages -->
<!-- end enums -->

View File

@ -122,6 +122,7 @@ talosctl cluster create [flags]
-p, --exposed-ports string Comma-separated list of ports/protocols to expose on init node. Ex -p <hostPort>:<containerPort>/<protocol (tcp or udp)> (Docker provisioner only)
--extra-boot-kernel-args string add extra kernel args to the initial boot from vmlinuz and initramfs (QEMU only)
--extra-disks int number of extra disks to create for each worker VM
--extra-disks-drivers strings driver for each extra disk (virtio, ide, ahci, scsi, nvme)
--extra-disks-size int default limit on disk size in MB (each VM) (default 5120)
--extra-uefi-search-paths strings additional search paths for UEFI firmware (only applies when UEFI is enabled)
-h, --help help for create