Skip to content

Commit

Permalink
feat: add configuration for EPHEMERAL volume
Browse files Browse the repository at this point in the history
Fixes #9261

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
  • Loading branch information
smira committed Sep 6, 2024
1 parent faffa4c commit 3038ccf
Show file tree
Hide file tree
Showing 47 changed files with 1,614 additions and 80 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2024-09-03T14:18:03Z by kres b5ca957.
# Generated on 2024-09-05T10:32:02Z by kres b5ca957.

name: default
concurrency:
Expand Down Expand Up @@ -2556,6 +2556,10 @@ jobs:
- name: e2e-qemu
env:
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_EXTRA_DISKS: "2"
QEMU_EXTRA_DISKS_DRIVERS: ide,nvme
QEMU_EXTRA_DISKS_SIZE: "10240"
WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml'
run: |
sudo -E make e2e-qemu
- name: save artifacts
Expand Down Expand Up @@ -2855,6 +2859,10 @@ jobs:
- name: e2e-qemu
env:
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_EXTRA_DISKS: "2"
QEMU_EXTRA_DISKS_DRIVERS: ide,nvme
QEMU_EXTRA_DISKS_SIZE: "10240"
WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml'
WITH_DISK_ENCRYPTION: "true"
WITH_KUBESPAN: "true"
WITH_VIRTUAL_IP: "true"
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/integration-qemu-cron.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2024-05-27T16:20:10Z by kres bcb280a.
# Generated on 2024-09-04T16:05:13Z by kres b5ca957.

name: integration-qemu-cron
concurrency:
Expand Down Expand Up @@ -77,6 +77,10 @@ jobs:
- name: e2e-qemu
env:
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_EXTRA_DISKS: "2"
QEMU_EXTRA_DISKS_DRIVERS: ide,nvme
QEMU_EXTRA_DISKS_SIZE: "10240"
WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml'
run: |
sudo -E make e2e-qemu
- name: save artifacts
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/integration-qemu-encrypted-vip-cron.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.
#
# Generated on 2024-05-27T16:20:10Z by kres bcb280a.
# Generated on 2024-09-05T10:32:02Z by kres b5ca957.

name: integration-qemu-encrypted-vip-cron
concurrency:
Expand Down Expand Up @@ -77,6 +77,10 @@ jobs:
- name: e2e-qemu
env:
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_EXTRA_DISKS: "2"
QEMU_EXTRA_DISKS_DRIVERS: ide,nvme
QEMU_EXTRA_DISKS_SIZE: "10240"
WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml'
WITH_DISK_ENCRYPTION: "true"
WITH_KUBESPAN: "true"
WITH_VIRTUAL_IP: "true"
Expand Down
8 changes: 8 additions & 0 deletions .kres.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ spec:
withSudo: true
environment:
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_EXTRA_DISKS: "2"
QEMU_EXTRA_DISKS_SIZE: "10240"
QEMU_EXTRA_DISKS_DRIVERS: "ide,nvme"
WITH_CONFIG_PATCH_WORKER: "@hack/test/patches/ephemeral-nvme.yaml"
- name: save-talos-logs
conditions:
- always
Expand Down Expand Up @@ -1098,6 +1102,10 @@ spec:
WITH_VIRTUAL_IP: true
WITH_KUBESPAN: true
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_EXTRA_DISKS: "2"
QEMU_EXTRA_DISKS_SIZE: "10240"
QEMU_EXTRA_DISKS_DRIVERS: "ide,nvme"
WITH_CONFIG_PATCH_WORKER: "@hack/test/patches/ephemeral-nvme.yaml"
- name: save-talos-logs
conditions:
- always
Expand Down
1 change: 1 addition & 0 deletions api/resource/definitions/block/block.proto
Original file line number Diff line number Diff line change
Expand Up @@ -164,5 +164,6 @@ message VolumeStatusSpec {
talos.resource.definitions.enums.BlockFilesystemType filesystem = 10;
string mount_location = 11;
talos.resource.definitions.enums.BlockEncryptionProviderType encryption_provider = 12;
string pretty_size = 13;
}

5 changes: 5 additions & 0 deletions cmd/talosctl/cmd/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"gopkg.in/yaml.v3"

"github.com/siderolabs/talos/pkg/machinery/config/encoder"
"github.com/siderolabs/talos/pkg/machinery/config/types/block"
"github.com/siderolabs/talos/pkg/machinery/config/types/network"
"github.com/siderolabs/talos/pkg/machinery/config/types/runtime"
"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions"
Expand Down Expand Up @@ -130,6 +131,10 @@ var docsCmd = &cobra.Command{
name: "security",
fileDoc: security.GetFileDoc(),
},
{
name: "block",
fileDoc: block.GetFileDoc(),
},
} {
path := filepath.Join(dir, pkg.name)

Expand Down
6 changes: 6 additions & 0 deletions hack/release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ This can be also explicitly enabled by setting `talos.halt_if_installed=1` in ke
description = """\
Talos Linux installer now never wipes the system disk on upgrades, which means that the flag
`--preserve` is always set for `talosctl upgrade`.
"""

[notes.disk-management]
title = "Disk Management"
description = """\
Talos Linux now supports [configuration](https://www.talos.dev/v1.8/talos-guides/configuration/disk-management/#machine-configuration) for the `EPHEMERAL` volume.
"""

[make_deps]
Expand Down
1 change: 1 addition & 0 deletions hack/test/e2e-qemu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ function create_cluster {
--disk=15360 \
--extra-disks="${QEMU_EXTRA_DISKS:-0}" \
--extra-disks-size="${QEMU_EXTRA_DISKS_SIZE:-5120}" \
--extra-disks-drivers="${QEMU_EXTRA_DISKS_DRIVERS:-}" \
--mtu=1430 \
--memory=2048 \
--memory-workers="${QEMU_MEMORY_WORKERS:-2048}" \
Expand Down
8 changes: 8 additions & 0 deletions hack/test/patches/ephemeral-nvme.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1alpha1
kind: VolumeConfig
name: EPHEMERAL
provisioning:
diskSelector:
match: disk.transport == 'nvme'
minSize: 4GB
maxSize: 8GB
14 changes: 5 additions & 9 deletions internal/app/machined/pkg/controllers/block/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/cosi-project/runtime/pkg/state"
"github.com/dustin/go-humanize"
"github.com/siderolabs/gen/maps"
"github.com/siderolabs/go-blockdevice/v2/blkid"
"github.com/siderolabs/go-blockdevice/v2/partitioning"
Expand Down Expand Up @@ -208,8 +207,7 @@ func (ctrl *DiscoveryController) rescan(ctx context.Context, r controller.Runtim
dv.TypedSpec().Parent = device.TypedSpec().Parent
dv.TypedSpec().ParentDevPath = filepath.Join("/dev", device.TypedSpec().Parent)

dv.TypedSpec().Size = info.Size
dv.TypedSpec().PrettySize = humanize.Bytes(info.Size)
dv.TypedSpec().SetSize(info.Size)
dv.TypedSpec().SectorSize = info.SectorSize
dv.TypedSpec().IOSize = info.IOSize

Expand All @@ -232,14 +230,12 @@ func (ctrl *DiscoveryController) rescan(ctx context.Context, r controller.Runtim
dv.TypedSpec().Parent = id
dv.TypedSpec().ParentDevPath = filepath.Join("/dev", id)

dv.TypedSpec().Size = nested.ProbedSize

if dv.TypedSpec().Size == 0 {
dv.TypedSpec().Size = nested.PartitionSize
if nested.ProbedSize != 0 {
dv.TypedSpec().SetSize(nested.ProbedSize)
} else {
dv.TypedSpec().SetSize(nested.PartitionSize)
}

dv.TypedSpec().PrettySize = humanize.Bytes(dv.TypedSpec().Size)

dv.TypedSpec().SectorSize = info.SectorSize
dv.TypedSpec().IOSize = info.IOSize

Expand Down
5 changes: 2 additions & 3 deletions internal/app/machined/pkg/controllers/block/disks.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/dustin/go-humanize"
blkdev "github.com/siderolabs/go-blockdevice/v2/block"
"go.uber.org/zap"

Expand Down Expand Up @@ -157,9 +156,9 @@ func (ctrl *DisksController) analyzeBlockDevice(ctx context.Context, r controlle
touchedDisks[device.Metadata().ID()] = struct{}{}

return safe.WriterModify(ctx, r, block.NewDisk(block.NamespaceName, device.Metadata().ID()), func(d *block.Disk) error {
d.TypedSpec().SetSize(size)

d.TypedSpec().DevPath = filepath.Join("/dev", device.Metadata().ID())
d.TypedSpec().Size = size
d.TypedSpec().PrettySize = humanize.Bytes(size)
d.TypedSpec().IOSize = ioSize
d.TypedSpec().SectorSize = sectorSize
d.TypedSpec().Readonly = readOnly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func Grow(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext)
}

volumeContext.Status.Phase = block.VolumePhaseProvisioned
volumeContext.Status.Size += availableGrowth
volumeContext.Status.SetSize(volumeContext.Status.Size + availableGrowth)

return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func LocateAndProvision(ctx context.Context, logger *zap.Logger, volumeContext M

volumeContext.Status.UUID = dv.Uuid
volumeContext.Status.PartitionUUID = dv.PartitionUuid
volumeContext.Status.Size = dv.Size
volumeContext.Status.SetSize(dv.Size)

return nil
}
Expand Down Expand Up @@ -138,7 +138,7 @@ func LocateAndProvision(ctx context.Context, logger *zap.Logger, volumeContext M
volumeContext.Status.Phase = block.VolumePhaseProvisioned
volumeContext.Status.Location = pickedDisk
volumeContext.Status.ParentLocation = ""
volumeContext.Status.Size = diskCheckResult.DiskSize
volumeContext.Status.SetSize(diskCheckResult.DiskSize)
case block.VolumeTypePartition:
// we need to create a partition on the disk
partitionCreateResult, err := CreatePartition(ctx, logger, pickedDisk, volumeContext.Cfg, diskCheckResult.HasGPT)
Expand All @@ -151,7 +151,7 @@ func LocateAndProvision(ctx context.Context, logger *zap.Logger, volumeContext M
volumeContext.Status.PartitionIndex = partitionCreateResult.PartitionIdx
volumeContext.Status.ParentLocation = pickedDisk
volumeContext.Status.PartitionUUID = partitionCreateResult.Partition.PartGUID.String()
volumeContext.Status.Size = partitionCreateResult.Size
volumeContext.Status.SetSize(partitionCreateResult.Size)
default:
panic("unexpected volume type")
}
Expand Down
9 changes: 6 additions & 3 deletions internal/app/machined/pkg/controllers/block/volume_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,16 +204,19 @@ func (ctrl *VolumeConfigController) Run(ctx context.Context, r controller.Runtim

func (ctrl *VolumeConfigController) manageEphemeral(config cfg.Config) func(vc *block.VolumeConfig) error {
return func(vc *block.VolumeConfig) error {
extraVolumeConfig := config.Volumes().ByName(constants.EphemeralPartitionLabel)

vc.TypedSpec().Type = block.VolumeTypePartition

vc.TypedSpec().Provisioning = block.ProvisioningSpec{
Wave: block.WaveSystemDisk,
DiskSelector: block.DiskSelector{
Match: systemDiskMatch(),
Match: extraVolumeConfig.Provisioning().DiskSelector().ValueOr(systemDiskMatch()),
},
PartitionSpec: block.PartitionSpec{
MinSize: partition.EphemeralMinSize,
Grow: true,
MinSize: extraVolumeConfig.Provisioning().MinSize().ValueOr(partition.EphemeralMinSize),
MaxSize: extraVolumeConfig.Provisioning().MaxSize().ValueOr(0),
Grow: extraVolumeConfig.Provisioning().Grow().ValueOr(true),
Label: constants.EphemeralPartitionLabel,
TypeUUID: partition.LinuxFilesystemData,
},
Expand Down
62 changes: 62 additions & 0 deletions internal/app/machined/pkg/controllers/block/volume_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ import (
"testing"
"time"

"github.com/siderolabs/go-pointer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"

blockctrls "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block"
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
"github.com/siderolabs/talos/internal/pkg/partition"
"github.com/siderolabs/talos/pkg/machinery/cel"
"github.com/siderolabs/talos/pkg/machinery/cel/celenv"
"github.com/siderolabs/talos/pkg/machinery/config/container"
blockcfg "github.com/siderolabs/talos/pkg/machinery/config/types/block"
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/meta"
Expand Down Expand Up @@ -105,6 +110,14 @@ func (suite *VolumeConfigSuite) TestReconcileDefaults() {
asrt.NoError(err)
asrt.Equal(`volume.partition_label == "EPHEMERAL"`, string(locator))

locator, err = r.TypedSpec().Provisioning.DiskSelector.Match.MarshalText()
asrt.NoError(err)
asrt.Equal(`system_disk`, string(locator))

asrt.True(r.TypedSpec().Provisioning.PartitionSpec.Grow)
asrt.EqualValues(0, r.TypedSpec().Provisioning.PartitionSpec.MaxSize)
asrt.EqualValues(partition.EphemeralMinSize, r.TypedSpec().Provisioning.PartitionSpec.MinSize)

asrt.Equal(constants.EphemeralMountPoint, r.TypedSpec().Mount.TargetPath)
})
}
Expand Down Expand Up @@ -198,3 +211,52 @@ func (suite *VolumeConfigSuite) TestReconcileEncryptedSTATE() {
asrt.Empty(r.TypedSpec().Encryption)
})
}

func (suite *VolumeConfigSuite) TestReconcileExtraEPHEMERALConfig() {
ctest.AssertNoResource[*block.VolumeConfig](suite, constants.EphemeralPartitionLabel)

u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err)

ctr, err := container.New(
&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
ClusterConfig: &v1alpha1.ClusterConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
},
},
&blockcfg.VolumeConfigV1Alpha1{
MetaName: constants.EphemeralPartitionLabel,
ProvisioningSpec: blockcfg.ProvisioningSpec{
DiskSelectorSpec: blockcfg.DiskSelector{
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == "nvme"`, celenv.DiskLocator())),
},
ProvisioningGrow: pointer.To(false),
ProvisioningMaxSize: blockcfg.MustByteSize("2.5TiB"),
},
},
)
suite.Require().NoError(err)

cfg := config.NewMachineConfig(ctr)
suite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))

// now the volume config should be created
ctest.AssertResource(suite, constants.EphemeralPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {
asrt.NotEmpty(r.TypedSpec().Provisioning)
asrt.Empty(r.TypedSpec().Encryption)

locator, err := r.TypedSpec().Provisioning.DiskSelector.Match.MarshalText()
asrt.NoError(err)
asrt.Equal(`disk.transport == "nvme"`, string(locator))

asrt.False(r.TypedSpec().Provisioning.PartitionSpec.Grow)
asrt.EqualValues(2.5*1024*1024*1024*1024, r.TypedSpec().Provisioning.PartitionSpec.MaxSize)
asrt.EqualValues(partition.EphemeralMinSize, r.TypedSpec().Provisioning.PartitionSpec.MinSize)
})
}
Loading

0 comments on commit 3038ccf

Please sign in to comment.