Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions validators/cgroup_validator_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ import (
"os"
"path/filepath"
"strings"

"github.com/blang/semver/v4"
)

var _ Validator = &CgroupsValidator{}

// CgroupsValidator validates cgroup configuration.
type CgroupsValidator struct {
Reporter Reporter
Reporter Reporter
KubeletVersion string
}

// Name is part of the system.Validator interface.
Expand Down Expand Up @@ -114,7 +117,22 @@ func (c *CgroupsValidator) Validate(spec SysSpec) (warns, errs []error) {
requiredCgroupSpec = spec.CgroupsV2
optionalCgroupSpec = spec.CgroupsV2Optional
} else {
errs = append(errs, errors.New("cgroups v1 support is deprecated and will be removed in a future release. Please migrate to cgroups v2. To explicitly enable cgroups v1 support, you must set the kubelet configuration option 'FailCgroupV1' to 'false'. For more information see https://git.k8s.io/enhancements/keps/sig-node/5573-remove-cgroup-v1"))
v1DisabledInKubelet, err := c.isCgroupsV1DisabledInKubelet()
if err != nil {
return nil, []error{err}
}

v1Error := errors.New("cgroups v1 support is deprecated and will be removed in a future release. " +
"Please migrate to cgroups v2. To explicitly enable cgroups v1 support for kubelet v1.35 or newer, " +
"you must set the kubelet configuration option 'FailCgroupV1' to 'false'. You must also explicitly " +
"skip this validation. For more information, see https://git.k8s.io/enhancements/keps/sig-node/5573-remove-cgroup-v1")

if v1DisabledInKubelet {
errs = append(errs, v1Error)
} else {
warns = append(warns, v1Error)
}

subsystems, err = c.getCgroupV1Subsystems()
if err != nil {
return nil, []error{fmt.Errorf("failed to get cgroups v1 subsystems: %w", err)}
Expand Down Expand Up @@ -229,3 +247,24 @@ func checkCgroupV2Freeze(unifiedMountpoint string) (isCgroupfs bool, warn error)
isCgroupfs = true
return
}

// isCgroupsV1DisabledInKubelet checks the KubeletVersion and determines if that version
// disabled cgroups v1 support by default:
// - If the version is newer than 1.35 pre-release, return true.
// - If the version is not defined or older than pre-release 1.35, return false.
func (c *CgroupsValidator) isCgroupsV1DisabledInKubelet() (bool, error) {
if c.KubeletVersion == "" {
return false, nil
}

kv, err := semver.Parse(c.KubeletVersion)
if err != nil {
return false, fmt.Errorf("malformed KubeletVersion in CgroupsValidator: %w", err)
}

if kv.Compare(semver.MustParse("1.35.0-0")) > -1 {
return true, nil
}

return false, nil
}
3 changes: 2 additions & 1 deletion validators/cgroup_validator_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ const mountsFilePath = ""

// CgroupsValidator validates cgroup configuration.
type CgroupsValidator struct {
Reporter Reporter
Reporter Reporter
KubeletVersion string
}

// Validate is part of the system.Validator interface.
Expand Down
51 changes: 51 additions & 0 deletions validators/cgroup_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,54 @@ cgroup /sys/fs/cgroup/memory cgroup rw,seclabel,nosuid,nodev,noexec,relatime,mem
})
}
}

func TestIsCgroupsV1DisabledInKubelet(t *testing.T) {
tests := []struct {
name string
version string
expectedResult bool
expectedError bool
}{
{
name: "invalid version",
version: "foo",
expectedError: true,
},
{
name: "empty version",
version: "",
expectedResult: false,
},
{
name: "version older than 1.35.0-0 causes a warning",
version: "1.34.7",
expectedResult: false,
},
{
name: "1.35.0 pre-release causes an error",
version: "1.35.0-alpha.1",
expectedResult: true,
},
{
name: "newer versions than 1.35 cause an error",
version: "1.35.1",
expectedResult: true,
},
}

v := CgroupsValidator{}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
v.KubeletVersion = tc.version
result, err := v.isCgroupsV1DisabledInKubelet()

if (err != nil) != tc.expectedError {
t.Fatalf("expected error: %v, got: %v", tc.expectedError, err != nil)
}
if result != tc.expectedResult {
t.Fatalf("expected result: %v, got: %v", tc.expectedResult, result)
}
})
}
}