diff --git a/cmd/kubeadm/app/cmd/config.go b/cmd/kubeadm/app/cmd/config.go index be8d486b531..30435f2b187 100644 --- a/cmd/kubeadm/app/cmd/config.go +++ b/cmd/kubeadm/app/cmd/config.go @@ -311,7 +311,7 @@ func newCmdConfigMigrate(out io.Writer) *cobra.Command { // newCmdConfigValidate returns cobra.Command for the "kubeadm config validate" command func newCmdConfigValidate(out io.Writer) *cobra.Command { var cfgPath string - var allowExperimental bool + var allowDeprecated, allowExperimental bool cmd := &cobra.Command{ Use: "validate", @@ -336,7 +336,7 @@ func newCmdConfigValidate(out io.Writer) *cobra.Command { return err } - if err := configutil.ValidateConfig(cfgBytes, allowExperimental); err != nil { + if err := configutil.ValidateConfig(cfgBytes, allowDeprecated, allowExperimental); err != nil { return err } fmt.Fprintln(out, "ok") @@ -346,6 +346,7 @@ func newCmdConfigValidate(out io.Writer) *cobra.Command { Args: cobra.NoArgs, } options.AddConfigFlag(cmd.Flags(), &cfgPath) + cmd.Flags().BoolVar(&allowDeprecated, options.AllowDeprecatedAPI, false, "Allow validation of deprecated APIs.") cmd.Flags().BoolVar(&allowExperimental, options.AllowExperimentalAPI, false, "Allow validation of experimental, unreleased APIs.") return cmd } diff --git a/cmd/kubeadm/app/cmd/options/constant.go b/cmd/kubeadm/app/cmd/options/constant.go index 34334458617..44c5fb669d9 100644 --- a/cmd/kubeadm/app/cmd/options/constant.go +++ b/cmd/kubeadm/app/cmd/options/constant.go @@ -143,6 +143,9 @@ const ( // CleanupTmpDir flag indicates whether reset will cleanup the tmp dir CleanupTmpDir = "cleanup-tmp-dir" + // AllowDeprecatedAPI flag can be used to allow deprecated APIs + AllowDeprecatedAPI = "allow-deprecated-api" + // AllowExperimentalAPI flag can be used to allow experimental / work in progress APIs AllowExperimentalAPI = "allow-experimental-api" diff --git a/cmd/kubeadm/app/util/config/common.go b/cmd/kubeadm/app/util/config/common.go index 3fda0e89dd9..f8666754c85 100644 --- a/cmd/kubeadm/app/util/config/common.go +++ b/cmd/kubeadm/app/util/config/common.go @@ -322,12 +322,28 @@ func MigrateOldConfig(oldConfig []byte, allowExperimental bool, mutators migrate newConfig = append(newConfig, b) } + // Migrate UpgradeConfiguration if there is any + if kubeadmutil.GroupVersionKindsHasUpgradeConfiguration(gvks...) { + o, err := documentMapToUpgradeConfiguration(gvkmap, true, allowExperimental, true) + if err != nil { + return []byte{}, err + } + if err := mutators.mutate([]any{o}); err != nil { + return []byte{}, err + } + b, err := MarshalKubeadmConfigObject(o, gv) + if err != nil { + return []byte{}, err + } + newConfig = append(newConfig, b) + } + return bytes.Join(newConfig, []byte(constants.YAMLDocumentSeparator)), nil } // ValidateConfig takes a byte slice containing a kubeadm configuration and performs conversion // to internal types and validation. -func ValidateConfig(config []byte, allowExperimental bool) error { +func ValidateConfig(config []byte, allowDeprecated, allowExperimental bool) error { gvkmap, err := kubeadmutil.SplitConfigDocuments(config) if err != nil { return err @@ -344,21 +360,28 @@ func ValidateConfig(config []byte, allowExperimental bool) error { // Validate InitConfiguration and ClusterConfiguration if there are any in the config if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvks...) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvks...) { - if _, err := documentMapToInitConfiguration(gvkmap, true, allowExperimental, true, true); err != nil { + if _, err := documentMapToInitConfiguration(gvkmap, allowDeprecated, allowExperimental, true, true); err != nil { return err } } // Validate JoinConfiguration if there is any if kubeadmutil.GroupVersionKindsHasJoinConfiguration(gvks...) { - if _, err := documentMapToJoinConfiguration(gvkmap, true, allowExperimental, true, true); err != nil { + if _, err := documentMapToJoinConfiguration(gvkmap, allowDeprecated, allowExperimental, true, true); err != nil { return err } } // Validate ResetConfiguration if there is any if kubeadmutil.GroupVersionKindsHasResetConfiguration(gvks...) { - if _, err := documentMapToResetConfiguration(gvkmap, true, allowExperimental, true, true); err != nil { + if _, err := documentMapToResetConfiguration(gvkmap, allowDeprecated, allowExperimental, true, true); err != nil { + return err + } + } + + // Validate UpgradeConfiguration if there is any + if kubeadmutil.GroupVersionKindsHasUpgradeConfiguration(gvks...) { + if _, err := documentMapToUpgradeConfiguration(gvkmap, allowDeprecated, allowExperimental, true); err != nil { return err } } diff --git a/cmd/kubeadm/app/util/config/common_test.go b/cmd/kubeadm/app/util/config/common_test.go index 8f8692cd7dd..cf3b9907c45 100644 --- a/cmd/kubeadm/app/util/config/common_test.go +++ b/cmd/kubeadm/app/util/config/common_test.go @@ -726,7 +726,7 @@ func TestValidateConfig(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := ValidateConfig([]byte(test.cfg), test.allowExperimental) + err := ValidateConfig([]byte(test.cfg), true, test.allowExperimental) if (err != nil) != test.expectedError { t.Fatalf("expected error: %v, got: %v, error: %v", test.expectedError, (err != nil), err) } diff --git a/cmd/kubeadm/app/util/config/upgradeconfiguration.go b/cmd/kubeadm/app/util/config/upgradeconfiguration.go index 3b4b56909f6..43f5fb004f5 100644 --- a/cmd/kubeadm/app/util/config/upgradeconfiguration.go +++ b/cmd/kubeadm/app/util/config/upgradeconfiguration.go @@ -34,7 +34,7 @@ import ( // documentMapToUpgradeConfiguration takes a map between GVKs and YAML/JSON documents (as returned by SplitYAMLDocuments), // finds a UpgradeConfiguration, decodes it, dynamically defaults it and then validates it prior to return. -func documentMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated bool) (*kubeadmapi.UpgradeConfiguration, error) { +func documentMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated, allowExperimental, strictErrors bool) (*kubeadmapi.UpgradeConfiguration, error) { upgradeBytes := []byte{} for gvk, bytes := range gvkmap { @@ -44,13 +44,17 @@ func documentMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap, allowDepre } // check if this version is supported and possibly not deprecated - if err := validateSupportedVersion(gvk, allowDeprecated, true); err != nil { + if err := validateSupportedVersion(gvk, allowDeprecated, allowExperimental); err != nil { return nil, err } // verify the validity of the YAML/JSON if err := strict.VerifyUnmarshalStrict([]*runtime.Scheme{kubeadmscheme.Scheme}, gvk, bytes); err != nil { - klog.Warning(err.Error()) + if !strictErrors { + klog.Warning(err.Error()) + } else { + return nil, err + } } upgradeBytes = bytes @@ -107,7 +111,7 @@ func BytesToUpgradeConfiguration(b []byte) (*kubeadmapi.UpgradeConfiguration, er return nil, err } - return documentMapToUpgradeConfiguration(gvkmap, false) + return documentMapToUpgradeConfiguration(gvkmap, false, false, false) } // LoadOrDefaultUpgradeConfiguration takes a path to a config file and a versioned configuration that can serve as the default config