From e42eb28500e2014e7abb7a7bb275f1917db87be7 Mon Sep 17 00:00:00 2001 From: Alexander Kanevskiy Date: Wed, 1 Nov 2017 16:40:13 +0200 Subject: [PATCH] Implement individual control for kubeadm preflight checks With new flag `--ignore-checks-errors` user is able to decrease severity of each individual check to warning. Old flag `--skip-preflight-checks` now acts as `--ignore-checks-errors=all` and will produce warnings. Fixes: kubernetes/kubeadm#480 --- cmd/kubeadm/app/apis/kubeadm/validation/BUILD | 1 + .../app/apis/kubeadm/validation/validation.go | 27 ++- .../kubeadm/validation/validation_test.go | 29 +++ cmd/kubeadm/app/cmd/init.go | 34 +-- cmd/kubeadm/app/cmd/join.go | 36 ++-- cmd/kubeadm/app/cmd/phases/BUILD | 1 + cmd/kubeadm/app/cmd/phases/preflight.go | 5 +- cmd/kubeadm/app/cmd/reset.go | 26 ++- cmd/kubeadm/app/cmd/reset_test.go | 4 + cmd/kubeadm/app/cmd/upgrade/BUILD | 2 + cmd/kubeadm/app/cmd/upgrade/apply.go | 7 +- cmd/kubeadm/app/cmd/upgrade/common.go | 10 +- cmd/kubeadm/app/cmd/upgrade/plan.go | 6 +- cmd/kubeadm/app/cmd/upgrade/upgrade.go | 6 + cmd/kubeadm/app/preflight/BUILD | 2 + cmd/kubeadm/app/preflight/checks.go | 195 ++++++++++++++++-- cmd/kubeadm/app/preflight/checks_test.go | 19 +- 17 files changed, 332 insertions(+), 78 deletions(-) diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD index 1c5508fcab..ad9b8936a9 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/BUILD +++ b/cmd/kubeadm/app/apis/kubeadm/validation/BUILD @@ -33,6 +33,7 @@ go_library( "//pkg/registry/core/service/ipallocator:go_default_library", "//pkg/util/node:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", ], diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index e54416e8b0..65787dc5cf 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -26,6 +26,7 @@ import ( "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" @@ -289,7 +290,7 @@ func ValidateMixedArguments(flag *pflag.FlagSet) error { mixedInvalidFlags := []string{} flag.Visit(func(f *pflag.Flag) { - if f.Name == "config" || strings.HasPrefix(f.Name, "skip-") || f.Name == "dry-run" || f.Name == "kubeconfig" { + if f.Name == "config" || strings.HasPrefix(f.Name, "ignore-checks-") || strings.HasPrefix(f.Name, "skip-") || f.Name == "dry-run" || f.Name == "kubeconfig" { // "--skip-*" flags or other whitelisted flags can be set with --config return } @@ -328,3 +329,27 @@ func ValidateAPIEndpoint(c *kubeadm.MasterConfiguration, fldPath *field.Path) fi } return allErrs } + +// ValidateIgnoreChecksErrors validates duplicates in ignore-checks-errors flag. +func ValidateIgnoreChecksErrors(ignoreChecksErrors []string, skipPreflightChecks bool) (sets.String, error) { + ignoreErrors := sets.NewString() + allErrs := field.ErrorList{} + + for _, item := range ignoreChecksErrors { + ignoreErrors.Insert(strings.ToLower(item)) // parameters are case insensitive + } + + // TODO: remove once deprecated flag --skip-preflight-checks is removed. + if skipPreflightChecks { + if ignoreErrors.Has("all") { + allErrs = append(allErrs, field.Invalid(field.NewPath("ignore-checks-errors"), strings.Join(ignoreErrors.List(), ","), "'all' is used together with deprecated flag --skip-preflight-checks. Remove deprecated flag")) + } + ignoreErrors.Insert("all") + } + + if ignoreErrors.Has("all") && ignoreErrors.Len() > 1 { + allErrs = append(allErrs, field.Invalid(field.NewPath("ignore-checks-errors"), strings.Join(ignoreErrors.List(), ","), "don't specify individual checks if 'all' is used")) + } + + return ignoreErrors, allErrs.ToAggregate() +} diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go index 2344c9a97f..ebc197eecb 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go @@ -458,3 +458,32 @@ func TestValidateFeatureGates(t *testing.T) { } } } + +func TestValidateIgnoreChecksErrors(t *testing.T) { + var tests = []struct { + ignoreChecksErrors []string + skipPreflightChecks bool + expectedLen int + expectedError bool + }{ + {[]string{}, false, 0, false}, // empty list, no old skip-preflight-checks + {[]string{}, true, 1, false}, // empty list, old skip-preflight-checks + {[]string{"check1", "check2"}, false, 2, false}, // non-duplicate + {[]string{"check1", "check2"}, true, 3, true}, // non-duplicate, but skip-preflight-checks + {[]string{"check1", "check2", "check1"}, false, 2, false}, // duplicates + {[]string{"check1", "check2", "all"}, false, 3, true}, // non-duplicate, but 'all' present together wth individual checks + {[]string{"all"}, false, 1, false}, // skip all checks by using new flag + {[]string{"all"}, true, 1, true}, // skip all checks by using both old and new flags at the same time + } + for _, rt := range tests { + result, err := ValidateIgnoreChecksErrors(rt.ignoreChecksErrors, rt.skipPreflightChecks) + switch { + case err != nil && !rt.expectedError: + t.Errorf("ValidateIgnoreChecksErrors: unexpected error for input (%s, %v), error: %v", rt.ignoreChecksErrors, rt.skipPreflightChecks, err) + case err == nil && rt.expectedError: + t.Errorf("ValidateIgnoreChecksErrors: expected error for input (%s, %v) but got: %v", rt.ignoreChecksErrors, rt.skipPreflightChecks, result) + case result.Len() != rt.expectedLen: + t.Errorf("ValidateIgnoreChecksErrors: expected Len = %d for input (%s, %v) but got: %v, %v", rt.expectedLen, rt.ignoreChecksErrors, rt.skipPreflightChecks, result.Len(), result) + } + } +} diff --git a/cmd/kubeadm/app/cmd/init.go b/cmd/kubeadm/app/cmd/init.go index 815a7ce81c..458e02f837 100644 --- a/cmd/kubeadm/app/cmd/init.go +++ b/cmd/kubeadm/app/cmd/init.go @@ -31,6 +31,7 @@ import ( flag "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" clientset "k8s.io/client-go/kubernetes" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" @@ -112,6 +113,7 @@ func NewCmdInit(out io.Writer) *cobra.Command { var dryRun bool var featureGatesString string var criSocket string + var ignoreChecksErrors []string cmd := &cobra.Command{ Use: "init", @@ -126,7 +128,10 @@ func NewCmdInit(out io.Writer) *cobra.Command { internalcfg := &kubeadmapi.MasterConfiguration{} legacyscheme.Scheme.Convert(cfg, internalcfg, nil) - i, err := NewInit(cfgPath, internalcfg, skipPreFlight, skipTokenPrint, dryRun, criSocket) + ignoreChecksErrorsSet, err := validation.ValidateIgnoreChecksErrors(ignoreChecksErrors, skipPreFlight) + kubeadmutil.CheckErr(err) + + i, err := NewInit(cfgPath, internalcfg, ignoreChecksErrorsSet, skipTokenPrint, dryRun, criSocket) kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(i.Validate(cmd)) kubeadmutil.CheckErr(i.Run(out)) @@ -134,7 +139,7 @@ func NewCmdInit(out io.Writer) *cobra.Command { } AddInitConfigFlags(cmd.PersistentFlags(), cfg, &featureGatesString) - AddInitOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &skipTokenPrint, &dryRun, &criSocket) + AddInitOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &skipTokenPrint, &dryRun, &criSocket, &ignoreChecksErrors) return cmd } @@ -190,16 +195,21 @@ func AddInitConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiext.MasterConfigur } // AddInitOtherFlags adds init flags that are not bound to a configuration file to the given flagset -func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight, skipTokenPrint, dryRun *bool, criSocket *string) { +func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight, skipTokenPrint, dryRun *bool, criSocket *string, ignoreChecksErrors *[]string) { flagSet.StringVar( cfgPath, "config", *cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental.", ) + flagSet.StringSliceVar( + ignoreChecksErrors, "ignore-checks-errors", *ignoreChecksErrors, + "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.", + ) // Note: All flags that are not bound to the cfg object should be whitelisted in cmd/kubeadm/app/apis/kubeadm/validation/validation.go flagSet.BoolVar( skipPreFlight, "skip-preflight-checks", *skipPreFlight, "Skip preflight checks which normally run before modifying the system.", ) + flagSet.MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-checks-errors=all") // Note: All flags that are not bound to the cfg object should be whitelisted in cmd/kubeadm/app/apis/kubeadm/validation/validation.go flagSet.BoolVar( skipTokenPrint, "skip-token-print", *skipTokenPrint, @@ -217,7 +227,7 @@ func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight, sk } // NewInit validates given arguments and instantiates Init struct with provided information. -func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight, skipTokenPrint, dryRun bool, criSocket string) (*Init, error) { +func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, ignoreChecksErrors sets.String, skipTokenPrint, dryRun bool, criSocket string) (*Init, error) { fmt.Println("[kubeadm] WARNING: kubeadm is currently in beta") if cfgPath != "" { @@ -249,19 +259,15 @@ func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight, fmt.Println("\t(/etc/systemd/system/kubelet.service.d/10-kubeadm.conf should be edited for this purpose)") } - if !skipPreFlight { - fmt.Println("[preflight] Running pre-flight checks.") + fmt.Println("[preflight] Running pre-flight checks.") - if err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket); err != nil { - return nil, err - } - - // Try to start the kubelet service in case it's inactive - preflight.TryStartKubelet() - } else { - fmt.Println("[preflight] Skipping pre-flight checks.") + if err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket, ignoreChecksErrors); err != nil { + return nil, err } + // Try to start the kubelet service in case it's inactive + preflight.TryStartKubelet(ignoreChecksErrors) + return &Init{cfg: cfg, skipTokenPrint: skipTokenPrint, dryRun: dryRun}, nil } diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 266f268b06..9b34fc0846 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -29,6 +29,7 @@ import ( flag "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" clientset "k8s.io/client-go/kubernetes" certutil "k8s.io/client-go/util/cert" @@ -110,6 +111,7 @@ func NewCmdJoin(out io.Writer) *cobra.Command { var cfgPath string var criSocket string var featureGatesString string + var ignoreChecksErrors []string cmd := &cobra.Command{ Use: "join [flags]", @@ -127,7 +129,10 @@ func NewCmdJoin(out io.Writer) *cobra.Command { internalcfg := &kubeadmapi.NodeConfiguration{} legacyscheme.Scheme.Convert(cfg, internalcfg, nil) - j, err := NewJoin(cfgPath, args, internalcfg, skipPreFlight, criSocket) + ignoreChecksErrorsSet, err := validation.ValidateIgnoreChecksErrors(ignoreChecksErrors, skipPreFlight) + kubeadmutil.CheckErr(err) + + j, err := NewJoin(cfgPath, args, internalcfg, ignoreChecksErrorsSet, criSocket) kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(j.Validate(cmd)) kubeadmutil.CheckErr(j.Run(out)) @@ -135,7 +140,7 @@ func NewCmdJoin(out io.Writer) *cobra.Command { } AddJoinConfigFlags(cmd.PersistentFlags(), cfg, &featureGatesString) - AddJoinOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &criSocket) + AddJoinOtherFlags(cmd.PersistentFlags(), &cfgPath, &skipPreFlight, &criSocket, &ignoreChecksErrors) return cmd } @@ -170,15 +175,20 @@ func AddJoinConfigFlags(flagSet *flag.FlagSet, cfg *kubeadmapiext.NodeConfigurat } // AddJoinOtherFlags adds join flags that are not bound to a configuration file to the given flagset -func AddJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight *bool, criSocket *string) { +func AddJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight *bool, criSocket *string, ignoreChecksErrors *[]string) { flagSet.StringVar( cfgPath, "config", *cfgPath, "Path to kubeadm config file.") + flagSet.StringSliceVar( + ignoreChecksErrors, "ignore-checks-errors", *ignoreChecksErrors, + "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.", + ) flagSet.BoolVar( skipPreFlight, "skip-preflight-checks", false, "Skip preflight checks which normally run before modifying the system.", ) + flagSet.MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-checks-errors=all") flagSet.StringVar( criSocket, "cri-socket", "/var/run/dockershim.sock", `Specify the CRI socket to connect to.`, @@ -191,7 +201,7 @@ type Join struct { } // NewJoin instantiates Join struct with given arguments -func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, skipPreFlight bool, criSocket string) (*Join, error) { +func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, ignoreChecksErrors sets.String, criSocket string) (*Join, error) { fmt.Println("[kubeadm] WARNING: kubeadm is currently in beta") if cfg.NodeName == "" { @@ -208,20 +218,16 @@ func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, s } } - if !skipPreFlight { - fmt.Println("[preflight] Running pre-flight checks.") + fmt.Println("[preflight] Running pre-flight checks.") - // Then continue with the others... - if err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket); err != nil { - return nil, err - } - - // Try to start the kubelet service in case it's inactive - preflight.TryStartKubelet() - } else { - fmt.Println("[preflight] Skipping pre-flight checks.") + // Then continue with the others... + if err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket, ignoreChecksErrors); err != nil { + return nil, err } + // Try to start the kubelet service in case it's inactive + preflight.TryStartKubelet(ignoreChecksErrors) + return &Join{cfg: cfg}, nil } diff --git a/cmd/kubeadm/app/cmd/phases/BUILD b/cmd/kubeadm/app/cmd/phases/BUILD index d4cc7c6301..e2b0c0049e 100644 --- a/cmd/kubeadm/app/cmd/phases/BUILD +++ b/cmd/kubeadm/app/cmd/phases/BUILD @@ -50,6 +50,7 @@ go_library( "//pkg/util/normalizer:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", ], diff --git a/cmd/kubeadm/app/cmd/phases/preflight.go b/cmd/kubeadm/app/cmd/phases/preflight.go index 9e91da3ae0..54b51343af 100644 --- a/cmd/kubeadm/app/cmd/phases/preflight.go +++ b/cmd/kubeadm/app/cmd/phases/preflight.go @@ -19,6 +19,7 @@ package phases import ( "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/util/sets" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" @@ -70,7 +71,7 @@ func NewCmdPreFlightMaster() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { cfg := &kubeadmapi.MasterConfiguration{} criSocket := "" - err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket) + err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket, sets.NewString()) kubeadmutil.CheckErr(err) }, } @@ -88,7 +89,7 @@ func NewCmdPreFlightNode() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { cfg := &kubeadmapi.NodeConfiguration{} criSocket := "" - err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket) + err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket, sets.NewString()) kubeadmutil.CheckErr(err) }, } diff --git a/cmd/kubeadm/app/cmd/reset.go b/cmd/kubeadm/app/cmd/reset.go index 74db95f0e4..0352f6fd1b 100644 --- a/cmd/kubeadm/app/cmd/reset.go +++ b/cmd/kubeadm/app/cmd/reset.go @@ -26,7 +26,9 @@ import ( "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/util/sets" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" @@ -45,20 +47,30 @@ func NewCmdReset(out io.Writer) *cobra.Command { var skipPreFlight bool var certsDir string var criSocketPath string + var ignoreChecksErrors []string + cmd := &cobra.Command{ Use: "reset", Short: "Run this to revert any changes made to this host by 'kubeadm init' or 'kubeadm join'.", Run: func(cmd *cobra.Command, args []string) { - r, err := NewReset(skipPreFlight, certsDir, criSocketPath) + ignoreChecksErrorsSet, err := validation.ValidateIgnoreChecksErrors(ignoreChecksErrors, skipPreFlight) + kubeadmutil.CheckErr(err) + + r, err := NewReset(ignoreChecksErrorsSet, certsDir, criSocketPath) kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(r.Run(out)) }, } + cmd.PersistentFlags().StringSliceVar( + &ignoreChecksErrors, "ignore-checks-errors", ignoreChecksErrors, + "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.", + ) cmd.PersistentFlags().BoolVar( &skipPreFlight, "skip-preflight-checks", false, "Skip preflight checks which normally run before modifying the system.", ) + cmd.PersistentFlags().MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-checks-errors=all") cmd.PersistentFlags().StringVar( &certsDir, "cert-dir", kubeadmapiext.DefaultCertificatesDir, @@ -80,15 +92,11 @@ type Reset struct { } // NewReset instantiate Reset struct -func NewReset(skipPreFlight bool, certsDir, criSocketPath string) (*Reset, error) { - if !skipPreFlight { - fmt.Println("[preflight] Running pre-flight checks.") +func NewReset(ignoreChecksErrors sets.String, certsDir, criSocketPath string) (*Reset, error) { + fmt.Println("[preflight] Running pre-flight checks.") - if err := preflight.RunRootCheckOnly(); err != nil { - return nil, err - } - } else { - fmt.Println("[preflight] Skipping pre-flight checks.") + if err := preflight.RunRootCheckOnly(ignoreChecksErrors); err != nil { + return nil, err } return &Reset{ diff --git a/cmd/kubeadm/app/cmd/reset_test.go b/cmd/kubeadm/app/cmd/reset_test.go index 08a26328d6..59780e0a5a 100644 --- a/cmd/kubeadm/app/cmd/reset_test.go +++ b/cmd/kubeadm/app/cmd/reset_test.go @@ -195,6 +195,10 @@ func (c *fakeDockerChecker) Check() (warnings, errors []error) { return c.warnings, c.errors } +func (c *fakeDockerChecker) Name() string { + return "FakeDocker" +} + func newFakeDockerChecker(warnings, errors []error) preflight.Checker { return &fakeDockerChecker{warnings: warnings, errors: errors} } diff --git a/cmd/kubeadm/app/cmd/upgrade/BUILD b/cmd/kubeadm/app/cmd/upgrade/BUILD index e0489bd934..28658102d5 100644 --- a/cmd/kubeadm/app/cmd/upgrade/BUILD +++ b/cmd/kubeadm/app/cmd/upgrade/BUILD @@ -13,6 +13,7 @@ go_library( deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library", + "//cmd/kubeadm/app/apis/kubeadm/validation:go_default_library", "//cmd/kubeadm/app/cmd/util:go_default_library", "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/phases/controlplane:go_default_library", @@ -27,6 +28,7 @@ go_library( "//pkg/util/version:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/client-go/discovery/fake:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", ], diff --git a/cmd/kubeadm/app/cmd/upgrade/apply.go b/cmd/kubeadm/app/cmd/upgrade/apply.go index b36ddf23c1..9df0c51b7a 100644 --- a/cmd/kubeadm/app/cmd/upgrade/apply.go +++ b/cmd/kubeadm/app/cmd/upgrade/apply.go @@ -25,6 +25,7 @@ import ( clientset "k8s.io/client-go/kubernetes" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane" @@ -70,8 +71,12 @@ func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command { Use: "apply [version]", Short: "Upgrade your Kubernetes cluster to the specified version.", Run: func(cmd *cobra.Command, args []string) { + var err error + flags.parent.ignoreChecksErrorsSet, err = validation.ValidateIgnoreChecksErrors(flags.parent.ignoreChecksErrors, flags.parent.skipPreFlight) + kubeadmutil.CheckErr(err) + // Ensure the user is root - err := runPreflightChecks(flags.parent.skipPreFlight) + err = runPreflightChecks(flags.parent.ignoreChecksErrorsSet) kubeadmutil.CheckErr(err) err = cmdutil.ValidateExactArgNumber(args, []string{"version"}) diff --git a/cmd/kubeadm/app/cmd/upgrade/common.go b/cmd/kubeadm/app/cmd/upgrade/common.go index fdbe23a1e6..00e1fa031d 100644 --- a/cmd/kubeadm/app/cmd/upgrade/common.go +++ b/cmd/kubeadm/app/cmd/upgrade/common.go @@ -26,6 +26,7 @@ import ( "github.com/ghodss/yaml" + "k8s.io/apimachinery/pkg/util/sets" fakediscovery "k8s.io/client-go/discovery/fake" clientset "k8s.io/client-go/kubernetes" kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1" @@ -97,14 +98,9 @@ func printConfiguration(cfg *kubeadmapiext.MasterConfiguration, w io.Writer) { } // runPreflightChecks runs the root preflight check -func runPreflightChecks(skipPreFlight bool) error { - if skipPreFlight { - fmt.Println("[preflight] Skipping pre-flight checks.") - return nil - } - +func runPreflightChecks(ignoreChecksErrors sets.String) error { fmt.Println("[preflight] Running pre-flight checks.") - return preflight.RunRootCheckOnly() + return preflight.RunRootCheckOnly(ignoreChecksErrors) } // getClient gets a real or fake client depending on whether the user is dry-running or not diff --git a/cmd/kubeadm/app/cmd/upgrade/plan.go b/cmd/kubeadm/app/cmd/upgrade/plan.go index 43b74d5174..e09c70c1be 100644 --- a/cmd/kubeadm/app/cmd/upgrade/plan.go +++ b/cmd/kubeadm/app/cmd/upgrade/plan.go @@ -25,6 +25,7 @@ import ( "github.com/spf13/cobra" + "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" "k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" ) @@ -35,8 +36,11 @@ func NewCmdPlan(parentFlags *cmdUpgradeFlags) *cobra.Command { Use: "plan", Short: "Check which versions are available to upgrade to and validate whether your current cluster is upgradeable.", Run: func(_ *cobra.Command, _ []string) { + var err error + parentFlags.ignoreChecksErrorsSet, err = validation.ValidateIgnoreChecksErrors(parentFlags.ignoreChecksErrors, parentFlags.skipPreFlight) + kubeadmutil.CheckErr(err) // Ensure the user is root - err := runPreflightChecks(parentFlags.skipPreFlight) + err = runPreflightChecks(parentFlags.ignoreChecksErrorsSet) kubeadmutil.CheckErr(err) err = RunPlan(parentFlags) diff --git a/cmd/kubeadm/app/cmd/upgrade/upgrade.go b/cmd/kubeadm/app/cmd/upgrade/upgrade.go index d5d1f97107..0be0ef1254 100644 --- a/cmd/kubeadm/app/cmd/upgrade/upgrade.go +++ b/cmd/kubeadm/app/cmd/upgrade/upgrade.go @@ -20,6 +20,7 @@ import ( "io" "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/util/sets" cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util" ) @@ -31,6 +32,8 @@ type cmdUpgradeFlags struct { allowRCUpgrades bool printConfig bool skipPreFlight bool + ignoreChecksErrors []string + ignoreChecksErrorsSet sets.String } // NewCmdUpgrade returns the cobra command for `kubeadm upgrade` @@ -42,6 +45,7 @@ func NewCmdUpgrade(out io.Writer) *cobra.Command { allowRCUpgrades: false, printConfig: false, skipPreFlight: false, + ignoreChecksErrorsSet: sets.NewString(), } cmd := &cobra.Command{ @@ -55,7 +59,9 @@ func NewCmdUpgrade(out io.Writer) *cobra.Command { cmd.PersistentFlags().BoolVar(&flags.allowExperimentalUpgrades, "allow-experimental-upgrades", flags.allowExperimentalUpgrades, "Show unstable versions of Kubernetes as an upgrade alternative and allow upgrading to an alpha/beta/release candidate versions of Kubernetes.") cmd.PersistentFlags().BoolVar(&flags.allowRCUpgrades, "allow-release-candidate-upgrades", flags.allowRCUpgrades, "Show release candidate versions of Kubernetes as an upgrade alternative and allow upgrading to a release candidate versions of Kubernetes.") cmd.PersistentFlags().BoolVar(&flags.printConfig, "print-config", flags.printConfig, "Specifies whether the configuration file that will be used in the upgrade should be printed or not.") + cmd.PersistentFlags().StringSliceVar(&flags.ignoreChecksErrors, "ignore-checks-errors", flags.ignoreChecksErrors, "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.") cmd.PersistentFlags().BoolVar(&flags.skipPreFlight, "skip-preflight-checks", flags.skipPreFlight, "Skip preflight checks that normally run before modifying the system.") + cmd.PersistentFlags().MarkDeprecated("skip-preflight-checks", "it is now equivalent to --ignore-checks-errors=all") cmd.AddCommand(NewCmdApply(flags)) cmd.AddCommand(NewCmdPlan(flags)) diff --git a/cmd/kubeadm/app/preflight/BUILD b/cmd/kubeadm/app/preflight/BUILD index 09382e316c..baaea43aa3 100644 --- a/cmd/kubeadm/app/preflight/BUILD +++ b/cmd/kubeadm/app/preflight/BUILD @@ -36,6 +36,7 @@ go_library( "//vendor/github.com/blang/semver:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", ], ) @@ -51,6 +52,7 @@ go_test( deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", "//vendor/github.com/renstrom/dedent:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", ], ) diff --git a/cmd/kubeadm/app/preflight/checks.go b/cmd/kubeadm/app/preflight/checks.go index 2efef91378..f36b2e066c 100644 --- a/cmd/kubeadm/app/preflight/checks.go +++ b/cmd/kubeadm/app/preflight/checks.go @@ -41,6 +41,7 @@ import ( "net/url" netutil "k8s.io/apimachinery/pkg/util/net" + "k8s.io/apimachinery/pkg/util/sets" apiservoptions "k8s.io/kubernetes/cmd/kube-apiserver/app/options" cmoptions "k8s.io/kubernetes/cmd/kube-controller-manager/app/options" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" @@ -74,13 +75,14 @@ type Error struct { } func (e *Error) Error() string { - return fmt.Sprintf("[preflight] Some fatal errors occurred:\n%s%s", e.Msg, "[preflight] If you know what you are doing, you can skip pre-flight checks with `--skip-preflight-checks`") + return fmt.Sprintf("[preflight] Some fatal errors occurred:\n%s%s", e.Msg, "[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-checks-errors=...`") } // Checker validates the state of the system to ensure kubeadm will be // successful as often as possilble. type Checker interface { Check() (warnings, errors []error) + Name() string } // CRICheck verifies the container runtime through the CRI. @@ -89,6 +91,11 @@ type CRICheck struct { exec utilsexec.Interface } +// Name returns label for CRICheck. +func (CRICheck) Name() string { + return "CRI" +} + // Check validates the container runtime through the CRI. func (criCheck CRICheck) Check() (warnings, errors []error) { if err := criCheck.exec.Command("sh", "-c", fmt.Sprintf("crictl -r %s info", criCheck.socket)).Run(); err != nil { @@ -104,6 +111,15 @@ func (criCheck CRICheck) Check() (warnings, errors []error) { type ServiceCheck struct { Service string CheckIfActive bool + Label string +} + +// Name returns label for ServiceCheck. If not provided, will return based on the service parameter +func (sc ServiceCheck) Name() string { + if sc.Label != "" { + return sc.Label + } + return fmt.Sprintf("Service-%s", strings.Title(sc.Service)) } // Check validates if the service is enabled and active. @@ -141,6 +157,11 @@ type FirewalldCheck struct { ports []int } +// Name returns label for FirewalldCheck. +func (FirewalldCheck) Name() string { + return "Firewalld" +} + // Check validates if the firewall is enabled and active. func (fc FirewalldCheck) Check() (warnings, errors []error) { initSystem, err := initsystem.GetInitSystem() @@ -165,7 +186,16 @@ func (fc FirewalldCheck) Check() (warnings, errors []error) { // PortOpenCheck ensures the given port is available for use. type PortOpenCheck struct { - port int + port int + label string +} + +// Name returns name for PortOpenCheck. If not known, will return "PortXXXX" based on port number +func (poc PortOpenCheck) Name() string { + if poc.label != "" { + return poc.label + } + return fmt.Sprintf("Port-%d", poc.port) } // Check validates if the particular port is available. @@ -185,9 +215,23 @@ func (poc PortOpenCheck) Check() (warnings, errors []error) { // IsPrivilegedUserCheck verifies user is privileged (linux - root, windows - Administrator) type IsPrivilegedUserCheck struct{} +// Name returns name for IsPrivilegedUserCheck +func (IsPrivilegedUserCheck) Name() string { + return "IsPrivilegedUser" +} + // DirAvailableCheck checks if the given directory either does not exist, or is empty. type DirAvailableCheck struct { - Path string + Path string + Label string +} + +// Name returns label for individual DirAvailableChecks. If not known, will return based on path. +func (dac DirAvailableCheck) Name() string { + if dac.Label != "" { + return dac.Label + } + return fmt.Sprintf("DirAvailable-%s", strings.Replace(dac.Path, "/", "-", -1)) } // Check validates if a directory does not exist or empty. @@ -215,7 +259,16 @@ func (dac DirAvailableCheck) Check() (warnings, errors []error) { // FileAvailableCheck checks that the given file does not already exist. type FileAvailableCheck struct { - Path string + Path string + Label string +} + +// Name returns label for individual FileAvailableChecks. If not known, will return based on path. +func (fac FileAvailableCheck) Name() string { + if fac.Label != "" { + return fac.Label + } + return fmt.Sprintf("FileAvailable-%s", strings.Replace(fac.Path, "/", "-", -1)) } // Check validates if the given file does not already exist. @@ -229,7 +282,16 @@ func (fac FileAvailableCheck) Check() (warnings, errors []error) { // FileExistingCheck checks that the given file does not already exist. type FileExistingCheck struct { - Path string + Path string + Label string +} + +// Name returns label for individual FileExistingChecks. If not known, will return based on path. +func (fac FileExistingCheck) Name() string { + if fac.Label != "" { + return fac.Label + } + return fmt.Sprintf("FileExisting-%s", strings.Replace(fac.Path, "/", "-", -1)) } // Check validates if the given file already exists. @@ -245,6 +307,15 @@ func (fac FileExistingCheck) Check() (warnings, errors []error) { type FileContentCheck struct { Path string Content []byte + Label string +} + +// Name returns label for individual FileContentChecks. If not known, will return based on path. +func (fcc FileContentCheck) Name() string { + if fcc.Label != "" { + return fcc.Label + } + return fmt.Sprintf("FileContent-%s", strings.Replace(fcc.Path, "/", "-", -1)) } // Check validates if the given file contains the given content. @@ -275,6 +346,15 @@ type InPathCheck struct { executable string mandatory bool exec utilsexec.Interface + label string +} + +// Name returns label for individual InPathCheck. If not known, will return based on path. +func (ipc InPathCheck) Name() string { + if ipc.label != "" { + return ipc.label + } + return fmt.Sprintf("FileExisting-%s", strings.Replace(ipc.executable, "/", "-", -1)) } // Check validates if the given executable is present in the path. @@ -297,6 +377,11 @@ type HostnameCheck struct { nodeName string } +// Name will return Hostname as name for HostnameCheck +func (HostnameCheck) Name() string { + return "Hostname" +} + // Check validates if hostname match dns sub domain regex. func (hc HostnameCheck) Check() (warnings, errors []error) { errors = []error{} @@ -322,6 +407,11 @@ type HTTPProxyCheck struct { Port int } +// Name returns HTTPProxy as name for HTTPProxyCheck +func (hst HTTPProxyCheck) Name() string { + return "HTTPProxy" +} + // Check validates http connectivity type, direct or via proxy. func (hst HTTPProxyCheck) Check() (warnings, errors []error) { @@ -352,6 +442,11 @@ type HTTPProxyCIDRCheck struct { CIDR string } +// Name will return HTTPProxyCIDR as name for HTTPProxyCIDRCheck +func (HTTPProxyCIDRCheck) Name() string { + return "HTTPProxyCIDR" +} + // Check validates http connectivity to first IP address in the CIDR. // If it is not directly connected and goes via proxy it will produce warning. func (subnet HTTPProxyCIDRCheck) Check() (warnings, errors []error) { @@ -399,6 +494,11 @@ type ExtraArgsCheck struct { SchedulerExtraArgs map[string]string } +// Name will return ExtraArgs as name for ExtraArgsCheck +func (ExtraArgsCheck) Name() string { + return "ExtraArgs" +} + // Check validates additional arguments of the control plane components. func (eac ExtraArgsCheck) Check() (warnings, errors []error) { argsCheck := func(name string, args map[string]string, f *pflag.FlagSet) []error { @@ -438,6 +538,11 @@ type SystemVerificationCheck struct { CRISocket string } +// Name will return SystemVerification as name for SystemVerificationCheck +func (SystemVerificationCheck) Name() string { + return "SystemVerification" +} + // Check runs all individual checks func (sysver SystemVerificationCheck) Check() (warnings, errors []error) { // Create a buffered writer and choose a quite large value (1M) and suppose the output from the system verification test won't exceed the limit @@ -490,6 +595,11 @@ type KubernetesVersionCheck struct { KubernetesVersion string } +// Name will return KubernetesVersion as name for KubernetesVersionCheck +func (KubernetesVersionCheck) Name() string { + return "KubernetesVersion" +} + // Check validates kubernetes and kubeadm versions func (kubever KubernetesVersionCheck) Check() (warnings, errors []error) { @@ -525,6 +635,11 @@ type KubeletVersionCheck struct { KubernetesVersion string } +// Name will return KubeletVersion as name for KubeletVersionCheck +func (KubeletVersionCheck) Name() string { + return "KubeletVersion" +} + // Check validates kubelet version. It should be not less than minimal supported version func (kubever KubeletVersionCheck) Check() (warnings, errors []error) { kubeletVersion, err := GetKubeletVersion() @@ -550,6 +665,11 @@ func (kubever KubeletVersionCheck) Check() (warnings, errors []error) { // SwapCheck warns if swap is enabled type SwapCheck struct{} +// Name will return Swap as name for SwapCheck +func (SwapCheck) Name() string { + return "Swap" +} + // Check validates whether swap is enabled or not func (swc SwapCheck) Check() (warnings, errors []error) { f, err := os.Open("/proc/swaps") @@ -584,6 +704,11 @@ type ExternalEtcdVersionCheck struct { Etcd kubeadmapi.Etcd } +// Name will return ExternalEtcdVersion as name for ExternalEtcdVersionCheck +func (ExternalEtcdVersionCheck) Name() string { + return "ExternalEtcdVersion" +} + // Check validates external etcd version func (evc ExternalEtcdVersionCheck) Check() (warnings, errors []error) { var config *tls.Config @@ -712,9 +837,9 @@ func getEtcdVersionResponse(client *http.Client, url string, target interface{}) } // RunInitMasterChecks executes all individual, applicable to Master node checks. -func RunInitMasterChecks(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfiguration, criSocket string) error { +func RunInitMasterChecks(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfiguration, criSocket string, ignoreChecksErrors sets.String) error { // First, check if we're root separately from the other preflight checks and fail fast - if err := RunRootCheckOnly(); err != nil { + if err := RunRootCheckOnly(ignoreChecksErrors); err != nil { return err } @@ -804,13 +929,13 @@ func RunInitMasterChecks(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfi ) } } - return RunChecks(checks, os.Stderr) + return RunChecks(checks, os.Stderr, ignoreChecksErrors) } // RunJoinNodeChecks executes all individual, applicable to node checks. -func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.NodeConfiguration, criSocket string) error { +func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.NodeConfiguration, criSocket string, ignoreChecksErrors sets.String) error { // First, check if we're root separately from the other preflight checks and fail fast - if err := RunRootCheckOnly(); err != nil { + if err := RunRootCheckOnly(ignoreChecksErrors); err != nil { return err } @@ -862,33 +987,50 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.NodeConfigura } } } - return RunChecks(checks, os.Stderr) + return RunChecks(checks, os.Stderr, ignoreChecksErrors) } // RunRootCheckOnly initializes checks slice of structs and call RunChecks -func RunRootCheckOnly() error { +func RunRootCheckOnly(ignoreChecksErrors sets.String) error { checks := []Checker{ IsPrivilegedUserCheck{}, } - return RunChecks(checks, os.Stderr) + return RunChecks(checks, os.Stderr, ignoreChecksErrors) } // RunChecks runs each check, displays it's warnings/errors, and once all // are processed will exit if any errors occurred. -func RunChecks(checks []Checker, ww io.Writer) error { - found := []error{} +func RunChecks(checks []Checker, ww io.Writer, ignoreChecksErrors sets.String) error { + type checkErrors struct { + Name string + Errors []error + } + found := []checkErrors{} + for _, c := range checks { + name := c.Name() warnings, errs := c.Check() - for _, w := range warnings { - io.WriteString(ww, fmt.Sprintf("[preflight] WARNING: %v\n", w)) + + if setHasItemOrAll(ignoreChecksErrors, name) { + // Decrease severity of errors to warnings for this check + warnings = append(warnings, errs...) + errs = []error{} + } + + for _, w := range warnings { + io.WriteString(ww, fmt.Sprintf("\t[WARNING %s]: %v\n", name, w)) + } + if len(errs) > 0 { + found = append(found, checkErrors{Name: name, Errors: errs}) } - found = append(found, errs...) } if len(found) > 0 { var errs bytes.Buffer - for _, i := range found { - errs.WriteString("\t" + i.Error() + "\n") + for _, c := range found { + for _, i := range c.Errors { + errs.WriteString(fmt.Sprintf("\t[ERROR %s]: %v\n", c.Name, i.Error())) + } } return &Error{Msg: errs.String()} } @@ -896,7 +1038,10 @@ func RunChecks(checks []Checker, ww io.Writer) error { } // TryStartKubelet attempts to bring up kubelet service -func TryStartKubelet() { +func TryStartKubelet(ignoreChecksErrors sets.String) { + if setHasItemOrAll(ignoreChecksErrors, "StartKubelet") { + return + } // If we notice that the kubelet service is inactive, try to start it initSystem, err := initsystem.GetInitSystem() if err != nil { @@ -910,3 +1055,11 @@ func TryStartKubelet() { } } } + +// setHasItemOrAll is helper function that return true if item is present in the set (case insensitive) or special key 'all' is present +func setHasItemOrAll(s sets.String, item string) bool { + if s.Has("all") || s.Has(strings.ToLower(item)) { + return true + } + return false +} diff --git a/cmd/kubeadm/app/preflight/checks_test.go b/cmd/kubeadm/app/preflight/checks_test.go index f2703a0da2..2432b7c2ce 100644 --- a/cmd/kubeadm/app/preflight/checks_test.go +++ b/cmd/kubeadm/app/preflight/checks_test.go @@ -29,6 +29,7 @@ import ( "net/http" "os" + "k8s.io/apimachinery/pkg/util/sets" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/utils/exec" ) @@ -166,6 +167,10 @@ type preflightCheckTest struct { msg string } +func (pfct preflightCheckTest) Name() string { + return "preflightCheckTest" +} + func (pfct preflightCheckTest) Check() (warning, errors []error) { if pfct.msg == "warning" { return []error{fmt.Errorf("warning")}, nil @@ -218,7 +223,7 @@ func TestRunInitMasterChecks(t *testing.T) { } for _, rt := range tests { - actual := RunInitMasterChecks(exec.New(), rt.cfg, "") + actual := RunInitMasterChecks(exec.New(), rt.cfg, "", sets.NewString()) if (actual == nil) != rt.expected { t.Errorf( "failed RunInitMasterChecks:\n\texpected: %t\n\t actual: %t\n\t error: %v", @@ -254,7 +259,7 @@ func TestRunJoinNodeChecks(t *testing.T) { } for _, rt := range tests { - actual := RunJoinNodeChecks(exec.New(), rt.cfg, "") + actual := RunJoinNodeChecks(exec.New(), rt.cfg, "", sets.NewString()) if (actual == nil) != rt.expected { t.Errorf( "failed RunJoinNodeChecks:\n\texpected: %t\n\t actual: %t", @@ -272,7 +277,7 @@ func TestRunChecks(t *testing.T) { output string }{ {[]Checker{}, true, ""}, - {[]Checker{preflightCheckTest{"warning"}}, true, "[preflight] WARNING: warning\n"}, // should just print warning + {[]Checker{preflightCheckTest{"warning"}}, true, "\t[WARNING preflightCheckTest]: warning\n"}, // should just print warning {[]Checker{preflightCheckTest{"error"}}, false, ""}, {[]Checker{preflightCheckTest{"test"}}, false, ""}, {[]Checker{DirAvailableCheck{Path: "/does/not/exist"}}, true, ""}, @@ -281,7 +286,7 @@ func TestRunChecks(t *testing.T) { {[]Checker{FileContentCheck{Path: "/does/not/exist"}}, false, ""}, {[]Checker{FileContentCheck{Path: "/"}}, true, ""}, {[]Checker{FileContentCheck{Path: "/", Content: []byte("does not exist")}}, false, ""}, - {[]Checker{InPathCheck{executable: "foobarbaz", exec: exec.New()}}, true, "[preflight] WARNING: foobarbaz not found in system path\n"}, + {[]Checker{InPathCheck{executable: "foobarbaz", exec: exec.New()}}, true, "\t[WARNING FileExisting-foobarbaz]: foobarbaz not found in system path\n"}, {[]Checker{InPathCheck{executable: "foobarbaz", mandatory: true, exec: exec.New()}}, false, ""}, {[]Checker{ExtraArgsCheck{ APIServerExtraArgs: map[string]string{"secure-port": "1234"}, @@ -290,14 +295,14 @@ func TestRunChecks(t *testing.T) { }}, true, ""}, {[]Checker{ExtraArgsCheck{ APIServerExtraArgs: map[string]string{"secure-port": "foo"}, - }}, true, "[preflight] WARNING: kube-apiserver: failed to parse extra argument --secure-port=foo\n"}, + }}, true, "\t[WARNING ExtraArgs]: kube-apiserver: failed to parse extra argument --secure-port=foo\n"}, {[]Checker{ExtraArgsCheck{ APIServerExtraArgs: map[string]string{"invalid-argument": "foo"}, - }}, true, "[preflight] WARNING: kube-apiserver: failed to parse extra argument --invalid-argument=foo\n"}, + }}, true, "\t[WARNING ExtraArgs]: kube-apiserver: failed to parse extra argument --invalid-argument=foo\n"}, } for _, rt := range tokenTest { buf := new(bytes.Buffer) - actual := RunChecks(rt.p, buf) + actual := RunChecks(rt.p, buf, sets.NewString()) if (actual == nil) != rt.expected { t.Errorf( "failed RunChecks:\n\texpected: %t\n\t actual: %t",