mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
kubeadm: fix panic when no UpgradeConfiguration was found in the config file
This commit is contained in:
parent
6476cf7cc9
commit
475334f995
@ -492,13 +492,3 @@ func defaultEmptyMigrateMutators() migrateMutators {
|
|||||||
|
|
||||||
return *mutators
|
return *mutators
|
||||||
}
|
}
|
||||||
|
|
||||||
// isKubeadmConfigPresent checks if a kubeadm config type is found in the provided document map
|
|
||||||
func isKubeadmConfigPresent(docmap kubeadmapi.DocumentMap) bool {
|
|
||||||
for gvk := range docmap {
|
|
||||||
if gvk.Group == kubeadmapi.GroupName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -972,52 +972,3 @@ func TestDefaultMigrateMutators(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsKubeadmConfigPresent(t *testing.T) {
|
|
||||||
var tcases = []struct {
|
|
||||||
name string
|
|
||||||
gvkmap kubeadmapi.DocumentMap
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: " Wrong Group value",
|
|
||||||
gvkmap: kubeadmapi.DocumentMap{
|
|
||||||
{Group: "foo.k8s.io", Version: "v1", Kind: "Foo"}: []byte(`kind: Foo`),
|
|
||||||
},
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Empty Group value",
|
|
||||||
gvkmap: kubeadmapi.DocumentMap{
|
|
||||||
{Group: "", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
|
|
||||||
},
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Nil value",
|
|
||||||
gvkmap: nil,
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Correct Group value 1",
|
|
||||||
gvkmap: kubeadmapi.DocumentMap{
|
|
||||||
{Group: "kubeadm.k8s.io", Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Correct Group value 2",
|
|
||||||
gvkmap: kubeadmapi.DocumentMap{
|
|
||||||
{Group: kubeadmapi.GroupName, Version: "v1", Kind: "Empty"}: []byte(`kind: Empty`),
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tcases {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if isKubeadmConfigPresent(tt.gvkmap) != tt.expected {
|
|
||||||
t.Error("unexpected result")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -22,28 +22,34 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
kubeproxyconfig "k8s.io/kube-proxy/config/v1alpha1"
|
|
||||||
kubeletconfig "k8s.io/kubelet/config/v1beta1"
|
|
||||||
|
|
||||||
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/v1beta4"
|
kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
|
"k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
|
||||||
)
|
)
|
||||||
|
|
||||||
var componentCfgGV = sets.New(kubeproxyconfig.GroupName, kubeletconfig.GroupName)
|
|
||||||
|
|
||||||
// documentMapToUpgradeConfiguration takes a map between GVKs and YAML documents (as returned by SplitYAMLDocuments),
|
// documentMapToUpgradeConfiguration takes a map between GVKs and YAML documents (as returned by SplitYAMLDocuments),
|
||||||
// finds a UpgradeConfiguration, decodes it, dynamically defaults it and then validates it prior to return.
|
// 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 bool) (*kubeadmapi.UpgradeConfiguration, error) {
|
||||||
var internalcfg *kubeadmapi.UpgradeConfiguration
|
upgradeBytes := []byte{}
|
||||||
|
|
||||||
for gvk, bytes := range gvkmap {
|
for gvk, bytes := range gvkmap {
|
||||||
|
if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvk) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvk) || componentconfigs.Scheme.IsGroupRegistered(gvk.Group) {
|
||||||
|
klog.Warningf("[config] WARNING: YAML document with GroupVersionKind %v is deprecated for upgrade, please use config file with kind of UpgradeConfiguration instead \n", gvk)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if gvk.Kind != constants.UpgradeConfigurationKind {
|
||||||
|
klog.Warningf("[config] WARNING: Ignored YAML document with GroupVersionKind %v\n", gvk)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// check if this version is supported and possibly not deprecated
|
// check if this version is supported and possibly not deprecated
|
||||||
if err := validateSupportedVersion(gvk, allowDeprecated, true); err != nil {
|
if err := validateSupportedVersion(gvk, allowDeprecated, true); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -54,37 +60,19 @@ func documentMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap, allowDepre
|
|||||||
klog.Warning(err.Error())
|
klog.Warning(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvk) || kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvk) {
|
upgradeBytes = bytes
|
||||||
klog.Warningf("[config] WARNING: YAML document with GroupVersionKind %v is deprecated for upgrade, please use config file with kind of UpgradeConfiguration instead \n", gvk)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if kubeadmutil.GroupVersionKindsHasUpgradeConfiguration(gvk) {
|
|
||||||
// Set internalcfg to an empty struct value the deserializer will populate
|
|
||||||
internalcfg = &kubeadmapi.UpgradeConfiguration{}
|
|
||||||
// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
|
|
||||||
// right external version, defaulted, and converted into the internal version.
|
|
||||||
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), bytes, internalcfg); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the group is neither a kubeadm core type or of a supported component config group, we dump a warning about it being ignored
|
|
||||||
if !componentconfigs.Scheme.IsGroupRegistered(gvk.Group) {
|
|
||||||
klog.Warningf("[config] WARNING: Ignored YAML document with GroupVersionKind %v\n", gvk)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If UpgradeConfiguration wasn't given, default it by creating an external struct instance, default it and convert into the internal type
|
if len(upgradeBytes) == 0 {
|
||||||
if internalcfg == nil {
|
return nil, errors.Errorf("no %s found in the supplied config", constants.UpgradeConfigurationKind)
|
||||||
extinitcfg := &kubeadmapiv1.UpgradeConfiguration{}
|
}
|
||||||
kubeadmscheme.Scheme.Default(extinitcfg)
|
|
||||||
// Set upgradeCfg to an empty struct value the deserializer will populate
|
// Set internalcfg to an empty struct value the deserializer will populate
|
||||||
internalcfg = &kubeadmapi.UpgradeConfiguration{}
|
internalcfg := &kubeadmapi.UpgradeConfiguration{}
|
||||||
if err := kubeadmscheme.Scheme.Convert(extinitcfg, internalcfg, nil); err != nil {
|
// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
|
||||||
return nil, err
|
// right external version, defaulted, and converted into the internal version.
|
||||||
}
|
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), upgradeBytes, internalcfg); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates cfg
|
// Validates cfg
|
||||||
@ -96,9 +84,6 @@ func documentMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap, allowDepre
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DocMapToUpgradeConfiguration converts documentMap to an internal, defaulted and validated UpgradeConfiguration object.
|
// DocMapToUpgradeConfiguration converts documentMap to an internal, defaulted and validated UpgradeConfiguration object.
|
||||||
// The map may contain many different YAML documents. These YAML documents are parsed one-by-one
|
|
||||||
// and well-known ComponentConfig GroupVersionKinds are stored inside of the internal UpgradeConfiguration struct.
|
|
||||||
// The resulting UpgradeConfiguration is then dynamically defaulted and validated prior to return.
|
|
||||||
func DocMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap) (*kubeadmapi.UpgradeConfiguration, error) {
|
func DocMapToUpgradeConfiguration(gvkmap kubeadmapi.DocumentMap) (*kubeadmapi.UpgradeConfiguration, error) {
|
||||||
return documentMapToUpgradeConfiguration(gvkmap, false)
|
return documentMapToUpgradeConfiguration(gvkmap, false)
|
||||||
}
|
}
|
||||||
@ -123,18 +108,8 @@ func LoadUpgradeConfigurationFromFile(cfgPath string, _ LoadOrDefaultConfigurati
|
|||||||
// Convert documentMap to internal UpgradeConfiguration, InitConfiguration and ClusterConfiguration from config file will be ignored.
|
// Convert documentMap to internal UpgradeConfiguration, InitConfiguration and ClusterConfiguration from config file will be ignored.
|
||||||
// Upgrade should respect the cluster configuration from the existing cluster, re-configure the cluster with a InitConfiguration and
|
// Upgrade should respect the cluster configuration from the existing cluster, re-configure the cluster with a InitConfiguration and
|
||||||
// ClusterConfiguration from the config file is not allowed for upgrade.
|
// ClusterConfiguration from the config file is not allowed for upgrade.
|
||||||
if isKubeadmConfigPresent(docmap) {
|
if upgradeCfg, err = DocMapToUpgradeConfiguration(docmap); err != nil {
|
||||||
if upgradeCfg, err = DocMapToUpgradeConfiguration(docmap); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check is there any component configs defined in the config file.
|
|
||||||
for gvk := range docmap {
|
|
||||||
if componentCfgGV.Has(gvk.Group) {
|
|
||||||
klog.Warningf("[config] WARNING: YAML document with Component Configs %v is deprecated for upgrade and will be ignored \n", gvk.Group)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return upgradeCfg, nil
|
return upgradeCfg, nil
|
||||||
|
@ -38,9 +38,10 @@ import (
|
|||||||
|
|
||||||
func TestDocMapToUpgradeConfiguration(t *testing.T) {
|
func TestDocMapToUpgradeConfiguration(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
cfg kubeadmapiv1.UpgradeConfiguration
|
cfg interface{}
|
||||||
expectedCfg kubeadmapi.UpgradeConfiguration
|
expectedCfg kubeadmapi.UpgradeConfiguration
|
||||||
|
expectedError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "default config is set correctly",
|
name: "default config is set correctly",
|
||||||
@ -94,6 +95,16 @@ func TestDocMapToUpgradeConfiguration(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "no UpgradeConfiguration found",
|
||||||
|
cfg: kubeadmapiv1.InitConfiguration{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: kubeadmapiv1.SchemeGroupVersion.String(),
|
||||||
|
Kind: constants.InitConfigurationKind,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
@ -107,11 +118,13 @@ func TestDocMapToUpgradeConfiguration(t *testing.T) {
|
|||||||
t.Fatalf("Unexpect error of SplitYAMLDocuments: %v", err)
|
t.Fatalf("Unexpect error of SplitYAMLDocuments: %v", err)
|
||||||
}
|
}
|
||||||
cfg, err := DocMapToUpgradeConfiguration(docmap)
|
cfg, err := DocMapToUpgradeConfiguration(docmap)
|
||||||
if err != nil {
|
if (err != nil) != tc.expectedError {
|
||||||
t.Fatalf("unexpected error of DocMapToUpgradeConfiguration: %v\nconfig: %s", err, string(b))
|
t.Fatalf("failed DocMapToUpgradeConfiguration:\n\texpected error: %t\n\t actual error: %v", tc.expectedError, err)
|
||||||
}
|
}
|
||||||
if diff := cmp.Diff(*cfg, tc.expectedCfg, cmpopts.IgnoreFields(kubeadmapi.UpgradeConfiguration{}, "Timeouts")); diff != "" {
|
if err == nil {
|
||||||
t.Fatalf("DocMapToUpgradeConfiguration returned unexpected diff (-want,+got):\n%s", diff)
|
if diff := cmp.Diff(*cfg, tc.expectedCfg, cmpopts.IgnoreFields(kubeadmapi.UpgradeConfiguration{}, "Timeouts")); diff != "" {
|
||||||
|
t.Fatalf("DocMapToUpgradeConfiguration returned unexpected diff (-want,+got):\n%s", diff)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user