update system-validators to v1.1.2

Version v1.1.0 added support for validating cgroups v2.
v1.1.1 includes a fix for a broken cross-build on !linux.
v1.1.2 reverted a breaking API change with the introduction of CgroupsSpec.
This commit is contained in:
Lubomir I. Ivanov 2020-04-06 20:02:50 +03:00
parent 3c3fc800df
commit 8183787493
13 changed files with 282 additions and 116 deletions

4
go.mod
View File

@ -147,7 +147,7 @@ require (
k8s.io/metrics v0.0.0
k8s.io/repo-infra v0.0.1-alpha.1
k8s.io/sample-apiserver v0.0.0
k8s.io/system-validators v1.0.4
k8s.io/system-validators v1.1.2
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
sigs.k8s.io/kustomize v2.0.3+incompatible
sigs.k8s.io/yaml v1.2.0
@ -548,7 +548,7 @@ replace (
k8s.io/sample-apiserver => ./staging/src/k8s.io/sample-apiserver
k8s.io/sample-cli-plugin => ./staging/src/k8s.io/sample-cli-plugin
k8s.io/sample-controller => ./staging/src/k8s.io/sample-controller
k8s.io/system-validators => k8s.io/system-validators v1.0.4
k8s.io/system-validators => k8s.io/system-validators v1.1.2
k8s.io/utils => k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
modernc.org/cc => modernc.org/cc v1.0.0
modernc.org/golex => modernc.org/golex v1.0.0

4
go.sum
View File

@ -610,8 +610,8 @@ k8s.io/kube-openapi v0.0.0-20200401025727-01dfbe2eec3d h1:SaMrAnTezfJejw3Y3Ysw9D
k8s.io/kube-openapi v0.0.0-20200401025727-01dfbe2eec3d/go.mod h1:NwPpO8COeh/j9Q9ModsqBxwHcWDo/PmrJOPyquZCC1A=
k8s.io/repo-infra v0.0.1-alpha.1 h1:2us1n30u3cOcoPsacNfCvCssS9B9Yldr1ZGOdK0728U=
k8s.io/repo-infra v0.0.1-alpha.1/go.mod h1:wO1t9WaB99V80ljbeENTnayuEEwNZt7gECYh/CEyOJ8=
k8s.io/system-validators v1.0.4 h1:sW57tJ/ciqOVbbTLN+ZNy64MJMNqUuiwrirQv8IR2Kw=
k8s.io/system-validators v1.0.4/go.mod h1:HgSgTg4NAGNoYYjKsUyk52gdNi2PVDswQ9Iyn66R7NI=
k8s.io/system-validators v1.1.2 h1:0xzEb0PqnDnUOuf/2E/gaJBOBN7j+qf0LIn12jw3oc4=
k8s.io/system-validators v1.1.2/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q=
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=

View File

@ -3,12 +3,14 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"cgroup_validator.go",
"cgroup_validator_linux.go",
"cgroup_validator_other.go",
"docker_validator.go",
"kernel_validator.go",
"kernel_validator_helper.go",
"os_validator.go",
"package_validator.go",
"package_validator_linux.go",
"package_validator_other.go",
"report.go",
"types.go",
"types_unix.go",
@ -19,9 +21,18 @@ go_library(
importpath = "k8s.io/system-validators/validators",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
] + select({
"@io_bazel_rules_go//go/platform:android": [
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//vendor/github.com/blang/semver:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"//conditions:default": [],
}),
)
filegroup(

View File

@ -1,102 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package system
import (
"bufio"
"os"
"strings"
"github.com/pkg/errors"
)
var _ Validator = &CgroupsValidator{}
// CgroupsValidator validates cgroup configuration.
type CgroupsValidator struct {
Reporter Reporter
}
// Name is part of the system.Validator interface.
func (c *CgroupsValidator) Name() string {
return "cgroups"
}
const (
cgroupsConfigPrefix = "CGROUPS_"
)
// Validate is part of the system.Validator interface.
func (c *CgroupsValidator) Validate(spec SysSpec) ([]error, []error) {
subsystems, err := c.getCgroupSubsystems()
if err != nil {
return nil, []error{errors.Wrap(err, "failed to get cgroup subsystems")}
}
if err = c.validateCgroupSubsystems(spec.Cgroups, subsystems); err != nil {
return nil, []error{err}
}
return nil, nil
}
func (c *CgroupsValidator) validateCgroupSubsystems(cgroupSpec, subsystems []string) error {
missing := []string{}
for _, cgroup := range cgroupSpec {
found := false
for _, subsystem := range subsystems {
if cgroup == subsystem {
found = true
break
}
}
item := cgroupsConfigPrefix + strings.ToUpper(cgroup)
if found {
c.Reporter.Report(item, "enabled", good)
} else {
c.Reporter.Report(item, "missing", bad)
missing = append(missing, cgroup)
}
}
if len(missing) > 0 {
return errors.Errorf("missing cgroups: %s", strings.Join(missing, " "))
}
return nil
}
func (c *CgroupsValidator) getCgroupSubsystems() ([]string, error) {
f, err := os.Open("/proc/cgroups")
if err != nil {
return nil, err
}
defer f.Close()
subsystems := []string{}
s := bufio.NewScanner(f)
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
text := s.Text()
if text[0] != '#' {
parts := strings.Fields(text)
if len(parts) >= 4 && parts[3] != "0" {
subsystems = append(subsystems, parts[0])
}
}
}
return subsystems, nil
}

View File

@ -0,0 +1,153 @@
// +build linux
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package system
import (
"bufio"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
)
var _ Validator = &CgroupsValidator{}
// CgroupsValidator validates cgroup configuration.
type CgroupsValidator struct {
Reporter Reporter
}
// Name is part of the system.Validator interface.
func (c *CgroupsValidator) Name() string {
return "cgroups"
}
const (
cgroupsConfigPrefix = "CGROUPS_"
unifiedMountpoint = "/sys/fs/cgroup"
)
// Validate is part of the system.Validator interface.
func (c *CgroupsValidator) Validate(spec SysSpec) (warns, errs []error) {
// Get the subsystems from /sys/fs/cgroup/cgroup.controllers when cgroup v2 is used.
// /proc/cgroups is meaningless for v2
// https://github.com/torvalds/linux/blob/v5.3/Documentation/admin-guide/cgroup-v2.rst#deprecated-v1-core-features
var st unix.Statfs_t
var err error
if err := unix.Statfs(unifiedMountpoint, &st); err != nil {
return nil, []error{errors.Wrap(err, "cannot statfs the cgroupv2 root")}
}
var requiredCgroupSpec []string
var optionalCgroupSpec []string
var subsystems []string
if st.Type == unix.CGROUP2_SUPER_MAGIC {
subsystems, err = c.getCgroupV2Subsystems()
if err != nil {
return nil, []error{errors.Wrap(err, "failed to get cgroup v2 subsystems")}
}
requiredCgroupSpec = spec.CgroupsV2
optionalCgroupSpec = spec.CgroupsV2Optional
} else {
subsystems, err = c.getCgroupV1Subsystems()
if err != nil {
return nil, []error{errors.Wrap(err, "failed to get cgroup v1 subsystems")}
}
requiredCgroupSpec = spec.Cgroups
optionalCgroupSpec = spec.CgroupsOptional
}
if missingRequired := c.validateCgroupSubsystems(requiredCgroupSpec, subsystems, true); len(missingRequired) != 0 {
errs = []error{errors.Errorf("missing required cgroups: %s", strings.Join(missingRequired, " "))}
}
if missingOptional := c.validateCgroupSubsystems(optionalCgroupSpec, subsystems, false); len(missingOptional) != 0 {
warns = []error{errors.Errorf("missing optional cgroups: %s", strings.Join(missingOptional, " "))}
}
return
}
// validateCgroupSubsystems returns a list with the missing cgroups in the cgroup
func (c *CgroupsValidator) validateCgroupSubsystems(cgroups, subsystems []string, required bool) []string {
var missing []string
for _, cgroup := range cgroups {
found := false
for _, subsystem := range subsystems {
if cgroup == subsystem {
found = true
break
}
}
item := cgroupsConfigPrefix + strings.ToUpper(cgroup)
if found {
c.Reporter.Report(item, "enabled", good)
continue
} else if required {
c.Reporter.Report(item, "missing", bad)
} else {
c.Reporter.Report(item, "missing", warn)
}
missing = append(missing, cgroup)
}
return missing
}
func (c *CgroupsValidator) getCgroupV1Subsystems() ([]string, error) {
// Get the subsystems from /proc/cgroups when cgroup v1 is used.
f, err := os.Open("/proc/cgroups")
if err != nil {
return nil, err
}
defer f.Close()
subsystems := []string{}
s := bufio.NewScanner(f)
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
text := s.Text()
if text[0] != '#' {
parts := strings.Fields(text)
if len(parts) >= 4 && parts[3] != "0" {
subsystems = append(subsystems, parts[0])
}
}
}
return subsystems, nil
}
func (c *CgroupsValidator) getCgroupV2Subsystems() ([]string, error) {
// Some controllers are implicitly enabled by the kernel.
// Those controllers do not appear in /sys/fs/cgroup/cgroup.controllers.
// https://github.com/torvalds/linux/blob/v5.3/kernel/cgroup/cgroup.c#L433-L434
// We assume these are always available, as it is hard to detect availability.
// So, we hardcode the following as "pseudo" controllers.
// - devices: implemented in kernel 4.15
// - freezer: implemented in kernel 5.2
pseudo := []string{"devices", "freezer"}
data, err := ioutil.ReadFile(filepath.Join(unifiedMountpoint, "cgroup.controllers"))
if err != nil {
return nil, err
}
subsystems := append(pseudo, strings.Fields(string(data))...)
return subsystems, nil
}

View File

@ -0,0 +1,38 @@
// +build !linux
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package system
// NOOP for non-Linux OSes.
var _ Validator = &CgroupsValidator{}
// CgroupsValidator validates cgroup configuration.
type CgroupsValidator struct {
Reporter Reporter
}
// Validate is part of the system.Validator interface.
func (c *CgroupsValidator) Validate(spec SysSpec) (warns, errs []error) {
return
}
// Name is part of the system.Validator interface.
func (c *CgroupsValidator) Name() string {
return "cgroups"
}

View File

@ -1,3 +1,5 @@
// +build linux
/*
Copyright 2017 The Kubernetes Authors.

View File

@ -0,0 +1,38 @@
// +build !linux
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package system
// NOOP for non-Linux OSes.
// packageValidator implements the Validator interface. It validates packages
// and their versions.
type packageValidator struct {
reporter Reporter
}
// Name returns the name of the package validator.
func (validator *packageValidator) Name() string {
return "package"
}
// Validate checks packages and their versions against the packageSpecs using
// the packageManager, and returns an error on any package/version mismatch.
func (validator *packageValidator) Validate(spec SysSpec) ([]error, []error) {
return nil, nil
}

View File

@ -112,8 +112,16 @@ type SysSpec struct {
OS string `json:"os,omitempty"`
// KernelConfig defines the spec for kernel.
KernelSpec KernelSpec `json:"kernelSpec,omitempty"`
// Cgroups is the required cgroups.
Cgroups []string `json:"cgroups,omitempty"`
// CgroupsOptional is the optional cgroups.
CgroupsOptional []string `json:"cgroupsOptional,omitempty"`
// CgroupsV2 is the required cgroups v2.
CgroupsV2 []string `json:"cgroupsV2,omitempty"`
// CgroupsV2Optional is the optional cgroups v2.
CgroupsV2Optional []string `json:"cgroupsV2Optional,omitempty"`
// RuntimeSpec defines the spec for runtime.
RuntimeSpec RuntimeSpec `json:"runtimeSpec,omitempty"`
// PackageSpec defines the required packages and their versions.

View File

@ -57,6 +57,16 @@ var DefaultSysSpec = SysSpec{
Forbidden: []KernelConfig{},
},
Cgroups: []string{"cpu", "cpuacct", "cpuset", "devices", "freezer", "memory"},
CgroupsOptional: []string{
// The hugetlb cgroup is optional since some kernels are compiled without support for huge pages
// and therefore lacks corresponding hugetlb cgroup
"hugetlb",
// The pids cgroup is optional since it is only used when at least one of the feature flags "SupportPodPidsLimit" and
// "SupportNodePidsLimit" is enabled
"pids",
},
CgroupsV2: []string{"cpu", "cpuset", "devices", "freezer", "memory"},
CgroupsV2Optional: []string{"hugetlb", "pids"},
RuntimeSpec: RuntimeSpec{
DockerSpec: &DockerSpec{
Version: []string{`1\.1[1-3]\..*`, `17\.0[3,6,9]\..*`, `18\.0[6,9]\..*`, `19\.03\..*`},

View File

@ -32,7 +32,6 @@ var DefaultSysSpec = SysSpec{
Optional: []KernelConfig{},
Forbidden: []KernelConfig{},
},
Cgroups: []string{},
RuntimeSpec: RuntimeSpec{
DockerSpec: &DockerSpec{
Version: []string{`18\.0[6,9]\..*`},

View File

@ -18,6 +18,7 @@ package system
import (
"fmt"
"runtime"
)
// Validator is the interface for all validators.
@ -53,23 +54,31 @@ func Validate(spec SysSpec, validators []Validator) ([]error, []error) {
}
// ValidateSpec uses all default validators to validate the system and writes to stdout.
func ValidateSpec(spec SysSpec, runtime string) ([]error, []error) {
func ValidateSpec(spec SysSpec, containerRuntime string) ([]error, []error) {
// OS-level validators.
var osValidators = []Validator{
&OSValidator{Reporter: DefaultReporter},
&KernelValidator{Reporter: DefaultReporter},
&CgroupsValidator{Reporter: DefaultReporter},
&packageValidator{reporter: DefaultReporter},
}
// Docker-specific validators.
var dockerValidators = []Validator{
&DockerValidator{Reporter: DefaultReporter},
}
validators := osValidators
switch runtime {
switch containerRuntime {
case "docker":
validators = append(validators, dockerValidators...)
}
// Linux-specific validators.
if runtime.GOOS == "linux" {
validators = append(validators,
&CgroupsValidator{Reporter: DefaultReporter},
&packageValidator{reporter: DefaultReporter},
)
}
return Validate(spec, validators)
}

2
vendor/modules.txt vendored
View File

@ -1945,7 +1945,7 @@ k8s.io/sample-apiserver/pkg/generated/openapi
k8s.io/sample-apiserver/pkg/registry
k8s.io/sample-apiserver/pkg/registry/wardle/fischer
k8s.io/sample-apiserver/pkg/registry/wardle/flunder
# k8s.io/system-validators v1.0.4 => k8s.io/system-validators v1.0.4
# k8s.io/system-validators v1.1.2 => k8s.io/system-validators v1.1.2
k8s.io/system-validators/validators
# k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 => k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
k8s.io/utils/buffer