From dacec687a42c574c33a11e545fce4449e4a9cc96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Sat, 12 Nov 2016 16:36:40 +0200 Subject: [PATCH] Add a reporter to the system verification check --- test/e2e_node/e2e_node_suite_test.go | 2 +- test/e2e_node/system/BUILD | 2 +- test/e2e_node/system/cgroup_validator.go | 8 +++-- test/e2e_node/system/cgroup_validator_test.go | 4 ++- test/e2e_node/system/docker_validator.go | 16 +++++---- test/e2e_node/system/docker_validator_test.go | 4 ++- test/e2e_node/system/kernel_validator.go | 15 ++++---- test/e2e_node/system/kernel_validator_test.go | 12 +++++-- test/e2e_node/system/os_validator.go | 18 +++++----- test/e2e_node/system/os_validator_test.go | 4 ++- test/e2e_node/system/{util.go => report.go} | 36 +++++++++++++------ test/e2e_node/system/validators.go | 26 +++++++++----- 12 files changed, 96 insertions(+), 51 deletions(-) rename test/e2e_node/system/{util.go => report.go} (54%) diff --git a/test/e2e_node/e2e_node_suite_test.go b/test/e2e_node/e2e_node_suite_test.go index 740f67b2a0e..c32b9cfee2d 100644 --- a/test/e2e_node/e2e_node_suite_test.go +++ b/test/e2e_node/e2e_node_suite_test.go @@ -93,7 +93,7 @@ func TestE2eNode(t *testing.T) { 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) } return diff --git a/test/e2e_node/system/BUILD b/test/e2e_node/system/BUILD index 646b3d4970a..5bef71351e0 100644 --- a/test/e2e_node/system/BUILD +++ b/test/e2e_node/system/BUILD @@ -17,8 +17,8 @@ go_library( "docker_validator.go", "kernel_validator.go", "os_validator.go", + "report.go", "types.go", - "util.go", "validators.go", ], tags = ["automanaged"], diff --git a/test/e2e_node/system/cgroup_validator.go b/test/e2e_node/system/cgroup_validator.go index 6ec1d76fcfa..86119a36032 100644 --- a/test/e2e_node/system/cgroup_validator.go +++ b/test/e2e_node/system/cgroup_validator.go @@ -25,7 +25,9 @@ import ( var _ Validator = &CgroupsValidator{} -type CgroupsValidator struct{} +type CgroupsValidator struct { + Reporter Reporter +} func (c *CgroupsValidator) Name() string { return "cgroups" @@ -55,9 +57,9 @@ func (c *CgroupsValidator) validateCgroupSubsystems(cgroupSpec, subsystems []str } item := cgroupsConfigPrefix + strings.ToUpper(cgroup) if found { - report(item, "enabled", good) + c.Reporter.Report(item, "enabled", good) } else { - report(item, "missing", bad) + c.Reporter.Report(item, "missing", bad) missing = append(missing, cgroup) } } diff --git a/test/e2e_node/system/cgroup_validator_test.go b/test/e2e_node/system/cgroup_validator_test.go index d306154b96d..c8f8275085d 100644 --- a/test/e2e_node/system/cgroup_validator_test.go +++ b/test/e2e_node/system/cgroup_validator_test.go @@ -23,7 +23,9 @@ import ( ) func TestValidateCgroupSubsystem(t *testing.T) { - v := &CgroupsValidator{} + v := &CgroupsValidator{ + Reporter: DefaultReporter, + } cgroupSpec := []string{"system1", "system2"} for desc, test := range map[string]struct { cgroupSpec []string diff --git a/test/e2e_node/system/docker_validator.go b/test/e2e_node/system/docker_validator.go index 0e207df8cb4..aa045b4adf1 100644 --- a/test/e2e_node/system/docker_validator.go +++ b/test/e2e_node/system/docker_validator.go @@ -28,7 +28,9 @@ import ( var _ Validator = &DockerValidator{} // DockerValidator validates docker configuration. -type DockerValidator struct{} +type DockerValidator struct { + Reporter Reporter +} func (d *DockerValidator) Name() string { return "docker" @@ -63,22 +65,22 @@ func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info) for _, v := range spec.Version { r := regexp.MustCompile(v) if r.MatchString(info.ServerVersion) { - report(dockerConfigPrefix+"VERSION", info.ServerVersion, good) + d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, good) matched = true } } 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) } // Validate graph driver. item := dockerConfigPrefix + "GRAPH_DRIVER" - for _, d := range spec.GraphDriver { - if info.Driver == d { - report(item, info.Driver, good) + for _, gd := range spec.GraphDriver { + if info.Driver == gd { + d.Reporter.Report(item, info.Driver, good) return nil } } - report(item, info.Driver, bad) + d.Reporter.Report(item, info.Driver, bad) return fmt.Errorf("unsupported graph driver: %s", info.Driver) } diff --git a/test/e2e_node/system/docker_validator_test.go b/test/e2e_node/system/docker_validator_test.go index 7e3f43171b0..0672b0c2988 100644 --- a/test/e2e_node/system/docker_validator_test.go +++ b/test/e2e_node/system/docker_validator_test.go @@ -24,7 +24,9 @@ import ( ) func TestValidateDockerInfo(t *testing.T) { - v := &DockerValidator{} + v := &DockerValidator{ + Reporter: DefaultReporter, + } spec := &DockerSpec{ Version: []string{`1\.(9|\d{2,})\..*`}, GraphDriver: []string{"driver_1", "driver_2"}, diff --git a/test/e2e_node/system/kernel_validator.go b/test/e2e_node/system/kernel_validator.go index e98cd46510f..19cd17fc7c6 100644 --- a/test/e2e_node/system/kernel_validator.go +++ b/test/e2e_node/system/kernel_validator.go @@ -39,6 +39,7 @@ var _ Validator = &KernelValidator{} // and kernel configuration. type KernelValidator struct { kernelRelease string + Reporter Reporter } func (k *KernelValidator) Name() string { @@ -60,11 +61,11 @@ const ( ) func (k *KernelValidator) Validate(spec SysSpec) error { - out, err := exec.Command("uname", "-r").CombinedOutput() + release, err := exec.Command("uname", "-r").CombinedOutput() if err != nil { 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 errs = append(errs, k.validateKernelVersion(spec.KernelSpec)) errs = append(errs, k.validateKernelConfig(spec.KernelSpec)) @@ -78,11 +79,11 @@ func (k *KernelValidator) validateKernelVersion(kSpec KernelSpec) error { for _, versionRegexp := range versionRegexps { r := regexp.MustCompile(versionRegexp) if r.MatchString(k.kernelRelease) { - report("KERNEL_VERSION", k.kernelRelease, good) + k.Reporter.Report("KERNEL_VERSION", k.kernelRelease, good) 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) } @@ -101,7 +102,7 @@ func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfi badConfigs := []string{} // reportAndRecord is a helper function to record bad config when // report. - reportAndRecord := func(name, msg, desc string, result resultType) { + reportAndRecord := func(name, msg, desc string, result ValidationResultType) { if result == bad { badConfigs = append(badConfigs, name) } @@ -109,7 +110,7 @@ func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfi if result != good && desc != "" { msg = msg + " - " + desc } - report(name, msg, result) + k.Reporter.Report(name, msg, result) } const ( required = iota @@ -117,7 +118,7 @@ func (k *KernelValidator) validateCachedKernelConfig(allConfig map[string]kConfi forbidden ) validateOpt := func(config KernelConfig, expect int) { - var found, missing resultType + var found, missing ValidationResultType switch expect { case required: found, missing = good, bad diff --git a/test/e2e_node/system/kernel_validator_test.go b/test/e2e_node/system/kernel_validator_test.go index be1420a4a20..92daad28c69 100644 --- a/test/e2e_node/system/kernel_validator_test.go +++ b/test/e2e_node/system/kernel_validator_test.go @@ -24,7 +24,9 @@ import ( ) func TestValidateKernelVersion(t *testing.T) { - v := &KernelValidator{} + v := &KernelValidator{ + Reporter: DefaultReporter, + } // Currently, testRegex is align with DefaultSysSpec.KernelVersion, but in the future // they may be different. // 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) { - v := &KernelValidator{} + v := &KernelValidator{ + Reporter: DefaultReporter, + } testKernelSpec := KernelSpec{ Required: []KernelConfig{{Name: "REQUIRED_1"}, {Name: "REQUIRED_2", Aliases: []string{"ALIASE_REQUIRED_2"}}}, Optional: []KernelConfig{{Name: "OPTIONAL_1"}, {Name: "OPTIONAL_2"}}, @@ -184,7 +188,9 @@ CONFIG_3=n` "CONFIG_2": asModule, "CONFIG_3": leftOut, } - v := &KernelValidator{} + v := &KernelValidator{ + Reporter: DefaultReporter, + } got, err := v.parseKernelConfig(bytes.NewReader([]byte(config))) assert.Nil(t, err, "Expect error not to occur when parse kernel configuration %q", config) assert.Equal(t, expected, got) diff --git a/test/e2e_node/system/os_validator.go b/test/e2e_node/system/os_validator.go index fc228a3418c..b5cd34c4694 100644 --- a/test/e2e_node/system/os_validator.go +++ b/test/e2e_node/system/os_validator.go @@ -24,25 +24,27 @@ import ( var _ Validator = &OSValidator{} -type OSValidator struct{} +type OSValidator struct { + Reporter Reporter +} -func (c *OSValidator) Name() string { +func (o *OSValidator) Name() string { return "os" } -func (c *OSValidator) Validate(spec SysSpec) error { - out, err := exec.Command("uname").CombinedOutput() +func (o *OSValidator) Validate(spec SysSpec) error { + os, err := exec.Command("uname").CombinedOutput() if err != nil { 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 { - report("OS", os, bad) + o.Reporter.Report("OS", os, bad) return fmt.Errorf("unsupported operating system: %s", os) } - report("OS", os, good) + o.Reporter.Report("OS", os, good) return nil } diff --git a/test/e2e_node/system/os_validator_test.go b/test/e2e_node/system/os_validator_test.go index f9e70a752c1..f4338f74a75 100644 --- a/test/e2e_node/system/os_validator_test.go +++ b/test/e2e_node/system/os_validator_test.go @@ -23,7 +23,9 @@ import ( ) func TestValidateOS(t *testing.T) { - v := &OSValidator{} + v := &OSValidator{ + Reporter: DefaultReporter, + } specOS := "Linux" for _, test := range []struct { os string diff --git a/test/e2e_node/system/util.go b/test/e2e_node/system/report.go similarity index 54% rename from test/e2e_node/system/util.go rename to test/e2e_node/system/report.go index 612891fcac2..6ece3e81586 100644 --- a/test/e2e_node/system/util.go +++ b/test/e2e_node/system/report.go @@ -18,20 +18,22 @@ package system import ( "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. -type resultType int +type ValidationResultType int32 const ( - good resultType = iota + good ValidationResultType = iota bad warn ) // color is the color of the message. -type color int +type color int32 const ( red color = 31 @@ -40,15 +42,19 @@ const ( 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) } -// report reports "item: r". item is white, and the color of r depends on the -// result type. -func report(item, r string, t resultType) { +// The default reporter for the system verification test +type StreamReporter struct { + // The stream that this reporter is writing to + WriteStream io.Writer +} + +func (dr *StreamReporter) Report(key, value string, resultType ValidationResultType) error { var c color - switch t { + switch resultType { case good: c = green case bad: @@ -58,5 +64,15 @@ func report(item, r string, t resultType) { default: 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, } diff --git a/test/e2e_node/system/validators.go b/test/e2e_node/system/validators.go index c799f8ff34d..277c30cb4de 100644 --- a/test/e2e_node/system/validators.go +++ b/test/e2e_node/system/validators.go @@ -29,21 +29,31 @@ type Validator interface { Validate(SysSpec) error } -// validators are all the validators. -var validators = []Validator{ - &OSValidator{}, - &KernelValidator{}, - &CgroupsValidator{}, - &DockerValidator{}, +// Reporter is the interface for the reporters for the validators. +type Reporter interface { + // Report reports the results of the system verification + Report(string, string, ValidationResultType) error } // Validate uses all validators to validate the system. -func Validate() error { +func Validate(spec SysSpec, report Reporter) 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 { glog.Infof("Validating %s...", v.Name()) errs = append(errs, v.Validate(spec)) } return errors.NewAggregate(errs) } + +// ValidateDefault uses all default validators to validate the system and writes to stdout. +func ValidateDefault() error { + return Validate(DefaultSysSpec, DefaultReporter) +}