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}
var errs []error
var warns []error
// All the validators we'd like to run:
var validators = []system.Validator{
&system.OSValidator{Reporter: reporter},
@ -333,7 +334,9 @@ func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
// Run all 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)
@ -341,9 +344,9 @@ func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
// 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:")
bufw.Flush()
return nil, []error{err}
return warns, []error{err}
}
return nil, nil
return warns, nil
}
type etcdVersionResponse struct {

View File

@ -98,7 +98,7 @@ func TestE2eNode(t *testing.T) {
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)
}
return

View File

@ -37,12 +37,12 @@ const (
cgroupsConfigPrefix = "CGROUPS_"
)
func (c *CgroupsValidator) Validate(spec SysSpec) error {
func (c *CgroupsValidator) Validate(spec SysSpec) (error, error) {
subsystems, err := c.getCgroupSubsystems()
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 {

View File

@ -37,29 +37,30 @@ func (d *DockerValidator) Name() string {
}
const (
dockerEndpoint = "unix:///var/run/docker.sock"
dockerConfigPrefix = "DOCKER_"
dockerEndpoint = "unix:///var/run/docker.sock"
dockerConfigPrefix = "DOCKER_"
maxDockerValidatedVersion = "1.12"
)
// 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 DockerSpec is not specified, assume current runtime is not
// docker, skip the docker configuration validation.
return nil
return nil, nil
}
c, err := client.NewClient(dockerEndpoint, "", nil, 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())
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)
}
func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info) error {
func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info) (error, error) {
// Validate docker version.
matched := false
for _, v := range spec.Version {
@ -70,17 +71,29 @@ func (d *DockerValidator) validateDockerInfo(spec *DockerSpec, info types.Info)
}
}
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)
return fmt.Errorf("unsupported docker version: %s", info.ServerVersion)
return nil, fmt.Errorf("unsupported docker version: %s", info.ServerVersion)
}
// Validate graph driver.
item := dockerConfigPrefix + "GRAPH_DRIVER"
for _, gd := range spec.GraphDriver {
if info.Driver == gd {
d.Reporter.Report(item, info.Driver, good)
return nil
return nil, nil
}
}
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,
}
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"},
}
for _, test := range []struct {
info types.Info
err bool
warn bool
}{
{
info: types.Info{Driver: "driver_1", ServerVersion: "1.10.1"},
err: false,
warn: false,
},
{
info: types.Info{Driver: "bad_driver", ServerVersion: "1.9.1"},
err: true,
warn: false,
},
{
info: types.Info{Driver: "driver_2", ServerVersion: "1.8.1"},
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"},
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"},
err: true,
err: false,
warn: true,
},
} {
err := v.validateDockerInfo(spec, test.info)
warn, err := v.validateDockerInfo(spec, test.info)
if !test.err {
assert.Nil(t, err, "Expect error not to occur with docker info %+v", test.info)
} else {
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_"
)
func (k *KernelValidator) Validate(spec SysSpec) error {
func (k *KernelValidator) Validate(spec SysSpec) (error, error) {
release, err := exec.Command("uname", "-r").CombinedOutput()
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))
var errs []error
errs = append(errs, k.validateKernelVersion(spec.KernelSpec))
errs = append(errs, k.validateKernelConfig(spec.KernelSpec))
return errors.NewAggregate(errs)
return nil, errors.NewAggregate(errs)
}
// validateKernelVersion validates the kernel version.

View File

@ -32,12 +32,12 @@ func (o *OSValidator) Name() string {
return "os"
}
func (o *OSValidator) Validate(spec SysSpec) error {
func (o *OSValidator) Validate(spec SysSpec) (error, error) {
os, err := exec.Command("uname").CombinedOutput()
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 {

View File

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