Skip to content
Permalink
Browse files

Merge pull request #74025 from rosti/deprecated-configs

kubeadm: Don't load deprecated configs
  • Loading branch information...
k8s-ci-robot committed Feb 19, 2019
2 parents d61e878 + f64baf7 commit 8d69dc630ba66d05ad95146583a7482ed1eb3f82
@@ -1,3 +1,3 @@
apiVersion: kubeadm.k8s.io/v1alpha3
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: 1.12.0
kubernetesVersion: 1.13.0
@@ -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
}
@@ -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 {
@@ -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
}

@@ -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,23 +160,16 @@ 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",
in: masterV1beta1YAMLAbstracted,
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,
@@ -84,21 +84,21 @@ 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
if gvk.Kind != constants.JoinConfigurationKind {
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
}

@@ -46,23 +46,16 @@ 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",
in: nodeV1beta1YAML,
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,
@@ -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
@@ -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",

0 comments on commit 8d69dc6

Please sign in to comment.
You can’t perform that action at this time.