diff --git a/api/resource/definitions/block/block.proto b/api/resource/definitions/block/block.proto
index 63f1e33fb..21e2606c2 100755
--- a/api/resource/definitions/block/block.proto
+++ b/api/resource/definitions/block/block.proto
@@ -158,6 +158,7 @@ message PartitionSpec {
bool grow = 3;
string label = 4;
string type_uuid = 5;
+ uint64 relative_max_size = 6;
}
// ProvisioningSpec is the spec for volume provisioning.
diff --git a/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/qemu.go b/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/qemu.go
index 8f9dc5846..448bb8217 100644
--- a/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/qemu.go
+++ b/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/qemu.go
@@ -536,7 +536,7 @@ func (m *Qemu) initExtraDisks() error {
Match: cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf("'%s' in disk.symlinks", m.Provisioner.UserDiskName(diskID+1)), celenv.DiskLocator())),
},
ProvisioningMinSize: block.MustByteSize(volumeSize),
- ProvisioningMaxSize: block.MustByteSize(volumeSize),
+ ProvisioningMaxSize: block.MustSize(volumeSize),
}
userVolume.EncryptionSpec = encryptionSpec
diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/partition.go b/internal/app/machined/pkg/controllers/block/internal/volumes/partition.go
index fb26684be..15bd357c5 100644
--- a/internal/app/machined/pkg/controllers/block/internal/volumes/partition.go
+++ b/internal/app/machined/pkg/controllers/block/internal/volumes/partition.go
@@ -64,7 +64,7 @@ func CreatePartition(ctx context.Context, logger *zap.Logger, diskPath string, v
available := pt.LargestContiguousAllocatable()
size := volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize
- maxSize := volumeCfg.TypedSpec().Provisioning.PartitionSpec.MaxSize
+ maxSize := volumeCfg.TypedSpec().Provisioning.PartitionSpec.ResolveMaxSize(available)
if available < size {
// should never happen
diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes.go b/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes.go
index aa7c96fa7..03da19f49 100644
--- a/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes.go
+++ b/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes.go
@@ -113,11 +113,12 @@ func GetEphemeralVolumeTransformer(inContainer bool) volumeConfigTransformer {
Match: extraVolumeConfig.Provisioning().DiskSelector().ValueOr(systemDiskMatch()),
},
PartitionSpec: block.PartitionSpec{
- MinSize: extraVolumeConfig.Provisioning().MinSize().ValueOr(quirks.New("").PartitionSizes().EphemeralMinSize()),
- MaxSize: extraVolumeConfig.Provisioning().MaxSize().ValueOr(0),
- Grow: extraVolumeConfig.Provisioning().Grow().ValueOr(true),
- Label: constants.EphemeralPartitionLabel,
- TypeUUID: partition.LinuxFilesystemData,
+ MinSize: extraVolumeConfig.Provisioning().MinSize().ValueOr(quirks.New("").PartitionSizes().EphemeralMinSize()),
+ MaxSize: extraVolumeConfig.Provisioning().MaxSize().ValueOrZero(),
+ RelativeMaxSize: extraVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),
+ Grow: extraVolumeConfig.Provisioning().Grow().ValueOr(true),
+ Label: constants.EphemeralPartitionLabel,
+ TypeUUID: partition.LinuxFilesystemData,
},
FilesystemSpec: block.FilesystemSpec{
Type: block.FilesystemTypeXFS,
diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes_test.go b/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes_test.go
index 26ef89931..5449929e2 100644
--- a/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes_test.go
+++ b/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes_test.go
@@ -422,7 +422,7 @@ func TestEphemeralVolumeTransformerWithExtraConfig(t *testing.T) {
ephemeralConfig := blockcfg.NewVolumeConfigV1Alpha1()
ephemeralConfig.MetaName = constants.EphemeralPartitionLabel
ephemeralConfig.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("10GiB")
- ephemeralConfig.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("100GiB")
+ ephemeralConfig.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("100GiB")
cfg, err := container.New(
baseCfg.DeepCopy(),
diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/user_volumes.go b/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/user_volumes.go
index efeba5adc..86925a518 100644
--- a/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/user_volumes.go
+++ b/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/user_volumes.go
@@ -100,11 +100,12 @@ func UserVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {
Match: userVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch),
},
PartitionSpec: block.PartitionSpec{
- MinSize: cmp.Or(userVolumeConfig.Provisioning().MinSize().ValueOrZero(), MinUserVolumeSize),
- MaxSize: userVolumeConfig.Provisioning().MaxSize().ValueOrZero(),
- Grow: userVolumeConfig.Provisioning().Grow().ValueOrZero(),
- Label: volumeID,
- TypeUUID: partition.LinuxFilesystemData,
+ MinSize: cmp.Or(userVolumeConfig.Provisioning().MinSize().ValueOrZero(), MinUserVolumeSize),
+ MaxSize: userVolumeConfig.Provisioning().MaxSize().ValueOrZero(),
+ RelativeMaxSize: userVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),
+ Grow: userVolumeConfig.Provisioning().Grow().ValueOrZero(),
+ Label: volumeID,
+ TypeUUID: partition.LinuxFilesystemData,
},
FilesystemSpec: block.FilesystemSpec{
Type: userVolumeConfig.Filesystem().Type(),
@@ -157,11 +158,12 @@ func RawVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {
Match: rawVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch),
},
PartitionSpec: block.PartitionSpec{
- MinSize: cmp.Or(rawVolumeConfig.Provisioning().MinSize().ValueOrZero(), MinUserVolumeSize),
- MaxSize: rawVolumeConfig.Provisioning().MaxSize().ValueOrZero(),
- Grow: rawVolumeConfig.Provisioning().Grow().ValueOrZero(),
- Label: volumeID,
- TypeUUID: partition.LinuxFilesystemData,
+ MinSize: cmp.Or(rawVolumeConfig.Provisioning().MinSize().ValueOrZero(), MinUserVolumeSize),
+ MaxSize: rawVolumeConfig.Provisioning().MaxSize().ValueOrZero(),
+ RelativeMaxSize: rawVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),
+ Grow: rawVolumeConfig.Provisioning().Grow().ValueOrZero(),
+ Label: volumeID,
+ TypeUUID: partition.LinuxFilesystemData,
},
FilesystemSpec: block.FilesystemSpec{
Type: block.FilesystemTypeNone,
@@ -230,10 +232,11 @@ func SwapVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {
Match: swapVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch),
},
PartitionSpec: block.PartitionSpec{
- MaxSize: cmp.Or(swapVolumeConfig.Provisioning().MaxSize().ValueOrZero(), MinUserVolumeSize),
- Grow: swapVolumeConfig.Provisioning().Grow().ValueOrZero(),
- Label: volumeID,
- TypeUUID: partition.LinkSwap,
+ MaxSize: cmp.Or(swapVolumeConfig.Provisioning().MaxSize().ValueOrZero(), MinUserVolumeSize),
+ RelativeMaxSize: swapVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),
+ Grow: swapVolumeConfig.Provisioning().Grow().ValueOrZero(),
+ Label: volumeID,
+ TypeUUID: partition.LinkSwap,
},
FilesystemSpec: block.FilesystemSpec{
Type: block.FilesystemTypeSwap,
diff --git a/internal/app/machined/pkg/controllers/block/volume_config_test.go b/internal/app/machined/pkg/controllers/block/volume_config_test.go
index 2ff310056..96ee86b48 100644
--- a/internal/app/machined/pkg/controllers/block/volume_config_test.go
+++ b/internal/app/machined/pkg/controllers/block/volume_config_test.go
@@ -301,7 +301,7 @@ func (suite *VolumeConfigSuite) TestReconcileExtraEPHEMERALConfig() {
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == "nvme"`, celenv.DiskLocator())),
},
ProvisioningGrow: pointer.To(false),
- ProvisioningMaxSize: blockcfg.MustByteSize("2.5TiB"),
+ ProvisioningMaxSize: blockcfg.MustSize("2.5TiB"),
},
EncryptionSpec: blockcfg.EncryptionSpec{
EncryptionProvider: block.EncryptionProviderLUKS2,
@@ -341,12 +341,12 @@ func (suite *VolumeConfigSuite) TestReconcileUserRawVolumes() {
rv1.MetaName = "data1"
suite.Require().NoError(rv1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))
rv1.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("10GiB")
- rv1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("100GiB")
+ rv1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("100GiB")
rv2 := blockcfg.NewRawVolumeConfigV1Alpha1()
rv2.MetaName = "data2"
suite.Require().NoError(rv2.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))
- rv2.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("1TiB")
+ rv2.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("1TiB")
rv2.EncryptionSpec = blockcfg.EncryptionSpec{
EncryptionProvider: block.EncryptionProviderLUKS2,
EncryptionKeys: []blockcfg.EncryptionKey{
@@ -415,14 +415,14 @@ func (suite *VolumeConfigSuite) TestReconcileUserSwapVolumes() {
uvPart1.MetaName = userVolumeNames[0]
suite.Require().NoError(uvPart1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))
uvPart1.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("10GiB")
- uvPart1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("100GiB")
+ uvPart1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("100GiB")
uvPart1.FilesystemSpec.FilesystemType = block.FilesystemTypeXFS
uvPart2 := blockcfg.NewUserVolumeConfigV1Alpha1()
uvPart2.MetaName = userVolumeNames[1]
uvPart2.VolumeType = pointer.To(block.VolumeTypePartition)
suite.Require().NoError(uvPart2.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))
- uvPart2.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("1TiB")
+ uvPart2.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("1TiB")
uvPart2.EncryptionSpec = blockcfg.EncryptionSpec{
EncryptionProvider: block.EncryptionProviderLUKS2,
EncryptionKeys: []blockcfg.EncryptionKey{
@@ -461,7 +461,7 @@ func (suite *VolumeConfigSuite) TestReconcileUserSwapVolumes() {
sv1 := blockcfg.NewSwapVolumeConfigV1Alpha1()
sv1.MetaName = "swap"
suite.Require().NoError(sv1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == "nvme"`)))
- sv1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("2GiB")
+ sv1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("2GiB")
ctr, err := container.New(uvPart1, uvPart2, uvDir1, uvDisk1, sv1)
suite.Require().NoError(err)
diff --git a/internal/app/machined/pkg/controllers/cri/image_cache_config_test.go b/internal/app/machined/pkg/controllers/cri/image_cache_config_test.go
index 7b933fe3c..c1cf75fd9 100644
--- a/internal/app/machined/pkg/controllers/cri/image_cache_config_test.go
+++ b/internal/app/machined/pkg/controllers/cri/image_cache_config_test.go
@@ -240,7 +240,7 @@ func (suite *ImageCacheConfigSuite) TestReconcileWithImageCacheVolume() {
volumeConfig := blockcfg.NewVolumeConfigV1Alpha1()
volumeConfig.MetaName = constants.ImageCachePartitionLabel
- volumeConfig.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("10GiB")
+ volumeConfig.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("10GiB")
container, err := container.New(v1alpha1Cfg, volumeConfig)
suite.Require().NoError(err)
diff --git a/internal/integration/api/volumes.go b/internal/integration/api/volumes.go
index fb6bb3ff8..9269c37da 100644
--- a/internal/integration/api/volumes.go
+++ b/internal/integration/api/volumes.go
@@ -512,18 +512,30 @@ func (suite *VolumesSuite) TestUserVolumesPartition() {
userVolumeIDs := xslices.Map(volumeIDs, func(volumeID string) string { return constants.UserVolumePrefix + volumeID })
- configDocs := xslices.Map(volumeIDs, func(volumeID string) any {
+ configDocs := xslices.Map(volumeIDs[:1], func(volumeID string) any {
doc := blockcfg.NewUserVolumeConfigV1Alpha1()
doc.MetaName = volumeID
doc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(
cel.ParseBooleanExpression(fmt.Sprintf("'%s' in disk.symlinks", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),
)
doc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("100MiB")
- doc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("1GiB")
+ doc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("1GiB")
return doc
})
+ configDocs = append(configDocs, xslices.Map(volumeIDs[1:], func(volumeID string) any {
+ doc := blockcfg.NewUserVolumeConfigV1Alpha1()
+ doc.MetaName = volumeID
+ doc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(
+ cel.ParseBooleanExpression(fmt.Sprintf("'%s' in disk.symlinks", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),
+ )
+ doc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("100MiB")
+ doc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("20%")
+
+ return doc
+ })...)
+
// create user volumes
suite.PatchMachineConfig(ctx, configDocs...)
@@ -979,7 +991,7 @@ func (suite *VolumesSuite) TestRawVolumes() {
cel.ParseBooleanExpression(fmt.Sprintf("'%s' in disk.symlinks", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),
)
doc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("100MiB")
- doc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("500MiB")
+ doc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("500MiB")
return doc
})
@@ -1104,7 +1116,7 @@ func (suite *VolumesSuite) TestExistingVolumes() {
cel.ParseBooleanExpression(fmt.Sprintf("'%s' in disk.symlinks", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),
)
userVolumeDoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("100MiB")
- userVolumeDoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("1GiB")
+ userVolumeDoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("1GiB")
// create user volumes
suite.PatchMachineConfig(ctx, userVolumeDoc)
@@ -1299,7 +1311,7 @@ func (suite *VolumesSuite) TestSwapOnOff() {
},
}
doc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize("100MiB")
- doc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustByteSize("500MiB")
+ doc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize("500MiB")
// create user volumes
suite.PatchMachineConfig(ctx, doc)
diff --git a/pkg/machinery/api/resource/definitions/block/block.pb.go b/pkg/machinery/api/resource/definitions/block/block.pb.go
index 9e3cff64d..edd49a8d2 100644
--- a/pkg/machinery/api/resource/definitions/block/block.pb.go
+++ b/pkg/machinery/api/resource/definitions/block/block.pb.go
@@ -1236,14 +1236,15 @@ func (x *MountStatusSpec) GetDetached() bool {
// PartitionSpec is the spec for volume partitioning.
type PartitionSpec struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- MinSize uint64 `protobuf:"varint,1,opt,name=min_size,json=minSize,proto3" json:"min_size,omitempty"`
- MaxSize uint64 `protobuf:"varint,2,opt,name=max_size,json=maxSize,proto3" json:"max_size,omitempty"`
- Grow bool `protobuf:"varint,3,opt,name=grow,proto3" json:"grow,omitempty"`
- Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"`
- TypeUuid string `protobuf:"bytes,5,opt,name=type_uuid,json=typeUuid,proto3" json:"type_uuid,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
+ state protoimpl.MessageState `protogen:"open.v1"`
+ MinSize uint64 `protobuf:"varint,1,opt,name=min_size,json=minSize,proto3" json:"min_size,omitempty"`
+ MaxSize uint64 `protobuf:"varint,2,opt,name=max_size,json=maxSize,proto3" json:"max_size,omitempty"`
+ Grow bool `protobuf:"varint,3,opt,name=grow,proto3" json:"grow,omitempty"`
+ Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"`
+ TypeUuid string `protobuf:"bytes,5,opt,name=type_uuid,json=typeUuid,proto3" json:"type_uuid,omitempty"`
+ RelativeMaxSize uint64 `protobuf:"varint,6,opt,name=relative_max_size,json=relativeMaxSize,proto3" json:"relative_max_size,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *PartitionSpec) Reset() {
@@ -1311,6 +1312,13 @@ func (x *PartitionSpec) GetTypeUuid() string {
return ""
}
+func (x *PartitionSpec) GetRelativeMaxSize() uint64 {
+ if x != nil {
+ return x.RelativeMaxSize
+ }
+ return 0
+}
+
// ProvisioningSpec is the spec for volume provisioning.
type ProvisioningSpec struct {
state protoimpl.MessageState `protogen:"open.v1"`
@@ -2431,13 +2439,14 @@ const file_resource_definitions_block_block_proto_rawDesc = "" +
"\tread_only\x18\x05 \x01(\bR\breadOnly\x122\n" +
"\x15project_quota_support\x18\x06 \x01(\bR\x13projectQuotaSupport\x12n\n" +
"\x13encryption_provider\x18\a \x01(\x0e2=.talos.resource.definitions.enums.BlockEncryptionProviderTypeR\x12encryptionProvider\x12\x1a\n" +
- "\bdetached\x18\b \x01(\bR\bdetached\"\x8c\x01\n" +
+ "\bdetached\x18\b \x01(\bR\bdetached\"\xb8\x01\n" +
"\rPartitionSpec\x12\x19\n" +
"\bmin_size\x18\x01 \x01(\x04R\aminSize\x12\x19\n" +
"\bmax_size\x18\x02 \x01(\x04R\amaxSize\x12\x12\n" +
"\x04grow\x18\x03 \x01(\bR\x04grow\x12\x14\n" +
"\x05label\x18\x04 \x01(\tR\x05label\x12\x1b\n" +
- "\ttype_uuid\x18\x05 \x01(\tR\btypeUuid\"\xae\x02\n" +
+ "\ttype_uuid\x18\x05 \x01(\tR\btypeUuid\x12*\n" +
+ "\x11relative_max_size\x18\x06 \x01(\x04R\x0frelativeMaxSize\"\xae\x02\n" +
"\x10ProvisioningSpec\x12S\n" +
"\rdisk_selector\x18\x01 \x01(\v2..talos.resource.definitions.block.DiskSelectorR\fdiskSelector\x12V\n" +
"\x0epartition_spec\x18\x02 \x01(\v2/.talos.resource.definitions.block.PartitionSpecR\rpartitionSpec\x12\x12\n" +
diff --git a/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go b/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go
index 8e59ce566..c296c433b 100644
--- a/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go
+++ b/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go
@@ -1208,6 +1208,11 @@ func (m *PartitionSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
+ if m.RelativeMaxSize != 0 {
+ i = protohelpers.EncodeVarint(dAtA, i, uint64(m.RelativeMaxSize))
+ i--
+ dAtA[i] = 0x30
+ }
if len(m.TypeUuid) > 0 {
i -= len(m.TypeUuid)
copy(dAtA[i:], m.TypeUuid)
@@ -2693,6 +2698,9 @@ func (m *PartitionSpec) SizeVT() (n int) {
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
+ if m.RelativeMaxSize != 0 {
+ n += 1 + protohelpers.SizeOfVarint(uint64(m.RelativeMaxSize))
+ }
n += len(m.unknownFields)
return n
}
@@ -6421,6 +6429,25 @@ func (m *PartitionSpec) UnmarshalVT(dAtA []byte) error {
}
m.TypeUuid = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
+ case 6:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field RelativeMaxSize", wireType)
+ }
+ m.RelativeMaxSize = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return protohelpers.ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.RelativeMaxSize |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
diff --git a/pkg/machinery/config/config/volume.go b/pkg/machinery/config/config/volume.go
index 5e48cf441..3ae24c4e3 100644
--- a/pkg/machinery/config/config/volume.go
+++ b/pkg/machinery/config/config/volume.go
@@ -32,6 +32,7 @@ type VolumeProvisioningConfig interface {
Grow() optional.Optional[bool]
MinSize() optional.Optional[uint64]
MaxSize() optional.Optional[uint64]
+ RelativeMaxSize() optional.Optional[uint64]
}
// WrapVolumesConfigList wraps a list of VolumeConfig providing access by name.
@@ -81,6 +82,14 @@ func (emptyVolumeConfig) MaxSize() optional.Optional[uint64] {
return optional.None[uint64]()
}
+func (emptyVolumeConfig) RelativeMinSize() optional.Optional[uint64] {
+ return optional.None[uint64]()
+}
+
+func (emptyVolumeConfig) RelativeMaxSize() optional.Optional[uint64] {
+ return optional.None[uint64]()
+}
+
// UserVolumeConfig defines the interface to access user volume configuration.
type UserVolumeConfig interface {
NamedDocument
diff --git a/pkg/machinery/config/schemas/config.schema.json b/pkg/machinery/config/schemas/config.schema.json
index 14ebf4928..84a19d357 100644
--- a/pkg/machinery/config/schemas/config.schema.json
+++ b/pkg/machinery/config/schemas/config.schema.json
@@ -313,9 +313,9 @@
"maxSize": {
"type": "string",
"title": "maxSize",
- "description": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\n",
- "markdownDescription": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.",
- "x-intellij-html-description": "\u003cp\u003eThe maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\u003c/p\u003e\n\n\u003cp\u003eSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\u003c/p\u003e\n"
+ "description": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\n",
+ "markdownDescription": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.",
+ "x-intellij-html-description": "\u003cp\u003eThe maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\u003c/p\u003e\n\n\u003cp\u003eSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\u003c/p\u003e\n"
}
},
"additionalProperties": false,
diff --git a/pkg/machinery/config/types/block/block_doc.go b/pkg/machinery/config/types/block/block_doc.go
index 13c436c13..66ebbdea7 100644
--- a/pkg/machinery/config/types/block/block_doc.go
+++ b/pkg/machinery/config/types/block/block_doc.go
@@ -666,9 +666,9 @@ func (ProvisioningSpec) Doc() *encoder.Doc {
},
{
Name: "maxSize",
- Type: "ByteSize",
+ Type: "Size",
Note: "",
- Description: "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.",
+ Description: "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.",
Comments: [3]string{"" /* encoder.HeadComment */, "The maximum size of the volume, if not specified the volume can grow to the size of the" /* encoder.LineComment */, "" /* encoder.FootComment */},
},
},
@@ -676,6 +676,7 @@ func (ProvisioningSpec) Doc() *encoder.Doc {
doc.Fields[2].AddExample("", "2.5GiB")
doc.Fields[3].AddExample("", "50GiB")
+ doc.Fields[3].AddExample("", "80%")
return doc
}
diff --git a/pkg/machinery/config/types/block/byte_size.go b/pkg/machinery/config/types/block/byte_size.go
index 7e97536ec..5a1eb1e24 100644
--- a/pkg/machinery/config/types/block/byte_size.go
+++ b/pkg/machinery/config/types/block/byte_size.go
@@ -29,19 +29,6 @@ type ByteSize struct {
raw []byte
}
-// MustByteSize returns a new ByteSize with the given value.
-//
-// It panics if the value is invalid.
-func MustByteSize(value string) ByteSize {
- var bs ByteSize
-
- if err := bs.UnmarshalText([]byte(value)); err != nil {
- panic(err)
- }
-
- return bs
-}
-
// Value returns the value.
func (bs ByteSize) Value() uint64 {
return pointer.SafeDeref(bs.value)
diff --git a/pkg/machinery/config/types/block/deep_copy.generated.go b/pkg/machinery/config/types/block/deep_copy.generated.go
index 538fe6bf2..565c41815 100644
--- a/pkg/machinery/config/types/block/deep_copy.generated.go
+++ b/pkg/machinery/config/types/block/deep_copy.generated.go
@@ -31,13 +31,29 @@ func (o *RawVolumeConfigV1Alpha1) DeepCopy() *RawVolumeConfigV1Alpha1 {
cp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))
copy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)
}
- if o.ProvisioningSpec.ProvisioningMaxSize.value != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.value = new(uint64)
- *cp.ProvisioningSpec.ProvisioningMaxSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.value
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)
+ }
}
- if o.ProvisioningSpec.ProvisioningMaxSize.raw != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.raw))
- copy(cp.ProvisioningSpec.ProvisioningMaxSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.raw)
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)
+ }
}
if o.EncryptionSpec.EncryptionKeys != nil {
cp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))
@@ -99,13 +115,29 @@ func (o *SwapVolumeConfigV1Alpha1) DeepCopy() *SwapVolumeConfigV1Alpha1 {
cp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))
copy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)
}
- if o.ProvisioningSpec.ProvisioningMaxSize.value != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.value = new(uint64)
- *cp.ProvisioningSpec.ProvisioningMaxSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.value
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)
+ }
}
- if o.ProvisioningSpec.ProvisioningMaxSize.raw != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.raw))
- copy(cp.ProvisioningSpec.ProvisioningMaxSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.raw)
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)
+ }
}
if o.EncryptionSpec.EncryptionKeys != nil {
cp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))
@@ -171,13 +203,29 @@ func (o *UserVolumeConfigV1Alpha1) DeepCopy() *UserVolumeConfigV1Alpha1 {
cp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))
copy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)
}
- if o.ProvisioningSpec.ProvisioningMaxSize.value != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.value = new(uint64)
- *cp.ProvisioningSpec.ProvisioningMaxSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.value
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)
+ }
}
- if o.ProvisioningSpec.ProvisioningMaxSize.raw != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.raw))
- copy(cp.ProvisioningSpec.ProvisioningMaxSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.raw)
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)
+ }
}
if o.FilesystemSpec.ProjectQuotaSupportConfig != nil {
cp.FilesystemSpec.ProjectQuotaSupportConfig = new(bool)
@@ -243,13 +291,29 @@ func (o *VolumeConfigV1Alpha1) DeepCopy() *VolumeConfigV1Alpha1 {
cp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))
copy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)
}
- if o.ProvisioningSpec.ProvisioningMaxSize.value != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.value = new(uint64)
- *cp.ProvisioningSpec.ProvisioningMaxSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.value
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)
+ }
}
- if o.ProvisioningSpec.ProvisioningMaxSize.raw != nil {
- cp.ProvisioningSpec.ProvisioningMaxSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.raw))
- copy(cp.ProvisioningSpec.ProvisioningMaxSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.raw)
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)
+ *cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value
+ }
+ if o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {
+ cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))
+ copy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)
+ }
}
if o.EncryptionSpec.EncryptionKeys != nil {
cp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))
diff --git a/pkg/machinery/config/types/block/percentage_size.go b/pkg/machinery/config/types/block/percentage_size.go
new file mode 100644
index 000000000..0239cf34f
--- /dev/null
+++ b/pkg/machinery/config/types/block/percentage_size.go
@@ -0,0 +1,82 @@
+// 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 (
+ "bytes"
+ "encoding"
+ "fmt"
+ "slices"
+ "strconv"
+
+ "github.com/siderolabs/go-pointer"
+ "gopkg.in/yaml.v3"
+)
+
+// Check interfaces.
+var (
+ _ encoding.TextMarshaler = PercentageSize{}
+ _ encoding.TextUnmarshaler = (*PercentageSize)(nil)
+ _ yaml.IsZeroer = PercentageSize{}
+)
+
+// PercentageSize is a size in percents.
+type PercentageSize struct {
+ value *uint64
+ raw []byte
+}
+
+// Value returns the value.
+func (ps PercentageSize) Value() uint64 {
+ return pointer.SafeDeref(ps.value)
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (ps PercentageSize) MarshalText() ([]byte, error) {
+ if ps.raw != nil {
+ return ps.raw, nil
+ }
+
+ if ps.value != nil {
+ return []byte(strconv.FormatUint(*ps.value, 10)), nil
+ }
+
+ return nil, nil
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (ps *PercentageSize) UnmarshalText(text []byte) error {
+ if len(text) == 0 {
+ ps.value = nil
+ ps.raw = nil
+
+ return nil
+ }
+
+ if !bytes.HasSuffix(text, []byte("%")) {
+ return fmt.Errorf("percentage must end with '%%'")
+ }
+
+ numStr := string(text[:len(text)-1])
+
+ value, err := strconv.ParseFloat(numStr, 64)
+ if err != nil {
+ return fmt.Errorf("invalid percentage value: %w", err)
+ }
+
+ if value < 0 || value > 100 {
+ return fmt.Errorf("percentage must be between 0 and 100, got %v", value)
+ }
+
+ ps.value = pointer.To(uint64(value))
+ ps.raw = slices.Clone(text)
+
+ return nil
+}
+
+// IsZero implements yaml.IsZeroer.
+func (ps PercentageSize) IsZero() bool {
+ return ps.value == nil && ps.raw == nil
+}
diff --git a/pkg/machinery/config/types/block/raw_volume_config.go b/pkg/machinery/config/types/block/raw_volume_config.go
index d31b2bb2c..bc5e13464 100644
--- a/pkg/machinery/config/types/block/raw_volume_config.go
+++ b/pkg/machinery/config/types/block/raw_volume_config.go
@@ -90,7 +90,7 @@ func exampleRawVolumeConfigV1Alpha1() *RawVolumeConfigV1Alpha1 {
DiskSelectorSpec: DiskSelector{
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == "nvme"`, celenv.DiskLocator())),
},
- ProvisioningMaxSize: MustByteSize("50GiB"),
+ ProvisioningMaxSize: MustSize("50GiB"),
}
return cfg
diff --git a/pkg/machinery/config/types/block/raw_volume_config_test.go b/pkg/machinery/config/types/block/raw_volume_config_test.go
index f8e30a027..eefa8beb2 100644
--- a/pkg/machinery/config/types/block/raw_volume_config_test.go
+++ b/pkg/machinery/config/types/block/raw_volume_config_test.go
@@ -39,7 +39,7 @@ func TestRawVolumeConfigMarshalUnmarshal(t *testing.T) {
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == "nvme" && !system_disk`)))
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("100GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("100GiB")
return c
},
@@ -178,7 +178,7 @@ func TestRawVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("2.5TiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("10GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("10GiB")
return c
},
@@ -259,7 +259,7 @@ func TestRawVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
return c
diff --git a/pkg/machinery/config/types/block/size.go b/pkg/machinery/config/types/block/size.go
new file mode 100644
index 000000000..7bf1ac250
--- /dev/null
+++ b/pkg/machinery/config/types/block/size.go
@@ -0,0 +1,117 @@
+// 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 (
+ "encoding"
+ "strings"
+
+ "gopkg.in/yaml.v3"
+)
+
+// Check interfaces.
+var (
+ _ encoding.TextMarshaler = Size{}
+ _ encoding.TextUnmarshaler = (*PercentageSize)(nil)
+ _ yaml.IsZeroer = Size{}
+)
+
+// Size is either a PercentageSize or ByteSize.
+type Size struct {
+ PercentageSize *PercentageSize
+ ByteSize *ByteSize
+}
+
+// MustSize returns a new Size with the given value.
+//
+// It panics if the value is invalid.
+func MustSize(value string) Size {
+ var s Size
+
+ if err := s.UnmarshalText([]byte(value)); err != nil {
+ panic(err)
+ }
+
+ return s
+}
+
+// MustByteSize returns a new Size with the given ByteSize value.
+//
+// It panics if the value is invalid.
+func MustByteSize(value string) ByteSize {
+ var bs ByteSize
+
+ if err := bs.UnmarshalText([]byte(value)); err != nil {
+ panic(err)
+ }
+
+ return bs
+}
+
+// Value returns the value.
+func (s Size) Value() uint64 {
+ if s.ByteSize != nil {
+ return s.ByteSize.Value()
+ }
+
+ return 0
+}
+
+// RelativeValue returns the relative value.
+func (s Size) RelativeValue() (uint64, bool) {
+ if s.PercentageSize != nil {
+ return s.PercentageSize.Value(), true
+ }
+
+ return 0, false
+}
+
+// MarshalText implements encoding.TextMarshaler.
+func (s Size) MarshalText() ([]byte, error) {
+ if s.ByteSize != nil {
+ return s.ByteSize.MarshalText()
+ }
+
+ if s.PercentageSize != nil {
+ return s.PercentageSize.MarshalText()
+ }
+
+ return nil, nil
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (s *Size) UnmarshalText(text []byte) error {
+ if string(text) == "" {
+ return nil
+ }
+
+ if strings.Contains(string(text), "%") {
+ var ps PercentageSize
+ if err := ps.UnmarshalText(text); err != nil {
+ return err
+ }
+
+ s.PercentageSize = &ps
+ } else {
+ var bs ByteSize
+ if err := bs.UnmarshalText(text); err != nil {
+ return err
+ }
+
+ s.ByteSize = &bs
+ }
+
+ return nil
+}
+
+// IsZero implements yaml.IsZeroer.
+func (s Size) IsZero() bool {
+ return (s.PercentageSize == nil || s.PercentageSize.IsZero()) && (s.ByteSize == nil || s.ByteSize.IsZero())
+}
+
+// IsRelative returns if the Size is a relative size.
+func (s Size) IsRelative() bool {
+ return (s.PercentageSize != nil && !s.PercentageSize.IsZero())
+}
diff --git a/pkg/machinery/config/types/block/bytes_size_test.go b/pkg/machinery/config/types/block/size_test.go
similarity index 58%
rename from pkg/machinery/config/types/block/bytes_size_test.go
rename to pkg/machinery/config/types/block/size_test.go
index 4c41e4bed..053246deb 100644
--- a/pkg/machinery/config/types/block/bytes_size_test.go
+++ b/pkg/machinery/config/types/block/size_test.go
@@ -5,6 +5,7 @@
package block_test
import (
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -13,15 +14,17 @@ import (
"github.com/siderolabs/talos/pkg/machinery/config/types/block"
)
-func TestByteSizeUnmarshal(t *testing.T) {
+func TestSizeUnmarshal(t *testing.T) {
t.Parallel()
for _, test := range []struct {
- in string
-
+ in string
want uint64
}{
{in: "", want: 0},
+ {in: "100%", want: 100},
+ {in: "33.4%", want: 33},
+ {in: "33.4124%", want: 33},
{in: "1048576", want: 1048576},
{in: "2.5GiB", want: 2684354560},
{in: "2.5GB", want: 2500000000},
@@ -31,13 +34,25 @@ func TestByteSizeUnmarshal(t *testing.T) {
t.Run(test.in, func(t *testing.T) {
t.Parallel()
- var bs block.ByteSize
+ var s block.Size
- require.NoError(t, bs.UnmarshalText([]byte(test.in)))
+ require.NoError(t, s.UnmarshalText([]byte(test.in)))
- assert.Equal(t, test.want, bs.Value())
+ if strings.Contains(test.in, "%") {
+ assert.Zero(t, s.Value())
- out, err := bs.MarshalText()
+ val, ok := s.RelativeValue()
+ assert.True(t, ok)
+ assert.Equal(t, test.want, val)
+ } else {
+ assert.Equal(t, test.want, s.Value())
+
+ val, ok := s.RelativeValue()
+ assert.False(t, ok)
+ assert.Zero(t, val)
+ }
+
+ out, err := s.MarshalText()
require.NoError(t, err)
assert.Equal(t, test.in, string(out))
diff --git a/pkg/machinery/config/types/block/swap_volume_config.go b/pkg/machinery/config/types/block/swap_volume_config.go
index 14c76c64c..44c67b6a5 100644
--- a/pkg/machinery/config/types/block/swap_volume_config.go
+++ b/pkg/machinery/config/types/block/swap_volume_config.go
@@ -90,7 +90,7 @@ func exampleSwapVolumeConfigV1Alpha1() *SwapVolumeConfigV1Alpha1 {
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == "nvme"`, celenv.DiskLocator())),
},
ProvisioningMinSize: MustByteSize("3GiB"),
- ProvisioningMaxSize: MustByteSize("4GiB"),
+ ProvisioningMaxSize: MustSize("4GiB"),
}
cfg.EncryptionSpec = EncryptionSpec{
EncryptionProvider: block.EncryptionProviderLUKS2,
diff --git a/pkg/machinery/config/types/block/swap_volume_config_test.go b/pkg/machinery/config/types/block/swap_volume_config_test.go
index fb737625b..5eb9e2ba8 100644
--- a/pkg/machinery/config/types/block/swap_volume_config_test.go
+++ b/pkg/machinery/config/types/block/swap_volume_config_test.go
@@ -39,7 +39,7 @@ func TestSwapVolumeConfigMarshalUnmarshal(t *testing.T) {
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == "nvme" && !system_disk`)))
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("100GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("100GiB")
return c
},
@@ -178,7 +178,7 @@ func TestSwapVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("2.5TiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("10GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("10GiB")
return c
},
@@ -259,7 +259,7 @@ func TestSwapVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
return c
diff --git a/pkg/machinery/config/types/block/user_volume_config.go b/pkg/machinery/config/types/block/user_volume_config.go
index 93a852050..276c71a47 100644
--- a/pkg/machinery/config/types/block/user_volume_config.go
+++ b/pkg/machinery/config/types/block/user_volume_config.go
@@ -113,7 +113,7 @@ func exampleUserVolumeConfigV1Alpha1Partition() *UserVolumeConfigV1Alpha1 {
DiskSelectorSpec: DiskSelector{
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == "nvme"`, celenv.DiskLocator())),
},
- ProvisioningMaxSize: MustByteSize("50GiB"),
+ ProvisioningMaxSize: MustSize("50GiB"),
}
cfg.FilesystemSpec = FilesystemSpec{
FilesystemType: block.FilesystemTypeXFS,
diff --git a/pkg/machinery/config/types/block/user_volume_config_test.go b/pkg/machinery/config/types/block/user_volume_config_test.go
index bf9b24f40..916e117e8 100644
--- a/pkg/machinery/config/types/block/user_volume_config_test.go
+++ b/pkg/machinery/config/types/block/user_volume_config_test.go
@@ -40,7 +40,7 @@ func TestUserVolumeConfigMarshalUnmarshal(t *testing.T) {
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == "nvme" && !system_disk`)))
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("100GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("100GiB")
c.FilesystemSpec.FilesystemType = blockres.FilesystemTypeXFS
return c
@@ -195,7 +195,7 @@ func TestUserVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("2.5TiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("10GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("10GiB")
return c
},
@@ -210,7 +210,7 @@ func TestUserVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
c.FilesystemSpec.FilesystemType = blockres.FilesystemTypeISO9660
@@ -349,7 +349,7 @@ func TestUserVolumeConfigValidate(t *testing.T) {
c.VolumeType = pointer.To(blockres.VolumeTypeDisk)
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
c.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4
@@ -405,7 +405,7 @@ func TestUserVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
c.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4
@@ -421,7 +421,7 @@ func TestUserVolumeConfigValidate(t *testing.T) {
c.VolumeType = pointer.To(blockres.VolumeTypePartition)
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
c.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4
diff --git a/pkg/machinery/config/types/block/volume_config.go b/pkg/machinery/config/types/block/volume_config.go
index 570d5e46e..f321fb006 100644
--- a/pkg/machinery/config/types/block/volume_config.go
+++ b/pkg/machinery/config/types/block/volume_config.go
@@ -93,13 +93,15 @@ type ProvisioningSpec struct {
// The maximum size of the volume, if not specified the volume can grow to the size of the
// disk.
//
- // Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB.
+ // Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.
// examples:
// - value: >
// "50GiB"
+ // - value: >
+ // "80%"
// schema:
// type: string
- ProvisioningMaxSize ByteSize `yaml:"maxSize,omitempty"`
+ ProvisioningMaxSize Size `yaml:"maxSize,omitempty"`
}
// DiskSelector selects a disk for the volume.
@@ -135,7 +137,7 @@ func exampleVolumeConfigEphemeralV1Alpha1() *VolumeConfigV1Alpha1 {
DiskSelectorSpec: DiskSelector{
Match: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == "nvme"`, celenv.DiskLocator())),
},
- ProvisioningMaxSize: MustByteSize("50GiB"),
+ ProvisioningMaxSize: MustSize("50GiB"),
}
return cfg
@@ -230,7 +232,7 @@ func (s ProvisioningSpec) Validate(required bool, sizeSupported bool) ([]string,
}
if sizeSupported {
- if !s.ProvisioningMinSize.IsZero() && !s.ProvisioningMaxSize.IsZero() {
+ if !s.ProvisioningMinSize.IsZero() && !s.ProvisioningMaxSize.IsZero() && !s.ProvisioningMaxSize.IsRelative() {
if s.ProvisioningMinSize.Value() > s.ProvisioningMaxSize.Value() {
validationErrors = errors.Join(validationErrors, errors.New("min size is greater than max size"))
}
@@ -306,3 +308,17 @@ func (s ProvisioningSpec) MaxSize() optional.Optional[uint64] {
return optional.Some(s.ProvisioningMaxSize.Value())
}
+
+// RelativeMaxSize implements config.VolumeProvisioningConfig interface.
+func (s ProvisioningSpec) RelativeMaxSize() optional.Optional[uint64] {
+ if s.ProvisioningMaxSize.IsZero() {
+ return optional.None[uint64]()
+ }
+
+ val, ok := s.ProvisioningMaxSize.RelativeValue()
+ if !ok {
+ return optional.None[uint64]()
+ }
+
+ return optional.Some(val)
+}
diff --git a/pkg/machinery/config/types/block/volume_config_test.go b/pkg/machinery/config/types/block/volume_config_test.go
index 2e02c5eb4..22a354f2b 100644
--- a/pkg/machinery/config/types/block/volume_config_test.go
+++ b/pkg/machinery/config/types/block/volume_config_test.go
@@ -59,7 +59,7 @@ func TestVolumeConfigMarshalUnmarshal(t *testing.T) {
c := block.NewVolumeConfigV1Alpha1()
c.MetaName = constants.EphemeralPartitionLabel
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
return c
@@ -164,7 +164,7 @@ func TestVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("2.5TiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("10GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("10GiB")
return c
},
@@ -179,7 +179,7 @@ func TestVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.StatePartitionLabel
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("2.5GiB")
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("10GiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("10GiB")
return c
},
@@ -251,7 +251,7 @@ func TestVolumeConfigValidate(t *testing.T) {
c.MetaName = constants.EphemeralPartitionLabel
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))
- c.ProvisioningSpec.ProvisioningMaxSize = block.MustByteSize("2.5TiB")
+ c.ProvisioningSpec.ProvisioningMaxSize = block.MustSize("2.5TiB")
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
return c
diff --git a/pkg/machinery/resources/block/volume_config.go b/pkg/machinery/resources/block/volume_config.go
index 984e560e0..2058acfff 100644
--- a/pkg/machinery/resources/block/volume_config.go
+++ b/pkg/machinery/resources/block/volume_config.go
@@ -92,6 +92,9 @@ type PartitionSpec struct {
// Partition maximum size in bytes, if not set, grows to the maximum size.
MaxSize uint64 `yaml:"maxSize,omitempty" protobuf:"2"`
+ // Partition maximum size (relative), if not set, grows to the maximum size.
+ RelativeMaxSize uint64 `yaml:"relativeMaxSize" protobuf:"6"`
+
// Grow the partition automatically to the maximum size.
Grow bool `yaml:"grow" protobuf:"3"`
@@ -102,6 +105,15 @@ type PartitionSpec struct {
TypeUUID string `yaml:"typeUUID,omitempty" protobuf:"5"`
}
+// ResolveMaxSize resolves the maximum size of the partition.
+func (ps *PartitionSpec) ResolveMaxSize(available uint64) uint64 {
+ if ps.RelativeMaxSize != 0 {
+ return available * ps.RelativeMaxSize / 100
+ }
+
+ return ps.MaxSize
+}
+
// LocatorSpec is the spec for volume locator.
//
//gotagsrewrite:gen
diff --git a/website/content/v1.12/reference/api.md b/website/content/v1.12/reference/api.md
index d7af06c32..db9f8bf48 100644
--- a/website/content/v1.12/reference/api.md
+++ b/website/content/v1.12/reference/api.md
@@ -5798,6 +5798,7 @@ PartitionSpec is the spec for volume partitioning.
| grow | [bool](#bool) | | |
| label | [string](#string) | | |
| type_uuid | [string](#string) | | |
+| relative_max_size | [uint64](#uint64) | | |
diff --git a/website/content/v1.12/reference/configuration/block/rawvolumeconfig.md b/website/content/v1.12/reference/configuration/block/rawvolumeconfig.md
index 0083d82cf..96890ee9e 100644
--- a/website/content/v1.12/reference/configuration/block/rawvolumeconfig.md
+++ b/website/content/v1.12/reference/configuration/block/rawvolumeconfig.md
@@ -81,8 +81,10 @@ ProvisioningSpec describes how the volume is provisioned.
|`minSize` |ByteSize |The minimum size of the volume.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
minSize: 2.5GiB
{{< /highlight >}} | |
-|`maxSize` |ByteSize |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
+|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
maxSize: 50GiB
+{{< /highlight >}}{{< highlight yaml >}}
+maxSize: 80%
{{< /highlight >}} | |
diff --git a/website/content/v1.12/reference/configuration/block/swapvolumeconfig.md b/website/content/v1.12/reference/configuration/block/swapvolumeconfig.md
index d49667c6f..6d605b685 100644
--- a/website/content/v1.12/reference/configuration/block/swapvolumeconfig.md
+++ b/website/content/v1.12/reference/configuration/block/swapvolumeconfig.md
@@ -78,8 +78,10 @@ ProvisioningSpec describes how the volume is provisioned.
|`minSize` |ByteSize |The minimum size of the volume.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
minSize: 2.5GiB
{{< /highlight >}} | |
-|`maxSize` |ByteSize |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
+|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
maxSize: 50GiB
+{{< /highlight >}}{{< highlight yaml >}}
+maxSize: 80%
{{< /highlight >}} | |
diff --git a/website/content/v1.12/reference/configuration/block/uservolumeconfig.md b/website/content/v1.12/reference/configuration/block/uservolumeconfig.md
index c6bb374b6..20c015c33 100644
--- a/website/content/v1.12/reference/configuration/block/uservolumeconfig.md
+++ b/website/content/v1.12/reference/configuration/block/uservolumeconfig.md
@@ -64,6 +64,7 @@ provisioning:
# # The maximum size of the volume, if not specified the volume can grow to the size of the
# maxSize: 50GiB
+ # maxSize: 80%
# The filesystem describes how the volume is formatted.
filesystem:
type: xfs # Filesystem type. Default is `xfs`.
@@ -176,8 +177,10 @@ ProvisioningSpec describes how the volume is provisioned.
|`minSize` |ByteSize |The minimum size of the volume.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
minSize: 2.5GiB
{{< /highlight >}} | |
-|`maxSize` |ByteSize |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
+|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
maxSize: 50GiB
+{{< /highlight >}}{{< highlight yaml >}}
+maxSize: 80%
{{< /highlight >}} | |
diff --git a/website/content/v1.12/reference/configuration/block/volumeconfig.md b/website/content/v1.12/reference/configuration/block/volumeconfig.md
index 57aed8c3a..1d4fb9dcb 100644
--- a/website/content/v1.12/reference/configuration/block/volumeconfig.md
+++ b/website/content/v1.12/reference/configuration/block/volumeconfig.md
@@ -78,8 +78,10 @@ ProvisioningSpec describes how the volume is provisioned.
|`minSize` |ByteSize |The minimum size of the volume.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
minSize: 2.5GiB
{{< /highlight >}} | |
-|`maxSize` |ByteSize |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
+|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the
disk.
Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. Show example(s)
{{< highlight yaml >}}
maxSize: 50GiB
+{{< /highlight >}}{{< highlight yaml >}}
+maxSize: 80%
{{< /highlight >}} | |
diff --git a/website/content/v1.12/schemas/config.schema.json b/website/content/v1.12/schemas/config.schema.json
index 14ebf4928..84a19d357 100644
--- a/website/content/v1.12/schemas/config.schema.json
+++ b/website/content/v1.12/schemas/config.schema.json
@@ -313,9 +313,9 @@
"maxSize": {
"type": "string",
"title": "maxSize",
- "description": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\n",
- "markdownDescription": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.",
- "x-intellij-html-description": "\u003cp\u003eThe maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\u003c/p\u003e\n\n\u003cp\u003eSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\u003c/p\u003e\n"
+ "description": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\n",
+ "markdownDescription": "The maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\n\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.",
+ "x-intellij-html-description": "\u003cp\u003eThe maximum size of the volume, if not specified the volume can grow to the size of the\ndisk.\u003c/p\u003e\n\n\u003cp\u003eSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\u003c/p\u003e\n"
}
},
"additionalProperties": false,