diff --git a/cmd/kubeadm/app/cmd/upgrade/testdata/diff_master_config.yaml b/cmd/kubeadm/app/cmd/upgrade/testdata/diff_master_config.yaml index c9ae6e2bd3..7fc1180cfc 100644 --- a/cmd/kubeadm/app/cmd/upgrade/testdata/diff_master_config.yaml +++ b/cmd/kubeadm/app/cmd/upgrade/testdata/diff_master_config.yaml @@ -1,3 +1,3 @@ -apiVersion: kubeadm.k8s.io/v1alpha3 +apiVersion: kubeadm.k8s.io/v1beta1 kind: ClusterConfiguration -kubernetesVersion: 1.12.0 +kubernetesVersion: 1.13.0 diff --git a/cmd/kubeadm/app/util/config/common.go b/cmd/kubeadm/app/util/config/common.go index c782f6e7e0..a153d25258 100644 --- a/cmd/kubeadm/app/util/config/common.go +++ b/cmd/kubeadm/app/util/config/common.go @@ -48,20 +48,35 @@ func MarshalKubeadmConfigObject(obj runtime.Object) ([]byte, error) { } } -// ValidateSupportedVersion checks if a supplied GroupVersion is not on the list of unsupported GVs. If it is, an error is returned. -func ValidateSupportedVersion(gv schema.GroupVersion) error { +// validateSupportedVersion checks if the supplied GroupVersion is not on the lists of old unsupported or deprecated GVs. +// If it is, an error is returned. +func validateSupportedVersion(gv schema.GroupVersion, allowDeprecated bool) error { // The support matrix will look something like this now and in the future: // v1.10 and earlier: v1alpha1 // v1.11: v1alpha1 read-only, writes only v1alpha2 config - // v1.12: v1alpha2 read-only, writes only v1alpha3 config. Warns if the user tries to use v1alpha1 - // v1.13: v1alpha3 read-only, writes only v1beta1 config. Warns if the user tries to use v1alpha1 or v1alpha2 + // v1.12: v1alpha2 read-only, writes only v1alpha3 config. Errors if the user tries to use v1alpha1 + // v1.13: v1alpha3 read-only, writes only v1beta1 config. Errors if the user tries to use v1alpha1 or v1alpha2 + // v1.14: v1alpha3 convert only, writes only v1beta1 config. Errors if the user tries to use v1alpha1 or v1alpha2 oldKnownAPIVersions := map[string]string{ "kubeadm.k8s.io/v1alpha1": "v1.11", "kubeadm.k8s.io/v1alpha2": "v1.12", } - if useKubeadmVersion := oldKnownAPIVersions[gv.String()]; useKubeadmVersion != "" { + + // Deprecated API versions are supported by us, but can only be used for migration. + deprecatedAPIVersions := map[string]struct{}{ + "kubeadm.k8s.io/v1alpha3": {}, // Can be migrated with kubeadm 1.13+ + } + + gvString := gv.String() + + if useKubeadmVersion := oldKnownAPIVersions[gvString]; useKubeadmVersion != "" { return errors.Errorf("your configuration file uses an old API spec: %q. Please use kubeadm %s instead and run 'kubeadm config migrate --old-config old.yaml --new-config new.yaml', which will write the new, similar spec using a newer API version.", gv.String(), useKubeadmVersion) } + + if _, present := deprecatedAPIVersions[gvString]; present && !allowDeprecated { + return errors.Errorf("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.String()) + } + return nil } @@ -154,7 +169,7 @@ func MigrateOldConfig(oldConfig []byte) ([]byte, error) { // Migrate InitConfiguration and ClusterConfiguration if there are any in the config if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvks...) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvks...) { - o, err := documentMapToInitConfiguration(gvkmap) + o, err := documentMapToInitConfiguration(gvkmap, true) if err != nil { return []byte{}, err } @@ -167,7 +182,7 @@ func MigrateOldConfig(oldConfig []byte) ([]byte, error) { // Migrate JoinConfiguration if there is any if kubeadmutil.GroupVersionKindsHasJoinConfiguration(gvks...) { - o, err := documentMapToJoinConfiguration(gvkmap) + o, err := documentMapToJoinConfiguration(gvkmap, true) if err != nil { return []byte{}, err } diff --git a/cmd/kubeadm/app/util/config/common_test.go b/cmd/kubeadm/app/util/config/common_test.go index c2cff8b366..501a8d602b 100644 --- a/cmd/kubeadm/app/util/config/common_test.go +++ b/cmd/kubeadm/app/util/config/common_test.go @@ -17,6 +17,7 @@ limitations under the License. package config import ( + "fmt" "testing" "github.com/lithammer/dedent" @@ -27,12 +28,13 @@ import ( kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" ) -func TestValidateSupportedVersion(t *testing.T) { - const KubeadmGroupName = "kubeadm.k8s.io" +const KubeadmGroupName = "kubeadm.k8s.io" +func TestValidateSupportedVersion(t *testing.T) { tests := []struct { - gv schema.GroupVersion - expectedErr bool + gv schema.GroupVersion + allowDeprecated bool + expectedErr bool }{ { gv: schema.GroupVersion{ @@ -53,6 +55,14 @@ func TestValidateSupportedVersion(t *testing.T) { Group: KubeadmGroupName, Version: "v1alpha3", }, + expectedErr: true, + }, + { + gv: schema.GroupVersion{ + Group: KubeadmGroupName, + Version: "v1alpha3", + }, + allowDeprecated: true, }, { gv: schema.GroupVersion{ @@ -69,8 +79,8 @@ func TestValidateSupportedVersion(t *testing.T) { } for _, rt := range tests { - t.Run(rt.gv.String(), func(t *testing.T) { - err := ValidateSupportedVersion(rt.gv) + t.Run(fmt.Sprintf("%s/allowDeprecated:%t", rt.gv, rt.allowDeprecated), func(t *testing.T) { + err := validateSupportedVersion(rt.gv, rt.allowDeprecated) if rt.expectedErr && err == nil { t.Error("unexpected success") } else if !rt.expectedErr && err != nil { diff --git a/cmd/kubeadm/app/util/config/initconfiguration.go b/cmd/kubeadm/app/util/config/initconfiguration.go index e21ecac017..035015d624 100644 --- a/cmd/kubeadm/app/util/config/initconfiguration.go +++ b/cmd/kubeadm/app/util/config/initconfiguration.go @@ -190,11 +190,7 @@ func LoadInitConfigurationFromFile(cfgPath string) (*kubeadmapi.InitConfiguratio return nil, errors.Wrapf(err, "unable to read config from %q ", cfgPath) } - internalcfg, err := BytesToInitConfiguration(b) - if err != nil { - return nil, err - } - return internalcfg, nil + return BytesToInitConfiguration(b) } // LoadOrDefaultInitConfiguration takes a path to a config file and a versioned configuration that can serve as the default config @@ -222,18 +218,18 @@ func BytesToInitConfiguration(b []byte) (*kubeadmapi.InitConfiguration, error) { return nil, err } - return documentMapToInitConfiguration(gvkmap) + return documentMapToInitConfiguration(gvkmap, false) } // documentMapToInitConfiguration converts a map of GVKs and YAML documents to defaulted and validated configuration object. -func documentMapToInitConfiguration(gvkmap map[schema.GroupVersionKind][]byte) (*kubeadmapi.InitConfiguration, error) { +func documentMapToInitConfiguration(gvkmap map[schema.GroupVersionKind][]byte, allowDeprecated bool) (*kubeadmapi.InitConfiguration, error) { var initcfg *kubeadmapi.InitConfiguration var clustercfg *kubeadmapi.ClusterConfiguration decodedComponentConfigObjects := map[componentconfigs.RegistrationKind]runtime.Object{} for gvk, fileContent := range gvkmap { - // first, check if this GVK is supported one - if err := ValidateSupportedVersion(gvk.GroupVersion()); err != nil { + // first, check if this GVK is supported and possibly not deprecated + if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated); err != nil { return nil, err } diff --git a/cmd/kubeadm/app/util/config/initconfiguration_test.go b/cmd/kubeadm/app/util/config/initconfiguration_test.go index bd8a6e176f..cc11b97921 100644 --- a/cmd/kubeadm/app/util/config/initconfiguration_test.go +++ b/cmd/kubeadm/app/util/config/initconfiguration_test.go @@ -71,6 +71,7 @@ func TestLoadInitConfigurationFromFile(t *testing.T) { var tests = []struct { name string fileContents []byte + expectErr bool }{ { name: "v1beta1.partial1", @@ -92,10 +93,12 @@ func TestLoadInitConfigurationFromFile(t *testing.T) { { name: "v1alpha3.partial1", fileContents: cfgFiles["InitConfiguration_v1alpha3"], + expectErr: true, }, { name: "v1alpha3.partial2", fileContents: cfgFiles["ClusterConfiguration_v1alpha3"], + expectErr: true, }, { name: "v1alpha3.full", @@ -105,6 +108,7 @@ func TestLoadInitConfigurationFromFile(t *testing.T) { cfgFiles["Kube-proxy_componentconfig"], cfgFiles["Kubelet_componentconfig"], }, []byte(constants.YAMLDocumentSeparator)), + expectErr: true, }, } @@ -118,13 +122,19 @@ func TestLoadInitConfigurationFromFile(t *testing.T) { } obj, err := LoadInitConfigurationFromFile(cfgPath) - if err != nil { - t.Errorf("Error reading file: %v", err) - return - } + if rt.expectErr { + if err == nil { + t.Error("Unexpected success") + } + } else { + if err != nil { + t.Errorf("Error reading file: %v", err) + return + } - if obj == nil { - t.Errorf("Unexpected nil return value") + if obj == nil { + t.Errorf("Unexpected nil return value") + } } }) } @@ -150,10 +160,9 @@ func TestInitConfigurationMarshallingFromFile(t *testing.T) { // These tests are reading one file, loading it using LoadInitConfigurationFromFile that all of kubeadm is using for unmarshal of our API types, // and then marshals the internal object to the expected groupVersion { // v1alpha3 -> internal - name: "v1alpha3ToInternal", - in: masterV1alpha3YAMLAbstracted, - out: masterInternalYAMLAbstracted, - groupVersion: kubeadm.SchemeGroupVersion, + name: "v1alpha3IsDeprecated", + in: masterV1alpha3YAMLAbstracted, + expectedErr: true, }, { // v1beta1 -> internal name: "v1beta1ToInternal", @@ -161,12 +170,6 @@ func TestInitConfigurationMarshallingFromFile(t *testing.T) { out: masterInternalYAMLAbstracted, groupVersion: kubeadm.SchemeGroupVersion, }, - { // v1alpha3 -> internal -> v1beta1 - name: "v1alpha3Tov1beta1", - in: masterV1alpha3YAMLAbstracted, - out: masterV1beta1YAMLAbstracted, - groupVersion: kubeadmapiv1beta1.SchemeGroupVersion, - }, { // v1beta1 -> internal -> v1beta1 name: "v1beta1Tov1beta1", in: masterV1beta1YAMLAbstracted, @@ -181,7 +184,7 @@ func TestInitConfigurationMarshallingFromFile(t *testing.T) { out: masterDefaultedYAMLAbstracted, groupVersion: kubeadmapiv1beta1.SchemeGroupVersion, }, - { // v1alpha3 -> validation should fail + { // v1beta1 -> validation should fail name: "invalidYAMLShouldFail", in: masterInvalidYAML, expectedErr: true, diff --git a/cmd/kubeadm/app/util/config/joinconfiguration.go b/cmd/kubeadm/app/util/config/joinconfiguration.go index f328876d2a..9de0d1acd0 100644 --- a/cmd/kubeadm/app/util/config/joinconfiguration.go +++ b/cmd/kubeadm/app/util/config/joinconfiguration.go @@ -84,12 +84,12 @@ func LoadJoinConfigurationFromFile(cfgPath string) (*kubeadmapi.JoinConfiguratio return nil, err } - return documentMapToJoinConfiguration(gvkmap) + return documentMapToJoinConfiguration(gvkmap, false) } // 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. -func documentMapToJoinConfiguration(gvkmap map[schema.GroupVersionKind][]byte) (*kubeadmapi.JoinConfiguration, error) { +func documentMapToJoinConfiguration(gvkmap map[schema.GroupVersionKind][]byte, allowDeprecated bool) (*kubeadmapi.JoinConfiguration, error) { joinBytes := []byte{} for gvk, bytes := range gvkmap { // not interested in anything other than JoinConfiguration @@ -97,8 +97,8 @@ func documentMapToJoinConfiguration(gvkmap map[schema.GroupVersionKind][]byte) ( continue } - // check if this version is supported one - if err := ValidateSupportedVersion(gvk.GroupVersion()); err != nil { + // check if this version is supported and possibly not deprecated + if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated); err != nil { return nil, err } diff --git a/cmd/kubeadm/app/util/config/joinconfiguration_test.go b/cmd/kubeadm/app/util/config/joinconfiguration_test.go index 903d2a22ef..5fac3fa9c3 100644 --- a/cmd/kubeadm/app/util/config/joinconfiguration_test.go +++ b/cmd/kubeadm/app/util/config/joinconfiguration_test.go @@ -46,10 +46,9 @@ func TestLoadJoinConfigurationFromFile(t *testing.T) { // These tests are reading one file, loading it using LoadJoinConfigurationFromFile that all of kubeadm is using for unmarshal of our API types, // and then marshals the internal object to the expected groupVersion { // v1alpha3 -> internal - name: "v1alpha3ToInternal", - in: nodeV1alpha3YAML, - out: nodeInternalYAML, - groupVersion: kubeadm.SchemeGroupVersion, + name: "v1alpha3IsDeprecated", + in: nodeV1alpha3YAML, + expectedErr: true, }, { // v1beta1 -> internal name: "v1beta1ToInternal", @@ -57,12 +56,6 @@ func TestLoadJoinConfigurationFromFile(t *testing.T) { out: nodeInternalYAML, groupVersion: kubeadm.SchemeGroupVersion, }, - { // v1alpha3 -> internal -> v1beta1 - name: "v1alpha3Tov1beta1", - in: nodeV1alpha3YAML, - out: nodeV1beta1YAML, - groupVersion: kubeadmapiv1beta1.SchemeGroupVersion, - }, { // v1beta1 -> internal -> v1beta1 name: "v1beta1Tov1beta1", in: nodeV1beta1YAML, @@ -77,7 +70,7 @@ func TestLoadJoinConfigurationFromFile(t *testing.T) { out: nodeDefaultedYAML, groupVersion: kubeadmapiv1beta1.SchemeGroupVersion, }, - { // v1alpha3 -> validation should fail + { // v1beta1 -> validation should fail name: "invalidYAMLShouldFail", in: nodeInvalidYAML, expectedErr: true, diff --git a/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml b/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml index ff990c1a70..870a79e5be 100644 --- a/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml +++ b/cmd/kubeadm/app/util/config/testdata/defaulting/node/incomplete.yaml @@ -1,11 +1,11 @@ -apiVersion: kubeadm.k8s.io/v1alpha3 -discoveryToken: abcdef.0123456789abcdef -discoveryTokenAPIServers: -- kube-apiserver:6443 -discoveryTokenUnsafeSkipCAVerification: true +apiVersion: kubeadm.k8s.io/v1beta1 +discovery: + bootstrapToken: + apiServerEndpoint: kube-apiserver:6443 + token: abcdef.0123456789abcdef + unsafeSkipCAVerification: true + tlsBootstrapToken: abcdef.0123456789abcdef kind: JoinConfiguration nodeRegistration: criSocket: /var/run/dockershim.sock name: thegopher -tlsBootstrapToken: abcdef.0123456789abcdef -token: abcdef.0123456789abcdef diff --git a/cmd/kubeadm/test/cmd/init_test.go b/cmd/kubeadm/test/cmd/init_test.go index c96a21e3e5..68e30332d9 100644 --- a/cmd/kubeadm/test/cmd/init_test.go +++ b/cmd/kubeadm/test/cmd/init_test.go @@ -146,19 +146,19 @@ func TestCmdInitConfig(t *testing.T) { expected: false, }, { - name: "can't load v1alpha1 config", + name: "can't load old v1alpha1 config", args: "--config=testdata/init/v1alpha1.yaml", expected: false, }, { - name: "can't load v1alpha2 config", + name: "can't load old v1alpha2 config", args: "--config=testdata/init/v1alpha2.yaml", expected: false, }, { - name: "can load v1alpha3 config", + name: "can't load deprecated v1alpha3 config", args: "--config=testdata/init/v1alpha3.yaml", - expected: true, + expected: false, }, { name: "can load v1beta1 config",