kubeadm: validators pass warnings and errors

This change allows validators to pass warnings as well as errors. This
was needed because of how support for docker 1.13+ and the new EE and CE
versions is currently being handled.
This commit is contained in:
Derek McQuay 2017-03-08 11:28:36 -08:00
parent eeefd2ca87
commit 35f07095d8
No known key found for this signature in database
GPG Key ID: 92A7BC0C86B0B91A
8 changed files with 65 additions and 35 deletions

View File

@ -323,6 +323,7 @@ func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
reporter := &system.StreamReporter{WriteStream: bufw} reporter := &system.StreamReporter{WriteStream: bufw}
var errs []error var errs []error
var warns []error
// All the validators we'd like to run: // All the validators we'd like to run:
var validators = []system.Validator{ var validators = []system.Validator{
&system.OSValidator{Reporter: reporter}, &system.OSValidator{Reporter: reporter},
@ -333,7 +334,9 @@ func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
// Run all validators // Run all validators
for _, v := range validators { for _, v := range validators {
errs = append(errs, v.Validate(system.DefaultSysSpec)) warn, err := v.Validate(system.DefaultSysSpec)
errs = append(errs, err)
warns = append(warns, warn)
} }
err := utilerrors.NewAggregate(errs) err := utilerrors.NewAggregate(errs)
@ -341,9 +344,9 @@ func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
// Only print the output from the system verification check if the check failed // Only print the output from the system verification check if the check failed
fmt.Println("[preflight] The system verification failed. Printing the output from the verification:") fmt.Println("[preflight] The system verification failed. Printing the output from the verification:")
bufw.Flush() bufw.Flush()
return nil, []error{err} return warns, []error{err}
} }
return nil, nil return warns, nil
} }
type etcdVersionResponse struct { type etcdVersionResponse struct {

View File

@ -98,7 +98,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.ValidateDefault(framework.TestContext.ContainerRuntime); err != nil { if _, err := system.ValidateDefault(framework.TestContext.ContainerRuntime); err != nil {
glog.Exitf("system validation failed: %v", err) glog.Exitf("system validation failed: %v", err)
} }
return return

View File

@ -37,12 +37,12 @@ const (
cgroupsConfigPrefix = "CGROUPS_" cgroupsConfigPrefix = "CGROUPS_"
) )
func (c *CgroupsValidator) Validate(spec SysSpec) error { func (c *CgroupsValidator) Validate(spec SysSpec) (error, error) {
subsystems, err := c.getCgroupSubsystems() subsystems, err := c.getCgroupSubsystems()
if err != nil { if err != nil {
return fmt.Errorf("failed to get cgroup subsystems: %v", err) return nil, fmt.Errorf("failed to get cgroup subsystems: %v", err)
} }
return c.validateCgroupSubsystems(spec.Cgroups, subsystems) return nil, c.validateCgroupSubsystems(spec.Cgroups, subsystems)
} }
func (c *CgroupsValidator) validateCgroupSubsystems(cgroupSpec, subsystems []string) error { func (c *CgroupsValidator) validateCgroupSubsystems(cgroupSpec, subsystems []string) error {

View File

@ -37,29 +37,30 @@ func (d *DockerValidator) Name() string {
} }
const ( const (
dockerEndpoint = "unix:///var/run/docker.sock" dockerEndpoint = "unix:///var/run/docker.sock"
dockerConfigPrefix = "DOCKER_" dockerConfigPrefix = "DOCKER_"
maxDockerValidatedVersion = "1.12"
) )
// TODO(random-liu): Add more validating items. // TODO(random-liu): Add more validating items.
func (d *DockerValidator) Validate(spec SysSpec) error { func (d *DockerValidator) Validate(spec SysSpec) (error, error) {
if spec.RuntimeSpec.DockerSpec == nil { if spec.RuntimeSpec.DockerSpec == nil {
// If DockerSpec is not specified, assume current runtime is not // If DockerSpec is not specified, assume current runtime is not
// docker, skip the docker configuration validation. // docker, skip the docker configuration validation.
return nil return nil, nil
} }
c, err := client.NewClient(dockerEndpoint, "", nil, nil) c, err := client.NewClient(dockerEndpoint, "", nil, nil)
if err != nil { if err != nil {
return fmt.Errorf("failed to create docker client: %v", err) return nil, fmt.Errorf("failed to create docker client: %v", err)
} }
info, err := c.Info(context.Background()) info, err := c.Info(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get docker info: %v", err) return nil, fmt.Errorf("failed to get docker info: %v", err)
} }
return d.validateDockerInfo(spec.RuntimeSpec.DockerSpec, info) return d.validateDockerInfo(spec.RuntimeSpec.DockerSpec, info)
} }
func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info) error { func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info) (error, error) {
// Validate docker version. // Validate docker version.
matched := false matched := false
for _, v := range spec.Version { for _, v := range spec.Version {
@ -70,17 +71,29 @@ func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info)
} }
} }
if !matched { if !matched {
// catch if docker is 1.13+
ver := `1\.(1[3-9])\..*|\d{2}\.\d+\.\d+-[a-z]{2}`
r := regexp.MustCompile(ver)
if r.MatchString(info.ServerVersion) {
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, good)
w := fmt.Errorf(
"docker version is greater than the most recently validated version. Docker version: %s. Max validated version: %s",
info.ServerVersion,
maxDockerValidatedVersion,
)
return w, nil
}
d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, bad) d.Reporter.Report(dockerConfigPrefix+"VERSION", info.ServerVersion, bad)
return fmt.Errorf("unsupported docker version: %s", info.ServerVersion) return nil, fmt.Errorf("unsupported docker version: %s", info.ServerVersion)
} }
// Validate graph driver. // Validate graph driver.
item := dockerConfigPrefix + "GRAPH_DRIVER" item := dockerConfigPrefix + "GRAPH_DRIVER"
for _, gd := range spec.GraphDriver { for _, gd := range spec.GraphDriver {
if info.Driver == gd { if info.Driver == gd {
d.Reporter.Report(item, info.Driver, good) d.Reporter.Report(item, info.Driver, good)
return nil return nil, nil
} }
} }
d.Reporter.Report(item, info.Driver, bad) d.Reporter.Report(item, info.Driver, bad)
return fmt.Errorf("unsupported graph driver: %s", info.Driver) return nil, fmt.Errorf("unsupported graph driver: %s", info.Driver)
} }

View File

@ -28,42 +28,53 @@ func TestValidateDockerInfo(t *testing.T) {
Reporter: DefaultReporter, Reporter: DefaultReporter,
} }
spec := &DockerSpec{ spec := &DockerSpec{
Version: []string{`1\.(9|\d?[0-2]{2,})\..*`}, // Requires 1.9+ Version: []string{`1\.(9|1[0-2])\..*`}, // Requires 1.9+
GraphDriver: []string{"driver_1", "driver_2"}, GraphDriver: []string{"driver_1", "driver_2"},
} }
for _, test := range []struct { for _, test := range []struct {
info types.Info info types.Info
err bool err bool
warn bool
}{ }{
{ {
info: types.Info{Driver: "driver_1", ServerVersion: "1.10.1"}, info: types.Info{Driver: "driver_1", ServerVersion: "1.10.1"},
err: false, err: false,
warn: false,
}, },
{ {
info: types.Info{Driver: "bad_driver", ServerVersion: "1.9.1"}, info: types.Info{Driver: "bad_driver", ServerVersion: "1.9.1"},
err: true, err: true,
warn: false,
}, },
{ {
info: types.Info{Driver: "driver_2", ServerVersion: "1.8.1"}, info: types.Info{Driver: "driver_2", ServerVersion: "1.8.1"},
err: true, err: true,
warn: false,
}, },
// TODO remove once sig-node supports 1.13 // TODO remove/change warn value once sig-node supports 1.13
{ {
info: types.Info{Driver: "driver_2", ServerVersion: "1.13.1"}, info: types.Info{Driver: "driver_2", ServerVersion: "1.13.1"},
err: true, err: false,
warn: true,
}, },
// TODO remove once sig-node supports 17.03-0-ce // TODO remove/change warn value once sig-node supports 17.03-0-ce
{ {
info: types.Info{Driver: "driver_2", ServerVersion: "17.03.0-ce"}, info: types.Info{Driver: "driver_2", ServerVersion: "17.03.0-ce"},
err: true, err: false,
warn: true,
}, },
} { } {
err := v.validateDockerInfo(spec, test.info) warn, err := v.validateDockerInfo(spec, test.info)
if !test.err { if !test.err {
assert.Nil(t, err, "Expect error not to occur with docker info %+v", test.info) assert.Nil(t, err, "Expect error not to occur with docker info %+v", test.info)
} else { } else {
assert.NotNil(t, err, "Expect error to occur with docker info %+v", test.info) assert.NotNil(t, err, "Expect error to occur with docker info %+v", test.info)
} }
if !test.warn {
assert.Nil(t, warn, "Expect error not to occur with docker info %+v", test.info)
} else {
assert.NotNil(t, warn, "Expect error to occur with docker info %+v", test.info)
}
} }
} }

View File

@ -60,16 +60,16 @@ const (
kConfigPrefix = "CONFIG_" kConfigPrefix = "CONFIG_"
) )
func (k *KernelValidator) Validate(spec SysSpec) error { func (k *KernelValidator) Validate(spec SysSpec) (error, error) {
release, 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 nil, fmt.Errorf("failed to get kernel release: %v", err)
} }
k.kernelRelease = strings.TrimSpace(string(release)) 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))
return errors.NewAggregate(errs) return nil, errors.NewAggregate(errs)
} }
// validateKernelVersion validates the kernel version. // validateKernelVersion validates the kernel version.

View File

@ -32,12 +32,12 @@ func (o *OSValidator) Name() string {
return "os" return "os"
} }
func (o *OSValidator) Validate(spec SysSpec) error { func (o *OSValidator) Validate(spec SysSpec) (error, error) {
os, 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 nil, fmt.Errorf("failed to get os name: %v", err)
} }
return o.validateOS(strings.TrimSpace(string(os)), spec.OS) return nil, o.validateOS(strings.TrimSpace(string(os)), spec.OS)
} }
func (o *OSValidator) validateOS(os, specOS string) error { func (o *OSValidator) validateOS(os, specOS string) error {

View File

@ -26,7 +26,7 @@ type Validator interface {
// Name is the name of the validator. // Name is the name of the validator.
Name() string Name() string
// Validate is the validate function. // Validate is the validate function.
Validate(SysSpec) error Validate(SysSpec) (error, error)
} }
// Reporter is the interface for the reporters for the validators. // Reporter is the interface for the reporters for the validators.
@ -35,19 +35,22 @@ type Reporter interface {
Report(string, string, ValidationResultType) error Report(string, string, ValidationResultType) error
} }
// Validate uses validators to validate the system. // Validate uses validators to validate the system and returns a warning or error.
func Validate(spec SysSpec, validators []Validator) error { func Validate(spec SysSpec, validators []Validator) (error, error) {
var errs []error var errs []error
var warns []error
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)) warn, err := v.Validate(spec)
errs = append(errs, err)
warns = append(warns, warn)
} }
return errors.NewAggregate(errs) return errors.NewAggregate(warns), errors.NewAggregate(errs)
} }
// ValidateDefault uses all default validators to validate the system and writes to stdout. // ValidateDefault uses all default validators to validate the system and writes to stdout.
func ValidateDefault(runtime string) error { func ValidateDefault(runtime string) (error, error) {
// OS-level validators. // OS-level validators.
var osValidators = []Validator{ var osValidators = []Validator{
&OSValidator{Reporter: DefaultReporter}, &OSValidator{Reporter: DefaultReporter},