mirror of
https://github.com/siderolabs/talos.git
synced 2026-05-06 04:46:17 +02:00
feat: support project quota support for user volumes
Just exposting existing value via the config. Fixes #11090 Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
parent
52656cc3c1
commit
6415055847
@ -275,12 +275,13 @@ func (ctrl *UserVolumeConfigController) handleUserVolumeConfig(
|
||||
},
|
||||
}
|
||||
v.TypedSpec().Mount = block.MountSpec{
|
||||
TargetPath: userVolumeConfig.Name(),
|
||||
ParentID: constants.UserVolumeMountPoint,
|
||||
SelinuxLabel: constants.EphemeralSelinuxLabel,
|
||||
FileMode: 0o755,
|
||||
UID: 0,
|
||||
GID: 0,
|
||||
TargetPath: userVolumeConfig.Name(),
|
||||
ParentID: constants.UserVolumeMountPoint,
|
||||
SelinuxLabel: constants.EphemeralSelinuxLabel,
|
||||
FileMode: 0o755,
|
||||
UID: 0,
|
||||
GID: 0,
|
||||
ProjectQuotaSupport: userVolumeConfig.Filesystem().ProjectQuotaSupport(),
|
||||
}
|
||||
|
||||
if err := convertEncryptionConfiguration(userVolumeConfig.Encryption(), v.TypedSpec()); err != nil {
|
||||
|
||||
@ -23,6 +23,7 @@ import (
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
"github.com/google/uuid"
|
||||
"github.com/siderolabs/gen/xslices"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers"
|
||||
@ -598,7 +599,8 @@ func (suite *VolumesSuite) TestUserVolumes() {
|
||||
// wait for the discovered volume to disappear
|
||||
rtestutils.AssertNoResource[*block.DiscoveredVolume](ctx, suite.T(), suite.Client.COSI, filepath.Base(vs.TypedSpec().Location))
|
||||
|
||||
// re-create the volume
|
||||
// re-create the volume with project quota support
|
||||
configDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).FilesystemSpec.ProjectQuotaSupportConfig = pointer.To(true)
|
||||
suite.PatchMachineConfig(ctx, configDocs[0])
|
||||
|
||||
rtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,
|
||||
@ -608,7 +610,15 @@ func (suite *VolumesSuite) TestUserVolumes() {
|
||||
)
|
||||
|
||||
rtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,
|
||||
func(vs *block.MountStatus, _ *assert.Assertions) {})
|
||||
func(vs *block.MountStatus, asrt *assert.Assertions) {
|
||||
if vs.Metadata().ID() == userVolumeIDs[0] {
|
||||
// check that the project quota support is enabled
|
||||
asrt.True(vs.TypedSpec().ProjectQuotaSupport, "project quota support should be enabled for %s", vs.Metadata().ID())
|
||||
} else {
|
||||
// check that the project quota support is disabled
|
||||
asrt.False(vs.TypedSpec().ProjectQuotaSupport, "project quota support should be disabled for %s", vs.Metadata().ID())
|
||||
}
|
||||
})
|
||||
|
||||
// clean up
|
||||
suite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeIDs...)
|
||||
|
||||
@ -89,6 +89,8 @@ type UserVolumeConfig interface {
|
||||
type FilesystemConfig interface {
|
||||
// Type returns the filesystem type.
|
||||
Type() block.FilesystemType
|
||||
// ProjectQuotaSupport returns true if the filesystem should support project quotas.
|
||||
ProjectQuotaSupport() bool
|
||||
}
|
||||
|
||||
// SwapVolumeConfig defines the interface to access swap volume configuration.
|
||||
|
||||
@ -179,6 +179,13 @@
|
||||
"description": "Filesystem type. Default is xfs.\n",
|
||||
"markdownDescription": "Filesystem type. Default is `xfs`.",
|
||||
"x-intellij-html-description": "\u003cp\u003eFilesystem type. Default is \u003ccode\u003exfs\u003c/code\u003e.\u003c/p\u003e\n"
|
||||
},
|
||||
"projectQuotaSupport": {
|
||||
"type": "boolean",
|
||||
"title": "projectQuotaSupport",
|
||||
"description": "Enables project quota support, valid only for ‘xfs’ filesystem.\n\nNote: changing this value might require a full remount of the filesystem.\n",
|
||||
"markdownDescription": "Enables project quota support, valid only for 'xfs' filesystem.\n\nNote: changing this value might require a full remount of the filesystem.",
|
||||
"x-intellij-html-description": "\u003cp\u003eEnables project quota support, valid only for \u0026lsquo;xfs\u0026rsquo; filesystem.\u003c/p\u003e\n\n\u003cp\u003eNote: changing this value might require a full remount of the filesystem.\u003c/p\u003e\n"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
||||
@ -342,6 +342,13 @@ func (FilesystemSpec) Doc() *encoder.Doc {
|
||||
"xfs",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "projectQuotaSupport",
|
||||
Type: "bool",
|
||||
Note: "",
|
||||
Description: "Enables project quota support, valid only for 'xfs' filesystem.\n\nNote: changing this value might require a full remount of the filesystem.",
|
||||
Comments: [3]string{"" /* encoder.HeadComment */, "Enables project quota support, valid only for 'xfs' filesystem." /* encoder.LineComment */, "" /* encoder.FootComment */},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -85,6 +85,10 @@ func (o *UserVolumeConfigV1Alpha1) DeepCopy() *UserVolumeConfigV1Alpha1 {
|
||||
cp.ProvisioningSpec.ProvisioningMaxSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.raw))
|
||||
copy(cp.ProvisioningSpec.ProvisioningMaxSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.raw)
|
||||
}
|
||||
if o.FilesystemSpec.ProjectQuotaSupportConfig != nil {
|
||||
cp.FilesystemSpec.ProjectQuotaSupportConfig = new(bool)
|
||||
*cp.FilesystemSpec.ProjectQuotaSupportConfig = *o.FilesystemSpec.ProjectQuotaSupportConfig
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionKeys != nil {
|
||||
cp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))
|
||||
copy(cp.EncryptionSpec.EncryptionKeys, o.EncryptionSpec.EncryptionKeys)
|
||||
|
||||
10
pkg/machinery/config/types/block/testdata/uservolumeconfig_prjquota.yaml
vendored
Normal file
10
pkg/machinery/config/types/block/testdata/uservolumeconfig_prjquota.yaml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
apiVersion: v1alpha1
|
||||
kind: UserVolumeConfig
|
||||
name: secret-store
|
||||
provisioning:
|
||||
diskSelector:
|
||||
match: '!system_disk'
|
||||
minSize: 10GiB
|
||||
filesystem:
|
||||
type: xfs
|
||||
projectQuotaSupport: true
|
||||
@ -11,6 +11,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/siderolabs/go-pointer"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/cel"
|
||||
"github.com/siderolabs/talos/pkg/machinery/cel/celenv"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/config"
|
||||
@ -206,6 +208,11 @@ type FilesystemSpec struct {
|
||||
// - ext4
|
||||
// - xfs
|
||||
FilesystemType block.FilesystemType `yaml:"type,omitempty"`
|
||||
// description: |
|
||||
// Enables project quota support, valid only for 'xfs' filesystem.
|
||||
//
|
||||
// Note: changing this value might require a full remount of the filesystem.
|
||||
ProjectQuotaSupportConfig *bool `yaml:"projectQuotaSupport,omitempty"`
|
||||
}
|
||||
|
||||
// Type implements config.FilesystemConfig interface.
|
||||
@ -217,6 +224,11 @@ func (s FilesystemSpec) Type() block.FilesystemType {
|
||||
return s.FilesystemType
|
||||
}
|
||||
|
||||
// ProjectQuotaSupport implements config.FilesysteemConfig interface.
|
||||
func (s FilesystemSpec) ProjectQuotaSupport() bool {
|
||||
return pointer.SafeDeref(s.ProjectQuotaSupportConfig)
|
||||
}
|
||||
|
||||
// Validate implements config.Validator interface.
|
||||
func (s FilesystemSpec) Validate() ([]string, error) {
|
||||
switch s.FilesystemType { //nolint:exhaustive
|
||||
@ -227,5 +239,9 @@ func (s FilesystemSpec) Validate() ([]string, error) {
|
||||
return nil, fmt.Errorf("unsupported filesystem type: %s", s.FilesystemType)
|
||||
}
|
||||
|
||||
if pointer.SafeDeref(s.ProjectQuotaSupportConfig) && s.Type() != block.FilesystemTypeXFS {
|
||||
return nil, fmt.Errorf("project quota support is only available for xfs filesystem")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -69,6 +70,21 @@ func TestUserVolumeConfigMarshalUnmarshal(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
return c
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prjquota",
|
||||
filename: "uservolumeconfig_prjquota.yaml",
|
||||
cfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {
|
||||
c := block.NewUserVolumeConfigV1Alpha1()
|
||||
c.MetaName = "secret-store"
|
||||
|
||||
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))
|
||||
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
|
||||
c.FilesystemSpec.FilesystemType = blockres.FilesystemTypeXFS
|
||||
c.FilesystemSpec.ProjectQuotaSupportConfig = pointer.To(true)
|
||||
|
||||
return c
|
||||
},
|
||||
},
|
||||
@ -269,6 +285,23 @@ func TestUserVolumeConfigValidate(t *testing.T) {
|
||||
|
||||
expectedErrors: "at least one encryption key type must be specified for slot 0\nduplicate key slot 1",
|
||||
},
|
||||
{
|
||||
name: "prjquota not supported",
|
||||
|
||||
cfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {
|
||||
c := block.NewUserVolumeConfigV1Alpha1()
|
||||
c.MetaName = constants.EphemeralPartitionLabel
|
||||
|
||||
require.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))
|
||||
c.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize("10GiB")
|
||||
c.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4
|
||||
c.FilesystemSpec.ProjectQuotaSupportConfig = pointer.To(true)
|
||||
|
||||
return c
|
||||
},
|
||||
|
||||
expectedErrors: "project quota support is only available for xfs filesystem",
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
|
||||
|
||||
@ -130,6 +130,7 @@ FilesystemSpec configures the filesystem for the volume.
|
||||
| Field | Type | Description | Value(s) |
|
||||
|-------|------|-------------|----------|
|
||||
|`type` |FilesystemType |Filesystem type. Default is `xfs`. |`ext4`<br />`xfs`<br /> |
|
||||
|`projectQuotaSupport` |bool |Enables project quota support, valid only for 'xfs' filesystem.<br><br>Note: changing this value might require a full remount of the filesystem. | |
|
||||
|
||||
|
||||
|
||||
|
||||
@ -179,6 +179,13 @@
|
||||
"description": "Filesystem type. Default is xfs.\n",
|
||||
"markdownDescription": "Filesystem type. Default is `xfs`.",
|
||||
"x-intellij-html-description": "\u003cp\u003eFilesystem type. Default is \u003ccode\u003exfs\u003c/code\u003e.\u003c/p\u003e\n"
|
||||
},
|
||||
"projectQuotaSupport": {
|
||||
"type": "boolean",
|
||||
"title": "projectQuotaSupport",
|
||||
"description": "Enables project quota support, valid only for ‘xfs’ filesystem.\n\nNote: changing this value might require a full remount of the filesystem.\n",
|
||||
"markdownDescription": "Enables project quota support, valid only for 'xfs' filesystem.\n\nNote: changing this value might require a full remount of the filesystem.",
|
||||
"x-intellij-html-description": "\u003cp\u003eEnables project quota support, valid only for \u0026lsquo;xfs\u0026rsquo; filesystem.\u003c/p\u003e\n\n\u003cp\u003eNote: changing this value might require a full remount of the filesystem.\u003c/p\u003e\n"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user