Merge pull request #118866 from neolit123/1.28-add-v1beta4-to-scheme

kubeadm: add v1beta4 to scheme; add --allow-experimental-api flag
This commit is contained in:
Kubernetes Prow Robot 2023-06-27 08:56:44 -07:00 committed by GitHub
commit 1c32c3bd9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 21 deletions

View File

@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
) )
// Scheme is the runtime.Scheme to which all kubeadm api types are registered. // Scheme is the runtime.Scheme to which all kubeadm api types are registered.
@ -42,5 +43,8 @@ func init() {
func AddToScheme(scheme *runtime.Scheme) { func AddToScheme(scheme *runtime.Scheme) {
utilruntime.Must(kubeadm.AddToScheme(scheme)) utilruntime.Must(kubeadm.AddToScheme(scheme))
utilruntime.Must(v1beta3.AddToScheme(scheme)) utilruntime.Must(v1beta3.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(v1beta3.SchemeGroupVersion)) utilruntime.Must(v1beta4.AddToScheme(scheme))
// TODO: https://github.com/kubernetes/kubeadm/issues/2890
// make v1beta4 highest priority
utilruntime.Must(scheme.SetVersionPriority(v1beta3.SchemeGroupVersion, v1beta4.SchemeGroupVersion))
} }

View File

@ -225,6 +225,8 @@ func getDefaultNodeConfigBytes() ([]byte, error) {
// newCmdConfigMigrate returns cobra.Command for "kubeadm config migrate" command // newCmdConfigMigrate returns cobra.Command for "kubeadm config migrate" command
func newCmdConfigMigrate(out io.Writer) *cobra.Command { func newCmdConfigMigrate(out io.Writer) *cobra.Command {
var oldCfgPath, newCfgPath string var oldCfgPath, newCfgPath string
var allowExperimental bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "migrate", Use: "migrate",
Short: "Read an older version of the kubeadm configuration API types from a file, and output the similar config object for the newer version", Short: "Read an older version of the kubeadm configuration API types from a file, and output the similar config object for the newer version",
@ -252,7 +254,7 @@ func newCmdConfigMigrate(out io.Writer) *cobra.Command {
return err return err
} }
outputBytes, err := configutil.MigrateOldConfig(oldCfgBytes) outputBytes, err := configutil.MigrateOldConfig(oldCfgBytes, allowExperimental)
if err != nil { if err != nil {
return err return err
} }
@ -270,12 +272,14 @@ func newCmdConfigMigrate(out io.Writer) *cobra.Command {
} }
cmd.Flags().StringVar(&oldCfgPath, "old-config", "", "Path to the kubeadm config file that is using an old API version and should be converted. This flag is mandatory.") cmd.Flags().StringVar(&oldCfgPath, "old-config", "", "Path to the kubeadm config file that is using an old API version and should be converted. This flag is mandatory.")
cmd.Flags().StringVar(&newCfgPath, "new-config", "", "Path to the resulting equivalent kubeadm config file using the new API version. Optional, if not specified output will be sent to STDOUT.") cmd.Flags().StringVar(&newCfgPath, "new-config", "", "Path to the resulting equivalent kubeadm config file using the new API version. Optional, if not specified output will be sent to STDOUT.")
cmd.Flags().BoolVar(&allowExperimental, options.AllowExperimentalAPI, false, "Allow migration to experimental, unreleased APIs.")
return cmd return cmd
} }
// newCmdConfigValidate returns cobra.Command for the "kubeadm config validate" command // newCmdConfigValidate returns cobra.Command for the "kubeadm config validate" command
func newCmdConfigValidate(out io.Writer) *cobra.Command { func newCmdConfigValidate(out io.Writer) *cobra.Command {
var cfgPath string var cfgPath string
var allowExperimental bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "validate", Use: "validate",
@ -300,7 +304,7 @@ func newCmdConfigValidate(out io.Writer) *cobra.Command {
return err return err
} }
if err := configutil.ValidateConfig(cfgBytes); err != nil { if err := configutil.ValidateConfig(cfgBytes, allowExperimental); err != nil {
return err return err
} }
fmt.Fprintln(out, "ok") fmt.Fprintln(out, "ok")
@ -310,6 +314,7 @@ func newCmdConfigValidate(out io.Writer) *cobra.Command {
Args: cobra.NoArgs, Args: cobra.NoArgs,
} }
options.AddConfigFlag(cmd.Flags(), &cfgPath) options.AddConfigFlag(cmd.Flags(), &cfgPath)
cmd.Flags().BoolVar(&allowExperimental, options.AllowExperimentalAPI, false, "Allow validation of experimental, unreleased APIs.")
return cmd return cmd
} }

View File

@ -142,4 +142,7 @@ const (
// CleanupTmpDir flag indicates whether reset will cleanup the tmp dir // CleanupTmpDir flag indicates whether reset will cleanup the tmp dir
CleanupTmpDir = "cleanup-tmp-dir" CleanupTmpDir = "cleanup-tmp-dir"
// AllowExperimentalAPI flag can be used to allow experimental / work in progress APIs
AllowExperimentalAPI = "allow-experimental-api"
) )

View File

@ -37,6 +37,7 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme" kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs" "k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
"k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
@ -54,7 +55,7 @@ func MarshalKubeadmConfigObject(obj runtime.Object) ([]byte, error) {
// validateSupportedVersion checks if the supplied GroupVersion is not on the lists of old unsupported or deprecated GVs. // validateSupportedVersion checks if the supplied GroupVersion is not on the lists of old unsupported or deprecated GVs.
// If it is, an error is returned. // If it is, an error is returned.
func validateSupportedVersion(gv schema.GroupVersion, allowDeprecated bool) error { func validateSupportedVersion(gv schema.GroupVersion, allowDeprecated, allowExperimental bool) error {
// The support matrix will look something like this now and in the future: // The support matrix will look something like this now and in the future:
// v1.10 and earlier: v1alpha1 // v1.10 and earlier: v1alpha1
// v1.11: v1alpha1 read-only, writes only v1alpha2 config // v1.11: v1alpha1 read-only, writes only v1alpha2 config
@ -72,6 +73,13 @@ func validateSupportedVersion(gv schema.GroupVersion, allowDeprecated bool) erro
"kubeadm.k8s.io/v1beta2": "v1.22", "kubeadm.k8s.io/v1beta2": "v1.22",
} }
// v1.28: v1beta4 is released as experimental
experimentalAPIVersions := map[string]string{
// TODO: https://github.com/kubernetes/kubeadm/issues/2890
// remove this from experimental once v1beta4 is released
"kubeadm.k8s.io/v1beta4": "v1.28",
}
// Deprecated API versions are supported by us, but can only be used for migration. // Deprecated API versions are supported by us, but can only be used for migration.
deprecatedAPIVersions := map[string]struct{}{} deprecatedAPIVersions := map[string]struct{}{}
@ -85,6 +93,10 @@ func validateSupportedVersion(gv schema.GroupVersion, allowDeprecated bool) erro
klog.Warningf("your configuration file uses a deprecated API spec: %q. Please use 'kubeadm config migrate --old-config old.yaml --new-config new.yaml', which will write the new, similar spec using a newer API version.", gv) klog.Warningf("your configuration file uses a deprecated API spec: %q. Please use 'kubeadm config migrate --old-config old.yaml --new-config new.yaml', which will write the new, similar spec using a newer API version.", gv)
} }
if _, present := experimentalAPIVersions[gvString]; present && !allowExperimental {
return errors.Errorf("experimental API spec: %q is not allowed. You can use the --%s flag if the command supports it.", gv, options.AllowExperimentalAPI)
}
return nil return nil
} }
@ -205,7 +217,7 @@ func validateKnownGVKs(gvks []schema.GroupVersionKind) error {
// Skip legacy known GVs so that they don't return errors. // Skip legacy known GVs so that they don't return errors.
// This makes the function return errors only for GVs that where never known. // This makes the function return errors only for GVs that where never known.
if err := validateSupportedVersion(gvk.GroupVersion(), true); err != nil { if err := validateSupportedVersion(gvk.GroupVersion(), true, true); err != nil {
continue continue
} }
@ -229,7 +241,7 @@ func validateKnownGVKs(gvks []schema.GroupVersionKind) error {
// MigrateOldConfig migrates an old configuration from a byte slice into a new one (returned again as a byte slice). // MigrateOldConfig migrates an old configuration from a byte slice into a new one (returned again as a byte slice).
// Only kubeadm kinds are migrated. // Only kubeadm kinds are migrated.
func MigrateOldConfig(oldConfig []byte) ([]byte, error) { func MigrateOldConfig(oldConfig []byte, allowExperimental bool) ([]byte, error) {
newConfig := [][]byte{} newConfig := [][]byte{}
gvkmap, err := kubeadmutil.SplitYAMLDocuments(oldConfig) gvkmap, err := kubeadmutil.SplitYAMLDocuments(oldConfig)
@ -248,7 +260,7 @@ func MigrateOldConfig(oldConfig []byte) ([]byte, error) {
// Migrate InitConfiguration and ClusterConfiguration if there are any in the config // Migrate InitConfiguration and ClusterConfiguration if there are any in the config
if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvks...) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvks...) { if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvks...) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvks...) {
o, err := documentMapToInitConfiguration(gvkmap, true, true) o, err := documentMapToInitConfiguration(gvkmap, true, allowExperimental, true)
if err != nil { if err != nil {
return []byte{}, err return []byte{}, err
} }
@ -261,7 +273,7 @@ func MigrateOldConfig(oldConfig []byte) ([]byte, error) {
// Migrate JoinConfiguration if there is any // Migrate JoinConfiguration if there is any
if kubeadmutil.GroupVersionKindsHasJoinConfiguration(gvks...) { if kubeadmutil.GroupVersionKindsHasJoinConfiguration(gvks...) {
o, err := documentMapToJoinConfiguration(gvkmap, true, true) o, err := documentMapToJoinConfiguration(gvkmap, true, allowExperimental, true)
if err != nil { if err != nil {
return []byte{}, err return []byte{}, err
} }
@ -277,7 +289,7 @@ func MigrateOldConfig(oldConfig []byte) ([]byte, error) {
// ValidateConfig takes a byte slice containing a kubeadm configuration and performs conversion // ValidateConfig takes a byte slice containing a kubeadm configuration and performs conversion
// to internal types and validation. // to internal types and validation.
func ValidateConfig(oldConfig []byte) error { func ValidateConfig(oldConfig []byte, allowExperimental bool) error {
gvkmap, err := kubeadmutil.SplitYAMLDocuments(oldConfig) gvkmap, err := kubeadmutil.SplitYAMLDocuments(oldConfig)
if err != nil { if err != nil {
return err return err
@ -294,14 +306,14 @@ func ValidateConfig(oldConfig []byte) error {
// Validate InitConfiguration and ClusterConfiguration if there are any in the config // Validate InitConfiguration and ClusterConfiguration if there are any in the config
if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvks...) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvks...) { if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvks...) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvks...) {
if _, err := documentMapToInitConfiguration(gvkmap, true, true); err != nil { if _, err := documentMapToInitConfiguration(gvkmap, true, allowExperimental, true); err != nil {
return err return err
} }
} }
// Validate JoinConfiguration if there is any // Validate JoinConfiguration if there is any
if kubeadmutil.GroupVersionKindsHasJoinConfiguration(gvks...) { if kubeadmutil.GroupVersionKindsHasJoinConfiguration(gvks...) {
if _, err := documentMapToJoinConfiguration(gvkmap, true, true); err != nil { if _, err := documentMapToJoinConfiguration(gvkmap, true, allowExperimental, true); err != nil {
return err return err
} }
} }

View File

@ -36,6 +36,7 @@ func TestValidateSupportedVersion(t *testing.T) {
tests := []struct { tests := []struct {
gv schema.GroupVersion gv schema.GroupVersion
allowDeprecated bool allowDeprecated bool
allowExperimental bool
expectedErr bool expectedErr bool
}{ }{
{ {
@ -85,11 +86,25 @@ func TestValidateSupportedVersion(t *testing.T) {
Version: "v1", Version: "v1",
}, },
}, },
{
gv: schema.GroupVersion{
Group: KubeadmGroupName,
Version: "v1beta4",
},
allowExperimental: true,
},
{
gv: schema.GroupVersion{
Group: KubeadmGroupName,
Version: "v1beta4",
},
expectedErr: true,
},
} }
for _, rt := range tests { for _, rt := range tests {
t.Run(fmt.Sprintf("%s/allowDeprecated:%t", rt.gv, rt.allowDeprecated), func(t *testing.T) { t.Run(fmt.Sprintf("%s/allowDeprecated:%t", rt.gv, rt.allowDeprecated), func(t *testing.T) {
err := validateSupportedVersion(rt.gv, rt.allowDeprecated) err := validateSupportedVersion(rt.gv, rt.allowDeprecated, rt.allowExperimental)
if rt.expectedErr && err == nil { if rt.expectedErr && err == nil {
t.Error("unexpected success") t.Error("unexpected success")
} else if !rt.expectedErr && err != nil { } else if !rt.expectedErr && err != nil {

View File

@ -287,17 +287,17 @@ func BytesToInitConfiguration(b []byte) (*kubeadmapi.InitConfiguration, error) {
return nil, err return nil, err
} }
return documentMapToInitConfiguration(gvkmap, false, false) return documentMapToInitConfiguration(gvkmap, false, false, false)
} }
// documentMapToInitConfiguration converts a map of GVKs and YAML documents to defaulted and validated configuration object. // documentMapToInitConfiguration converts a map of GVKs and YAML documents to defaulted and validated configuration object.
func documentMapToInitConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated, strictErrors bool) (*kubeadmapi.InitConfiguration, error) { func documentMapToInitConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated, allowExperimental, strictErrors bool) (*kubeadmapi.InitConfiguration, error) {
var initcfg *kubeadmapi.InitConfiguration var initcfg *kubeadmapi.InitConfiguration
var clustercfg *kubeadmapi.ClusterConfiguration var clustercfg *kubeadmapi.ClusterConfiguration
for gvk, fileContent := range gvkmap { for gvk, fileContent := range gvkmap {
// first, check if this GVK is supported and possibly not deprecated // first, check if this GVK is supported and possibly not deprecated
if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated); err != nil { if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated, allowExperimental); err != nil {
return nil, err return nil, err
} }

View File

@ -85,12 +85,12 @@ func LoadJoinConfigurationFromFile(cfgPath string) (*kubeadmapi.JoinConfiguratio
return nil, err return nil, err
} }
return documentMapToJoinConfiguration(gvkmap, false, false) return documentMapToJoinConfiguration(gvkmap, false, false, false)
} }
// documentMapToJoinConfiguration takes a map between GVKs and YAML documents (as returned by SplitYAMLDocuments), // documentMapToJoinConfiguration takes a map between GVKs and YAML documents (as returned by SplitYAMLDocuments),
// finds a JoinConfiguration, decodes it, dynamically defaults it and then validates it prior to return. // finds a JoinConfiguration, decodes it, dynamically defaults it and then validates it prior to return.
func documentMapToJoinConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated, strictErrors bool) (*kubeadmapi.JoinConfiguration, error) { func documentMapToJoinConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated, allowExperimental, strictErrors bool) (*kubeadmapi.JoinConfiguration, error) {
joinBytes := []byte{} joinBytes := []byte{}
for gvk, bytes := range gvkmap { for gvk, bytes := range gvkmap {
// not interested in anything other than JoinConfiguration // not interested in anything other than JoinConfiguration
@ -99,7 +99,7 @@ func documentMapToJoinConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecat
} }
// check if this version is supported and possibly not deprecated // check if this version is supported and possibly not deprecated
if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated); err != nil { if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated, allowExperimental); err != nil {
return nil, err return nil, err
} }