mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-20 18:31:15 +00:00
Add a reporter to the system verification check
This commit is contained in:
parent
3509419543
commit
dacec687a4
@ -93,7 +93,7 @@ func TestE2eNode(t *testing.T) {
|
|||||||
glog.Exitf("chroot %q failed: %v", rootfs, err)
|
glog.Exitf("chroot %q failed: %v", rootfs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := system.Validate(); err != nil {
|
if err := system.ValidateDefault(); err != nil {
|
||||||
glog.Exitf("system validation failed: %v", err)
|
glog.Exitf("system validation failed: %v", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -17,8 +17,8 @@ go_library(
|
|||||||
"docker_validator.go",
|
"docker_validator.go",
|
||||||
"kernel_validator.go",
|
"kernel_validator.go",
|
||||||
"os_validator.go",
|
"os_validator.go",
|
||||||
|
"report.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
"util.go",
|
|
||||||
"validators.go",
|
"validators.go",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
@ -25,7 +25,9 @@ import (
|
|||||||
|
|
||||||
var _ Validator = &CgroupsValidator{}
|
var _ Validator = &CgroupsValidator{}
|
||||||
|
|
||||||
type CgroupsValidator struct{}
|
type CgroupsValidator struct {
|
||||||
|
Reporter Reporter
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CgroupsValidator) Name() string {
|
func (c *CgroupsValidator) Name() string {
|
||||||
return "cgroups"
|
return "cgroups"
|
||||||
@ -55,9 +57,9 @@ func (c *CgroupsValidator) validateCgroupSubsystems(cgroupSpec, subsystems []str
|
|||||||
}
|
}
|
||||||
item := cgroupsConfigPrefix + strings.ToUpper(cgroup)
|
item := cgroupsConfigPrefix + strings.ToUpper(cgroup)
|
||||||
if found {
|
if found {
|
||||||
report(item, "enabled", good)
|
c.Reporter.Report(item, "enabled", good)
|
||||||
} else {
|
} else {
|
||||||
report(item, "missing", bad)
|
c.Reporter.Report(item, "missing", bad)
|
||||||
missing = append(missing, cgroup)
|
missing = append(missing, cgroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateCgroupSubsystem(t *testing.T) {
|
func TestValidateCgroupSubsystem(t *testing.T) {
|
||||||
v := &CgroupsValidator{}
|
v := &CgroupsValidator{
|
||||||
|
Reporter: DefaultReporter,
|
||||||
|
}
|
||||||
cgroupSpec := []string{"system1", "system2"}
|
cgroupSpec := []string{"system1", "system2"}
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
cgroupSpec []string
|
cgroupSpec []string
|
||||||
|
@ -28,7 +28,9 @@ import (
|
|||||||
var _ Validator = &DockerValidator{}
|
var _ Validator = &DockerValidator{}
|
||||||
|
|
||||||
// DockerValidator validates docker configuration.
|
// DockerValidator validates docker configuration.
|
||||||
type DockerValidator struct{}
|
type DockerValidator struct {
|
||||||
|
Reporter Reporter
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DockerValidator) Name() string {
|
func (d *DockerValidator) Name() string {
|
||||||
return "docker"
|
return "docker"
|
||||||
@ -63,22 +65,22 @@ func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info)
|
|||||||
for _, v := range spec.Version {
|
for _, v := range spec.Version {
|
||||||
r := regexp.MustCompile(v)
|
r := regexp.MustCompile(v)
|
||||||
if r.MatchString(info.ServerVersion) {
|
if r.MatchString(info.ServerVersion) {
|
||||||
report(dockerConfigPrefix+"VERSION", info.ServerVersion, good)
|
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, good)
|
||||||
matched = true
|
matched = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !matched {
|
if !matched {
|
||||||
report(dockerConfigPrefix+"VERSION", info.ServerVersion, bad)
|
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, bad)
|
||||||
return fmt.Errorf("unsupported docker version: %s", info.ServerVersion)
|
return fmt.Errorf("unsupported docker version: %s", info.ServerVersion)
|
||||||
}
|
}
|
||||||
// Validate graph driver.
|
// Validate graph driver.
|
||||||
item := dockerConfigPrefix + "GRAPH_DRIVER"
|
item := dockerConfigPrefix + "GRAPH_DRIVER"
|
||||||
for _, d := range spec.GraphDriver {
|
for _, gd := range spec.GraphDriver {
|
||||||
if info.Driver == d {
|
if info.Driver == gd {
|
||||||
report(item, info.Driver, good)
|
d.Reporter.Report(item, info.Driver, good)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
report(item, info.Driver, bad)
|
d.Reporter.Report(item, info.Driver, bad)
|
||||||
return fmt.Errorf("unsupported graph driver: %s", info.Driver)
|
return fmt.Errorf("unsupported graph driver: %s", info.Driver)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateDockerInfo(t *testing.T) {
|
func TestValidateDockerInfo(t *testing.T) {
|
||||||
v := &DockerValidator{}
|
v := &DockerValidator{
|
||||||
|
Reporter: DefaultReporter,
|
||||||
|
}
|
||||||
spec := &DockerSpec{
|
spec := &DockerSpec{
|
||||||
Version: []string{`1\.(9|\d{2,})\..*`},
|
Version: []string{`1\.(9|\d{2,})\..*`},
|
||||||
GraphDriver: []string{"driver_1", "driver_2"},
|
GraphDriver: []string{"driver_1", "driver_2"},
|
||||||
|
@ -39,6 +39,7 @@ var _ Validator = &KernelValidator{}
|
|||||||
// and kernel configuration.
|
// and kernel configuration.
|
||||||
type KernelValidator struct {
|
type KernelValidator struct {
|
||||||
kernelRelease string
|
kernelRelease string
|
||||||
|
Reporter Reporter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KernelValidator) Name() string {
|
func (k *KernelValidator) Name() string {
|
||||||
@ -60,11 +61,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (k *KernelValidator) Validate(spec SysSpec) error {
|
func (k *KernelValidator) Validate(spec SysSpec) error {
|
||||||
out, err := exec.Command("uname", "-r").CombinedOutput()
|
release, err := exec.Command("uname", "-r").CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get kernel release: %v", err)
|
return fmt.Errorf("failed to get kernel release: %v", err)
|
||||||
}
|
}
|
||||||
k.kernelRelease = strings.TrimSpace(string(out))
|
k.kernelRelease = strings.TrimSpace(string(release))
|
||||||
var errs []error
|
var errs []error
|
||||||
errs = append(errs, k.validateKernelVersion(spec.KernelSpec))
|
errs = append(errs, k.validateKernelVersion(spec.KernelSpec))
|
||||||
errs = append(errs, k.validateKernelConfig(spec.KernelSpec))
|
errs = append(errs, k.validateKernelConfig(spec.KernelSpec))
|
||||||
@ -78,11 +79,11 @@ func (k *KernelValidator) validateKernelVersion(kSpec KernelSpec) error {
|
|||||||
for _, versionRegexp := range versionRegexps {
|
for _, versionRegexp := range versionRegexps {
|
||||||
r := regexp.MustCompile(versionRegexp)
|
r := regexp.MustCompile(versionRegexp)
|
||||||
if r.MatchString(k.kernelRelease) {
|
if r.MatchString(k.kernelRelease) {
|
||||||
report("KERNEL_VERSION", k.kernelRelease, good)
|
k.Reporter.Report("KERNEL_VERSION", k.kernelRelease, good)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
report("KERNEL_VERSION", k.kernelRelease, bad)
|
k.Reporter.Report("KERNEL_VERSION", k.kernelRelease, bad)
|
||||||
return fmt.Errorf("unsupported kernel release: %s", k.kernelRelease)
|
return fmt.Errorf("unsupported kernel release: %s", k.kernelRelease)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfi
|
|||||||
badConfigs := []string{}
|
badConfigs := []string{}
|
||||||
// reportAndRecord is a helper function to record bad config when
|
// reportAndRecord is a helper function to record bad config when
|
||||||
// report.
|
// report.
|
||||||
reportAndRecord := func(name, msg, desc string, result resultType) {
|
reportAndRecord := func(name, msg, desc string, result ValidationResultType) {
|
||||||
if result == bad {
|
if result == bad {
|
||||||
badConfigs = append(badConfigs, name)
|
badConfigs = append(badConfigs, name)
|
||||||
}
|
}
|
||||||
@ -109,7 +110,7 @@ func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfi
|
|||||||
if result != good && desc != "" {
|
if result != good && desc != "" {
|
||||||
msg = msg + " - " + desc
|
msg = msg + " - " + desc
|
||||||
}
|
}
|
||||||
report(name, msg, result)
|
k.Reporter.Report(name, msg, result)
|
||||||
}
|
}
|
||||||
const (
|
const (
|
||||||
required = iota
|
required = iota
|
||||||
@ -117,7 +118,7 @@ func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfi
|
|||||||
forbidden
|
forbidden
|
||||||
)
|
)
|
||||||
validateOpt := func(config KernelConfig, expect int) {
|
validateOpt := func(config KernelConfig, expect int) {
|
||||||
var found, missing resultType
|
var found, missing ValidationResultType
|
||||||
switch expect {
|
switch expect {
|
||||||
case required:
|
case required:
|
||||||
found, missing = good, bad
|
found, missing = good, bad
|
||||||
|
@ -24,7 +24,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateKernelVersion(t *testing.T) {
|
func TestValidateKernelVersion(t *testing.T) {
|
||||||
v := &KernelValidator{}
|
v := &KernelValidator{
|
||||||
|
Reporter: DefaultReporter,
|
||||||
|
}
|
||||||
// Currently, testRegex is align with DefaultSysSpec.KernelVersion, but in the future
|
// Currently, testRegex is align with DefaultSysSpec.KernelVersion, but in the future
|
||||||
// they may be different.
|
// they may be different.
|
||||||
// This is fine, because the test mainly tests the kernel version validation logic,
|
// This is fine, because the test mainly tests the kernel version validation logic,
|
||||||
@ -69,7 +71,9 @@ func TestValidateKernelVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateCachedKernelConfig(t *testing.T) {
|
func TestValidateCachedKernelConfig(t *testing.T) {
|
||||||
v := &KernelValidator{}
|
v := &KernelValidator{
|
||||||
|
Reporter: DefaultReporter,
|
||||||
|
}
|
||||||
testKernelSpec := KernelSpec{
|
testKernelSpec := KernelSpec{
|
||||||
Required: []KernelConfig{{Name: "REQUIRED_1"}, {Name: "REQUIRED_2", Aliases: []string{"ALIASE_REQUIRED_2"}}},
|
Required: []KernelConfig{{Name: "REQUIRED_1"}, {Name: "REQUIRED_2", Aliases: []string{"ALIASE_REQUIRED_2"}}},
|
||||||
Optional: []KernelConfig{{Name: "OPTIONAL_1"}, {Name: "OPTIONAL_2"}},
|
Optional: []KernelConfig{{Name: "OPTIONAL_1"}, {Name: "OPTIONAL_2"}},
|
||||||
@ -184,7 +188,9 @@ CONFIG_3=n`
|
|||||||
"CONFIG_2": asModule,
|
"CONFIG_2": asModule,
|
||||||
"CONFIG_3": leftOut,
|
"CONFIG_3": leftOut,
|
||||||
}
|
}
|
||||||
v := &KernelValidator{}
|
v := &KernelValidator{
|
||||||
|
Reporter: DefaultReporter,
|
||||||
|
}
|
||||||
got, err := v.parseKernelConfig(bytes.NewReader([]byte(config)))
|
got, err := v.parseKernelConfig(bytes.NewReader([]byte(config)))
|
||||||
assert.Nil(t, err, "Expect error not to occur when parse kernel configuration %q", config)
|
assert.Nil(t, err, "Expect error not to occur when parse kernel configuration %q", config)
|
||||||
assert.Equal(t, expected, got)
|
assert.Equal(t, expected, got)
|
||||||
|
@ -24,25 +24,27 @@ import (
|
|||||||
|
|
||||||
var _ Validator = &OSValidator{}
|
var _ Validator = &OSValidator{}
|
||||||
|
|
||||||
type OSValidator struct{}
|
type OSValidator struct {
|
||||||
|
Reporter Reporter
|
||||||
|
}
|
||||||
|
|
||||||
func (c *OSValidator) Name() string {
|
func (o *OSValidator) Name() string {
|
||||||
return "os"
|
return "os"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSValidator) Validate(spec SysSpec) error {
|
func (o *OSValidator) Validate(spec SysSpec) error {
|
||||||
out, err := exec.Command("uname").CombinedOutput()
|
os, err := exec.Command("uname").CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get os name: %v", err)
|
return fmt.Errorf("failed to get os name: %v", err)
|
||||||
}
|
}
|
||||||
return c.validateOS(strings.TrimSpace(string(out)), spec.OS)
|
return o.validateOS(strings.TrimSpace(string(os)), spec.OS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSValidator) validateOS(os, specOS string) error {
|
func (o *OSValidator) validateOS(os, specOS string) error {
|
||||||
if os != specOS {
|
if os != specOS {
|
||||||
report("OS", os, bad)
|
o.Reporter.Report("OS", os, bad)
|
||||||
return fmt.Errorf("unsupported operating system: %s", os)
|
return fmt.Errorf("unsupported operating system: %s", os)
|
||||||
}
|
}
|
||||||
report("OS", os, good)
|
o.Reporter.Report("OS", os, good)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateOS(t *testing.T) {
|
func TestValidateOS(t *testing.T) {
|
||||||
v := &OSValidator{}
|
v := &OSValidator{
|
||||||
|
Reporter: DefaultReporter,
|
||||||
|
}
|
||||||
specOS := "Linux"
|
specOS := "Linux"
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
os string
|
os string
|
||||||
|
@ -18,20 +18,22 @@ package system
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// resultType is type of the validation result. Different validation results
|
// ValidationResultType is type of the validation result. Different validation results
|
||||||
// corresponds to different colors.
|
// corresponds to different colors.
|
||||||
type resultType int
|
type ValidationResultType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
good resultType = iota
|
good ValidationResultType = iota
|
||||||
bad
|
bad
|
||||||
warn
|
warn
|
||||||
)
|
)
|
||||||
|
|
||||||
// color is the color of the message.
|
// color is the color of the message.
|
||||||
type color int
|
type color int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
red color = 31
|
red color = 31
|
||||||
@ -40,15 +42,19 @@ const (
|
|||||||
white = 37
|
white = 37
|
||||||
)
|
)
|
||||||
|
|
||||||
func wrap(s string, c color) string {
|
func colorize(s string, c color) string {
|
||||||
return fmt.Sprintf("\033[0;%dm%s\033[0m", c, s)
|
return fmt.Sprintf("\033[0;%dm%s\033[0m", c, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// report reports "item: r". item is white, and the color of r depends on the
|
// The default reporter for the system verification test
|
||||||
// result type.
|
type StreamReporter struct {
|
||||||
func report(item, r string, t resultType) {
|
// The stream that this reporter is writing to
|
||||||
|
WriteStream io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dr *StreamReporter) Report(key, value string, resultType ValidationResultType) error {
|
||||||
var c color
|
var c color
|
||||||
switch t {
|
switch resultType {
|
||||||
case good:
|
case good:
|
||||||
c = green
|
c = green
|
||||||
case bad:
|
case bad:
|
||||||
@ -58,5 +64,15 @@ func report(item, r string, t resultType) {
|
|||||||
default:
|
default:
|
||||||
c = white
|
c = white
|
||||||
}
|
}
|
||||||
fmt.Printf("%s: %s\n", wrap(item, white), wrap(r, c))
|
if dr.WriteStream == nil {
|
||||||
|
return fmt.Errorf("WriteStream has to be defined for this reporter")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(dr.WriteStream, "%s: %s\n", colorize(key, white), colorize(value, c))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultReporter is the default Reporter
|
||||||
|
var DefaultReporter = &StreamReporter{
|
||||||
|
WriteStream: os.Stdout,
|
||||||
}
|
}
|
@ -29,21 +29,31 @@ type Validator interface {
|
|||||||
Validate(SysSpec) error
|
Validate(SysSpec) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// validators are all the validators.
|
// Reporter is the interface for the reporters for the validators.
|
||||||
var validators = []Validator{
|
type Reporter interface {
|
||||||
&OSValidator{},
|
// Report reports the results of the system verification
|
||||||
&KernelValidator{},
|
Report(string, string, ValidationResultType) error
|
||||||
&CgroupsValidator{},
|
|
||||||
&DockerValidator{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate uses all validators to validate the system.
|
// Validate uses all validators to validate the system.
|
||||||
func Validate() error {
|
func Validate(spec SysSpec, report Reporter) error {
|
||||||
var errs []error
|
var errs []error
|
||||||
spec := DefaultSysSpec
|
// validators are all the validators.
|
||||||
|
var validators = []Validator{
|
||||||
|
&OSValidator{Reporter: report},
|
||||||
|
&KernelValidator{Reporter: report},
|
||||||
|
&CgroupsValidator{Reporter: report},
|
||||||
|
&DockerValidator{Reporter: report},
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range validators {
|
for _, v := range validators {
|
||||||
glog.Infof("Validating %s...", v.Name())
|
glog.Infof("Validating %s...", v.Name())
|
||||||
errs = append(errs, v.Validate(spec))
|
errs = append(errs, v.Validate(spec))
|
||||||
}
|
}
|
||||||
return errors.NewAggregate(errs)
|
return errors.NewAggregate(errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateDefault uses all default validators to validate the system and writes to stdout.
|
||||||
|
func ValidateDefault() error {
|
||||||
|
return Validate(DefaultSysSpec, DefaultReporter)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user