mirror of https://github.com/k3s-io/k3s
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#480pull/6/head
parent
bf32170dca
commit
e42eb28500
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -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"})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue