kubeadm: statically default the "from cluster" InitConfiguration

During operations such as "upgrade", kubeadm fetches the
ClusterConfiguration object from the kubeadm ConfigMap.
However, due to requiring node specifics it wraps it in an
InitConfiguration object. The function responsible for that is:
  app/util/config#FetchInitConfigurationFromCluster().

A problem with this function (and sub-calls) is that it ignores
the static defaults applied from versioned types
(e.g. v1beta3/defaults.go) and only applies dynamic defaults for:
- API endpoints
- node registration
- etc...

The introduction of Init|JoinConfiguration.ImagePullPolicy now
has static defaulting of the NodeRegistration object with a default
policy of "PullIfNotPresent". Respect this defaulting by constructing
a defaulted internal InitConfiguration from
FetchInitConfigurationFromCluster() and only then apply the dynamic
defaults over it.

This fixes a bug where "kubeadm upgrade ..." fails when pulling images
due to an empty ("") ImagePullPolicy. We could assume that empty
string means default policy on runtime in:
cmd/kubeadm/app/preflight/checks.go#ImagePullCheck()

but that might actually not be the user intent during "init" and "join",
due to e.g. a typo. Similarly, we don't allow empty tokens
on runtime and error out.
This commit is contained in:
Lubomir I. Ivanov 2021-07-08 02:35:30 +03:00
parent e67979eaf6
commit 6cf3e36c37
2 changed files with 10 additions and 1 deletions

View File

@ -26,6 +26,7 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
@ -68,8 +69,13 @@ func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Inte
return nil, errors.Wrap(err, "failed to get config map")
}
// InitConfiguration is composed with data from different places
// Take an empty versioned InitConfiguration, statically default it and convert it to the internal type
versionedInitcfg := &kubeadmapiv1.InitConfiguration{}
kubeadmscheme.Scheme.Default(versionedInitcfg)
initcfg := &kubeadmapi.InitConfiguration{}
if err := kubeadmscheme.Scheme.Convert(versionedInitcfg, initcfg, nil); err != nil {
return nil, errors.Wrap(err, "could not prepare a defaulted InitConfiguration")
}
// gets ClusterConfiguration from kubeadm-config
clusterConfigurationData, ok := configMap.Data[constants.ClusterConfigurationConfigMapKey]

View File

@ -730,6 +730,9 @@ func TestGetInitConfigurationFromCluster(t *testing.T) {
if cfg.ClusterConfiguration.KubernetesVersion != k8sVersionString {
t.Errorf("invalid ClusterConfiguration.KubernetesVersion")
}
if cfg.NodeRegistration.ImagePullPolicy != kubeadmapiv1.DefaultImagePullPolicy {
t.Errorf("invalid cfg.NodeRegistration.ImagePullPolicy %v", cfg.NodeRegistration.ImagePullPolicy)
}
if !rt.newControlPlane && (cfg.LocalAPIEndpoint.AdvertiseAddress != "1.2.3.4" || cfg.LocalAPIEndpoint.BindPort != 1234) {
t.Errorf("invalid cfg.LocalAPIEndpoint: %v", cfg.LocalAPIEndpoint)
}