Merge pull request #75499 from marccarre/issues/74246-more-decl-kubeadm-cli-args

Add ability to configure kubeadm's ignored pre-flight errors via InitConfiguration and JoinConfiguration
k3s-v1.15.3
Kubernetes Prow Robot 2019-05-23 20:58:30 -07:00 committed by GitHub
commit 73b8011d47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 331 additions and 53 deletions

View File

@ -32,6 +32,7 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
fuzzClusterConfiguration,
fuzzComponentConfigs,
fuzzDNS,
fuzzNodeRegistration,
fuzzLocalEtcd,
fuzzNetworking,
fuzzJoinConfiguration,
@ -87,6 +88,13 @@ func fuzzInitConfiguration(obj *kubeadm.InitConfiguration, c fuzz.Continue) {
obj.CertificateKey = ""
}
func fuzzNodeRegistration(obj *kubeadm.NodeRegistrationOptions, c fuzz.Continue) {
c.FuzzNoCustom(obj)
// Pinning values for fields that get defaults if fuzz value is empty string or nil (thus making the round trip test fail)
obj.IgnorePreflightErrors = nil
}
func fuzzClusterConfiguration(obj *kubeadm.ClusterConfiguration, c fuzz.Continue) {
c.FuzzNoCustom(obj)

View File

@ -229,6 +229,9 @@ type NodeRegistrationOptions struct {
// kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config-1.X ConfigMap
// Flags have higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
KubeletExtraArgs map[string]string
// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored when the current node is registered.
IgnorePreflightErrors []string
}
// Networking contains elements describing cluster's networking configuration.

View File

@ -45,3 +45,15 @@ func Convert_kubeadm_JoinControlPlane_To_v1beta1_JoinControlPlane(in *kubeadm.Jo
return nil
}
func Convert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOptions(in *kubeadm.NodeRegistrationOptions, out *NodeRegistrationOptions, s conversion.Scope) error {
if err := autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOptions(in, out, s); err != nil {
return err
}
if len(in.IgnorePreflightErrors) > 0 {
return errors.New("ignorePreflightErrors field is not supported by v1beta1 config format")
}
return nil
}

View File

@ -37,6 +37,14 @@ func TestInternalToVersionedInitConfigurationConversion(t *testing.T) {
},
expectedError: true,
},
"ignorePreflightErrors set causes an error": {
in: kubeadm.InitConfiguration{
NodeRegistration: kubeadm.NodeRegistrationOptions{
IgnorePreflightErrors: []string{"SomeUndesirableError"},
},
},
expectedError: true,
},
}
for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
@ -51,6 +59,66 @@ func TestInternalToVersionedInitConfigurationConversion(t *testing.T) {
}
}
func TestInternalToVersionedJoinConfigurationConversion(t *testing.T) {
testcases := map[string]struct {
in kubeadm.JoinConfiguration
expectedError bool
}{
"conversion succeeds": {
in: kubeadm.JoinConfiguration{},
expectedError: false,
},
"ignorePreflightErrors set causes an error": {
in: kubeadm.JoinConfiguration{
NodeRegistration: kubeadm.NodeRegistrationOptions{
IgnorePreflightErrors: []string{"SomeUndesirableError"},
},
},
expectedError: true,
},
}
for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
versioned := &JoinConfiguration{}
err := Convert_kubeadm_JoinConfiguration_To_v1beta1_JoinConfiguration(&tc.in, versioned, nil)
if err == nil && tc.expectedError {
t.Error("unexpected success")
} else if err != nil && !tc.expectedError {
t.Errorf("unexpected error: %v", err)
}
})
}
}
func TestInternalToVersionedNodeRegistrationOptionsConversion(t *testing.T) {
testcases := map[string]struct {
in kubeadm.NodeRegistrationOptions
expectedError bool
}{
"conversion succeeds": {
in: kubeadm.NodeRegistrationOptions{},
expectedError: false,
},
"ignorePreflightErrors set causes an error": {
in: kubeadm.NodeRegistrationOptions{
IgnorePreflightErrors: []string{"SomeUndesirableError"},
},
expectedError: true,
},
}
for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
versioned := &NodeRegistrationOptions{}
err := Convert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOptions(&tc.in, versioned, nil)
if err == nil && tc.expectedError {
t.Error("unexpected success")
} else if err != nil && !tc.expectedError {
t.Errorf("unexpected error: %v", err)
}
})
}
}
func TestInternalToVersionedJoinControlPlaneConversion(t *testing.T) {
testcases := map[string]struct {
in kubeadm.JoinControlPlane

View File

@ -257,6 +257,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*kubeadm.NodeRegistrationOptions)(nil), (*NodeRegistrationOptions)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOptions(a.(*kubeadm.NodeRegistrationOptions), b.(*NodeRegistrationOptions), scope)
}); err != nil {
return err
}
return nil
}
@ -848,10 +853,6 @@ func autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOpti
out.CRISocket = in.CRISocket
out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints))
out.KubeletExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.KubeletExtraArgs))
// WARNING: in.IgnorePreflightErrors requires manual conversion: does not exist in peer-type
return nil
}
// Convert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOptions is an autogenerated conversion function.
func Convert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOptions(in *kubeadm.NodeRegistrationOptions, out *NodeRegistrationOptions, s conversion.Scope) error {
return autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta1_NodeRegistrationOptions(in, out, s)
}

View File

@ -215,6 +215,9 @@ type NodeRegistrationOptions struct {
// kubeadm writes at runtime for the kubelet to source. This overrides the generic base-level configuration in the kubelet-config-1.X ConfigMap
// Flags have higher priority when parsing. These values are local and specific to the node kubeadm is executing on.
KubeletExtraArgs map[string]string `json:"kubeletExtraArgs,omitempty"`
// IgnorePreflightErrors provides a slice of pre-flight errors to be ignored when the current node is registered.
IgnorePreflightErrors []string `json:"ignorePreflightErrors,omitempty"`
}
// Networking contains elements describing cluster's networking configuration

View File

@ -821,6 +821,7 @@ func autoConvert_v1beta2_NodeRegistrationOptions_To_kubeadm_NodeRegistrationOpti
out.CRISocket = in.CRISocket
out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints))
out.KubeletExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.KubeletExtraArgs))
out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
return nil
}
@ -834,6 +835,7 @@ func autoConvert_kubeadm_NodeRegistrationOptions_To_v1beta2_NodeRegistrationOpti
out.CRISocket = in.CRISocket
out.Taints = *(*[]corev1.Taint)(unsafe.Pointer(&in.Taints))
out.KubeletExtraArgs = *(*map[string]string)(unsafe.Pointer(&in.KubeletExtraArgs))
out.IgnorePreflightErrors = *(*[]string)(unsafe.Pointer(&in.IgnorePreflightErrors))
return nil
}

View File

@ -538,6 +538,11 @@ func (in *NodeRegistrationOptions) DeepCopyInto(out *NodeRegistrationOptions) {
(*out)[key] = val
}
}
if in.IgnorePreflightErrors != nil {
in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}

View File

@ -34,6 +34,7 @@ go_test(
"//cmd/kubeadm/app/apis/kubeadm/v1beta2:go_default_library",
"//pkg/proxy/apis/config:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",

View File

@ -463,12 +463,25 @@ func ValidateAPIEndpoint(c *kubeadm.APIEndpoint, fldPath *field.Path) field.Erro
return allErrs
}
// ValidateIgnorePreflightErrors validates duplicates in ignore-preflight-errors flag.
func ValidateIgnorePreflightErrors(ignorePreflightErrors []string) (sets.String, error) {
// ValidateIgnorePreflightErrors validates duplicates in:
// - ignore-preflight-errors flag and
// - ignorePreflightErrors field in {Init,Join}Configuration files.
func ValidateIgnorePreflightErrors(ignorePreflightErrorsFromCLI, ignorePreflightErrorsFromConfigFile []string) (sets.String, error) {
ignoreErrors := sets.NewString()
allErrs := field.ErrorList{}
for _, item := range ignorePreflightErrors {
for _, item := range ignorePreflightErrorsFromConfigFile {
ignoreErrors.Insert(strings.ToLower(item)) // parameters are case insensitive
}
if ignoreErrors.Has("all") {
// "all" is forbidden in config files. Administrators should use an
// explicit list of errors they want to ignore, as it can be risky to
// mask all errors in such a way. Hence, we return an error:
allErrs = append(allErrs, field.Invalid(field.NewPath("ignorePreflightErrors"), "all", "'all' cannot be used in configuration file"))
}
for _, item := range ignorePreflightErrorsFromCLI {
ignoreErrors.Insert(strings.ToLower(item)) // parameters are case insensitive
}

View File

@ -24,6 +24,7 @@ import (
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
@ -703,26 +704,81 @@ func TestValidateFeatureGates(t *testing.T) {
func TestValidateIgnorePreflightErrors(t *testing.T) {
var tests = []struct {
ignorePreflightErrors []string
expectedLen int
expectedError bool
ignorePreflightErrorsFromCLI []string
ignorePreflightErrorsFromConfigFile []string
expectedSet sets.String
expectedError bool
}{
{[]string{}, 0, false}, // empty list
{[]string{"check1", "check2"}, 2, false}, // non-duplicate
{[]string{"check1", "check2", "check1"}, 2, false}, // duplicates
{[]string{"check1", "check2", "all"}, 3, true}, // non-duplicate, but 'all' present together wth individual checks
{[]string{"all"}, 1, false}, // skip all checks by using new flag
{[]string{"all"}, 1, false}, // skip all checks by using both old and new flags at the same time
{ // empty lists in CLI and config file
[]string{},
[]string{},
sets.NewString(),
false,
},
{ // empty list in CLI only
[]string{},
[]string{"a"},
sets.NewString("a"),
false,
},
{ // empty list in config file only
[]string{"a"},
[]string{},
sets.NewString("a"),
false,
},
{ // no duplicates, no overlap
[]string{"a", "b"},
[]string{"c", "d"},
sets.NewString("a", "b", "c", "d"),
false,
},
{ // some duplicates, with some overlapping duplicates
[]string{"a", "b", "a"},
[]string{"c", "b"},
sets.NewString("a", "b", "c"),
false,
},
{ // non-duplicate, but 'all' present together with individual checks in CLI
[]string{"a", "b", "all"},
[]string{},
sets.NewString(),
true,
},
{ // empty list in CLI, but 'all' present in config file, which is forbidden
[]string{},
[]string{"all"},
sets.NewString(),
true,
},
{ // non-duplicate, but 'all' present in config file, which is forbidden
[]string{"a", "b"},
[]string{"all"},
sets.NewString(),
true,
},
{ // non-duplicate, but 'all' present in CLI, while values are in config file, which is forbidden
[]string{"all"},
[]string{"a", "b"},
sets.NewString(),
true,
},
{ // skip all checks
[]string{"all"},
[]string{},
sets.NewString("all"),
false,
},
}
for _, rt := range tests {
result, err := ValidateIgnorePreflightErrors(rt.ignorePreflightErrors)
result, err := ValidateIgnorePreflightErrors(rt.ignorePreflightErrorsFromCLI, rt.ignorePreflightErrorsFromConfigFile)
switch {
case err != nil && !rt.expectedError:
t.Errorf("ValidateIgnorePreflightErrors: unexpected error for input (%s), error: %v", rt.ignorePreflightErrors, err)
t.Errorf("ValidateIgnorePreflightErrors: unexpected error for input (%s, %s), error: %v", rt.ignorePreflightErrorsFromCLI, rt.ignorePreflightErrorsFromConfigFile, err)
case err == nil && rt.expectedError:
t.Errorf("ValidateIgnorePreflightErrors: expected error for input (%s) but got: %v", rt.ignorePreflightErrors, result)
case result.Len() != rt.expectedLen:
t.Errorf("ValidateIgnorePreflightErrors: expected Len = %d for input (%s) but got: %v, %v", rt.expectedLen, rt.ignorePreflightErrors, result.Len(), result)
t.Errorf("ValidateIgnorePreflightErrors: expected error for input (%s, %s) but got: %v", rt.ignorePreflightErrorsFromCLI, rt.ignorePreflightErrorsFromConfigFile, result)
case err == nil && !result.Equal(rt.expectedSet):
t.Errorf("ValidateIgnorePreflightErrors: expected (%v) for input (%s, %s) but got: %v", rt.expectedSet, rt.ignorePreflightErrorsFromCLI, rt.ignorePreflightErrorsFromConfigFile, result)
}
}
}

View File

@ -567,6 +567,11 @@ func (in *NodeRegistrationOptions) DeepCopyInto(out *NodeRegistrationOptions) {
(*out)[key] = val
}
}
if in.IgnorePreflightErrors != nil {
in, out := &in.IgnorePreflightErrors, &out.IgnorePreflightErrors
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}

View File

@ -99,6 +99,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/testing:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",

View File

@ -296,11 +296,6 @@ func newInitData(cmd *cobra.Command, args []string, options *initOptions, out io
return nil, err
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors)
if err != nil {
return nil, err
}
if err = validation.ValidateMixedArguments(cmd.Flags()); err != nil {
return nil, err
}
@ -316,6 +311,13 @@ func newInitData(cmd *cobra.Command, args []string, options *initOptions, out io
return nil, err
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors, cfg.NodeRegistration.IgnorePreflightErrors)
if err != nil {
return nil, err
}
// Also set the union of pre-flight errors to InitConfiguration, to provide a consistent view of the runtime configuration:
cfg.NodeRegistration.IgnorePreflightErrors = ignorePreflightErrorsSet.List()
// override node name and CRI socket from the command line options
if options.externalcfg.NodeRegistration.Name != "" {
cfg.NodeRegistration.Name = options.externalcfg.NodeRegistration.Name

View File

@ -23,6 +23,7 @@ import (
"path/filepath"
"testing"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
"k8s.io/kubernetes/cmd/kubeadm/app/features"
)
@ -38,6 +39,9 @@ bootstrapTokens:
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: someName
ignorePreflightErrors:
- c
- d
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
@ -129,6 +133,30 @@ func TestNewInitData(t *testing.T) {
},
expectError: true,
},
// Pre-flight errors:
{
name: "pre-flights errors from CLI args only",
flags: map[string]string{
options.IgnorePreflightErrors: "a,b",
},
validate: expectedInitIgnorePreflightErrors("a", "b"),
},
{
name: "pre-flights errors from InitConfiguration only",
flags: map[string]string{
options.CfgPath: configFilePath,
},
validate: expectedInitIgnorePreflightErrors("c", "d"),
},
{
name: "pre-flights errors from both CLI args and InitConfiguration",
flags: map[string]string{
options.CfgPath: configFilePath,
options.IgnorePreflightErrors: "a,b",
},
validate: expectedInitIgnorePreflightErrors("a", "b", "c", "d"),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@ -157,3 +185,15 @@ func TestNewInitData(t *testing.T) {
})
}
}
func expectedInitIgnorePreflightErrors(expectedItems ...string) func(t *testing.T, data *initData) {
expected := sets.NewString(expectedItems...)
return func(t *testing.T, data *initData) {
if !expected.Equal(data.ignorePreflightErrors) {
t.Errorf("Invalid ignore preflight errors. Expected: %v. Actual: %v", expected.List(), data.ignorePreflightErrors.List())
}
if !expected.HasAll(data.cfg.NodeRegistration.IgnorePreflightErrors...) {
t.Errorf("Invalid ignore preflight errors in InitConfiguration. Expected: %v. Actual: %v", expected.List(), data.cfg.NodeRegistration.IgnorePreflightErrors)
}
}
}

View File

@ -349,12 +349,7 @@ func newJoinData(cmd *cobra.Command, args []string, opt *joinOptions, out io.Wri
}
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(opt.ignorePreflightErrors)
if err != nil {
return nil, err
}
if err = validation.ValidateMixedArguments(cmd.Flags()); err != nil {
if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil {
return nil, err
}
@ -383,6 +378,13 @@ func newJoinData(cmd *cobra.Command, args []string, opt *joinOptions, out io.Wri
return nil, err
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(opt.ignorePreflightErrors, cfg.NodeRegistration.IgnorePreflightErrors)
if err != nil {
return nil, err
}
// Also set the union of pre-flight errors to JoinConfiguration, to provide a consistent view of the runtime configuration:
cfg.NodeRegistration.IgnorePreflightErrors = ignorePreflightErrorsSet.List()
// override node name and CRI socket from the command line opt
if opt.externalcfg.NodeRegistration.Name != "" {
cfg.NodeRegistration.Name = opt.externalcfg.NodeRegistration.Name

View File

@ -22,6 +22,7 @@ import (
"path/filepath"
"testing"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
)
@ -36,6 +37,9 @@ discovery:
nodeRegistration:
criSocket: /run/containerd/containerd.sock
name: someName
ignorePreflightErrors:
- c
- d
`
)
@ -215,6 +219,31 @@ func TestNewJoinData(t *testing.T) {
},
expectError: true,
},
// Pre-flight errors:
{
name: "pre-flights errors from CLI args only",
flags: map[string]string{
options.IgnorePreflightErrors: "a,b",
options.FileDiscovery: "https://foo", //required only to pass discovery validation
},
validate: expectedJoinIgnorePreflightErrors(sets.NewString("a", "b")),
},
{
name: "pre-flights errors from JoinConfiguration only",
flags: map[string]string{
options.CfgPath: configFilePath,
},
validate: expectedJoinIgnorePreflightErrors(sets.NewString("c", "d")),
},
{
name: "pre-flights errors from both CLI args and JoinConfiguration",
flags: map[string]string{
options.CfgPath: configFilePath,
options.IgnorePreflightErrors: "a,b",
},
validate: expectedJoinIgnorePreflightErrors(sets.NewString("a", "b", "c", "d")),
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@ -243,3 +272,14 @@ func TestNewJoinData(t *testing.T) {
})
}
}
func expectedJoinIgnorePreflightErrors(expected sets.String) func(t *testing.T, data *joinData) {
return func(t *testing.T, data *joinData) {
if !expected.Equal(data.ignorePreflightErrors) {
t.Errorf("Invalid ignore preflight errors. Expected: %v. Actual: %v", expected.List(), data.ignorePreflightErrors.List())
}
if !expected.HasAll(data.cfg.NodeRegistration.IgnorePreflightErrors...) {
t.Errorf("Invalid ignore preflight errors in JoinConfiguration. Expected: %v. Actual: %v", expected.List(), data.cfg.NodeRegistration.IgnorePreflightErrors)
}
}
}

View File

@ -84,10 +84,6 @@ func newResetOptions() *resetOptions {
// newResetData returns a new resetData struct to be used for the execution of the kubeadm reset workflow.
func newResetData(cmd *cobra.Command, options *resetOptions, in io.Reader, out io.Writer) (*resetData, error) {
var cfg *kubeadmapi.InitConfiguration
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors)
if err != nil {
return nil, err
}
client, err := getClientset(options.kubeconfigPath, false)
if err == nil {
@ -100,6 +96,16 @@ func newResetData(cmd *cobra.Command, options *resetOptions, in io.Reader, out i
klog.V(1).Infof("[reset] Could not obtain a client set from the kubeconfig file: %s", options.kubeconfigPath)
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors, ignorePreflightErrors(cfg))
if err != nil {
return nil, err
}
kubeadmutil.CheckErr(err)
if cfg != nil {
// Also set the union of pre-flight errors to InitConfiguration, to provide a consistent view of the runtime configuration:
cfg.NodeRegistration.IgnorePreflightErrors = ignorePreflightErrorsSet.List()
}
var criSocketPath string
if options.criSocketPath == "" {
criSocketPath, err = resetDetectCRISocket(cfg)
@ -121,6 +127,13 @@ func newResetData(cmd *cobra.Command, options *resetOptions, in io.Reader, out i
}, nil
}
func ignorePreflightErrors(cfg *kubeadmapi.InitConfiguration) []string {
if cfg == nil {
return []string{}
}
return cfg.NodeRegistration.IgnorePreflightErrors
}
// AddResetFlags adds reset flags
func AddResetFlags(flagSet *flag.FlagSet, resetOptions *resetOptions) {
flagSet.StringVar(

View File

@ -76,17 +76,6 @@ func getK8sVersionFromUserInput(flags *applyPlanFlags, args []string, versionIsM
// enforceRequirements verifies that it's okay to upgrade and then returns the variables needed for the rest of the procedure
func enforceRequirements(flags *applyPlanFlags, dryRun bool, newK8sVersion string) (clientset.Interface, upgrade.VersionGetter, *kubeadmapi.InitConfiguration, error) {
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(flags.ignorePreflightErrors)
if err != nil {
return nil, nil, nil, err
}
// Ensure the user is root
klog.V(1).Info("running preflight checks")
if err := runPreflightChecks(ignorePreflightErrorsSet); err != nil {
return nil, nil, nil, err
}
client, err := getClient(flags.kubeConfigPath, dryRun)
if err != nil {
return nil, nil, nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", flags.kubeConfigPath)
@ -97,11 +86,6 @@ func enforceRequirements(flags *applyPlanFlags, dryRun bool, newK8sVersion strin
return nil, nil, nil, errors.New("cannot upgrade a self-hosted control plane")
}
// Run healthchecks against the cluster
if err := upgrade.CheckClusterHealth(client, ignorePreflightErrorsSet); err != nil {
return nil, nil, nil, errors.Wrap(err, "[upgrade/health] FATAL")
}
// Fetch the configuration from a file or ConfigMap and validate it
fmt.Println("[upgrade/config] Making sure the configuration is correct:")
@ -112,6 +96,24 @@ func enforceRequirements(flags *applyPlanFlags, dryRun bool, newK8sVersion strin
cfg, err = configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "upgrade/config", false)
}
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(flags.ignorePreflightErrors, cfg.NodeRegistration.IgnorePreflightErrors)
if err != nil {
return nil, nil, nil, err
}
// Also set the union of pre-flight errors to InitConfiguration, to provide a consistent view of the runtime configuration:
cfg.NodeRegistration.IgnorePreflightErrors = ignorePreflightErrorsSet.List()
// Ensure the user is root
klog.V(1).Info("running preflight checks")
if err := runPreflightChecks(ignorePreflightErrorsSet); err != nil {
return nil, nil, nil, err
}
// Run healthchecks against the cluster
if err := upgrade.CheckClusterHealth(client, ignorePreflightErrorsSet); err != nil {
return nil, nil, nil, errors.Wrap(err, "[upgrade/health] FATAL")
}
if err != nil {
if apierrors.IsNotFound(err) {
fmt.Printf("[upgrade/config] In order to upgrade, a ConfigMap called %q in the %s namespace must exist.\n", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem)

View File

@ -15,6 +15,7 @@ Discovery:
Timeout: 5m0s
NodeRegistration:
CRISocket: /var/run/dockershim.sock
IgnorePreflightErrors: null
KubeletExtraArgs: null
Name: control-plane-1
Taints: