mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #110327 from neolit123/1.25-ga-unversioned-kubelet-config
kubeadm: graduate the UnversionedKubeletConfigMap FG to GA
This commit is contained in:
commit
9fad5c981a
@ -26,27 +26,17 @@ import (
|
|||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: cleanup after UnversionedKubeletConfigMap goes GA:
|
func testClusterCfg() *kubeadmapi.ClusterConfiguration {
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
func testClusterCfg(legacyKubeletConfigMap bool) *kubeadmapi.ClusterConfiguration {
|
|
||||||
if legacyKubeletConfigMap {
|
|
||||||
return &kubeadmapi.ClusterConfiguration{
|
|
||||||
KubernetesVersion: constants.CurrentKubernetesVersion.String(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &kubeadmapi.ClusterConfiguration{
|
return &kubeadmapi.ClusterConfiguration{
|
||||||
KubernetesVersion: constants.CurrentKubernetesVersion.String(),
|
KubernetesVersion: constants.CurrentKubernetesVersion.String(),
|
||||||
FeatureGates: map[string]bool{features.UnversionedKubeletConfigMap: true},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefault(t *testing.T) {
|
func TestDefault(t *testing.T) {
|
||||||
legacyKubeletConfigMap := false
|
clusterCfg := testClusterCfg()
|
||||||
clusterCfg := testClusterCfg(legacyKubeletConfigMap)
|
|
||||||
localAPIEndpoint := &kubeadmapi.APIEndpoint{}
|
localAPIEndpoint := &kubeadmapi.APIEndpoint{}
|
||||||
nodeRegOps := &kubeadmapi.NodeRegistrationOptions{}
|
nodeRegOps := &kubeadmapi.NodeRegistrationOptions{}
|
||||||
|
|
||||||
@ -66,11 +56,10 @@ func TestFromCluster(t *testing.T) {
|
|||||||
testKubeletConfigMap(`
|
testKubeletConfigMap(`
|
||||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
apiVersion: kubelet.config.k8s.io/v1beta1
|
||||||
kind: KubeletConfiguration
|
kind: KubeletConfiguration
|
||||||
`, false),
|
`),
|
||||||
}
|
}
|
||||||
client := clientsetfake.NewSimpleClientset(objects...)
|
client := clientsetfake.NewSimpleClientset(objects...)
|
||||||
legacyKubeletConfigMap := false
|
clusterCfg := testClusterCfg()
|
||||||
clusterCfg := testClusterCfg(legacyKubeletConfigMap)
|
|
||||||
|
|
||||||
if err := FetchFromCluster(clusterCfg, client); err != nil {
|
if err := FetchFromCluster(clusterCfg, client); err != nil {
|
||||||
t.Fatalf("FetchFromCluster failed: %v", err)
|
t.Fatalf("FetchFromCluster failed: %v", err)
|
||||||
@ -79,30 +68,6 @@ func TestFromCluster(t *testing.T) {
|
|||||||
if len(clusterCfg.ComponentConfigs) != len(objects) {
|
if len(clusterCfg.ComponentConfigs) != len(objects) {
|
||||||
t.Fatalf("mismatch between supplied and loaded type numbers:\n\tgot: %d\n\texpected: %d", len(clusterCfg.ComponentConfigs), len(objects))
|
t.Fatalf("mismatch between supplied and loaded type numbers:\n\tgot: %d\n\texpected: %d", len(clusterCfg.ComponentConfigs), len(objects))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cleanup the legacy case below after UnversionedKubeletConfigMap goes GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
objectsLegacyKubelet := []runtime.Object{
|
|
||||||
testKubeProxyConfigMap(`
|
|
||||||
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
|
||||||
kind: KubeProxyConfiguration
|
|
||||||
`),
|
|
||||||
testKubeletConfigMap(`
|
|
||||||
apiVersion: kubelet.config.k8s.io/v1beta1
|
|
||||||
kind: KubeletConfiguration
|
|
||||||
`, true),
|
|
||||||
}
|
|
||||||
clientLegacyKubelet := clientsetfake.NewSimpleClientset(objectsLegacyKubelet...)
|
|
||||||
legacyKubeletConfigMap = true
|
|
||||||
clusterCfgLegacyKubelet := testClusterCfg(legacyKubeletConfigMap)
|
|
||||||
|
|
||||||
if err := FetchFromCluster(clusterCfgLegacyKubelet, clientLegacyKubelet); err != nil {
|
|
||||||
t.Fatalf("FetchFromCluster failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(clusterCfgLegacyKubelet.ComponentConfigs) != len(objectsLegacyKubelet) {
|
|
||||||
t.Fatalf("mismatch between supplied and loaded type numbers:\n\tgot: %d\n\texpected: %d", len(clusterCfg.ComponentConfigs), len(objects))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchFromDocumentMap(t *testing.T) {
|
func TestFetchFromDocumentMap(t *testing.T) {
|
||||||
@ -118,8 +83,7 @@ func TestFetchFromDocumentMap(t *testing.T) {
|
|||||||
t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err)
|
t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
legacyKubeletConfigMap := false
|
clusterCfg := testClusterCfg()
|
||||||
clusterCfg := testClusterCfg(legacyKubeletConfigMap)
|
|
||||||
if err = FetchFromDocumentMap(clusterCfg, gvkmap); err != nil {
|
if err = FetchFromDocumentMap(clusterCfg, gvkmap); err != nil {
|
||||||
t.Fatalf("FetchFromDocumentMap failed: %v", err)
|
t.Fatalf("FetchFromDocumentMap failed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -361,8 +361,7 @@ func TestGeneratedConfigFromCluster(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := clientsetfake.NewSimpleClientset(configMap)
|
client := clientsetfake.NewSimpleClientset(configMap)
|
||||||
legacyKubeletConfigMap := true
|
cfg, err := clusterConfigHandler.FromCluster(client, testClusterCfg())
|
||||||
cfg, err := clusterConfigHandler.FromCluster(client, testClusterCfg(legacyKubeletConfigMap))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected failure of FromCluster: %v", err)
|
t.Fatalf("unexpected failure of FromCluster: %v", err)
|
||||||
}
|
}
|
||||||
@ -487,8 +486,7 @@ func TestLoadingFromCluster(t *testing.T) {
|
|||||||
testClusterConfigMap(in, false),
|
testClusterConfigMap(in, false),
|
||||||
)
|
)
|
||||||
|
|
||||||
legacyKubeletConfigMap := true
|
return clusterConfigHandler.FromCluster(client, testClusterCfg())
|
||||||
return clusterConfigHandler.FromCluster(client, testClusterCfg(legacyKubeletConfigMap))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,8 +579,7 @@ func TestFetchFromClusterWithLocalOverwrites(t *testing.T) {
|
|||||||
t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err)
|
t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
legacyKubeletConfigMap := true
|
clusterCfg := testClusterCfg()
|
||||||
clusterCfg := testClusterCfg(legacyKubeletConfigMap)
|
|
||||||
|
|
||||||
err = FetchFromClusterWithLocalOverwrites(clusterCfg, client, docmap)
|
err = FetchFromClusterWithLocalOverwrites(clusterCfg, client, docmap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -716,8 +713,7 @@ func TestGetVersionStates(t *testing.T) {
|
|||||||
t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err)
|
t.Fatalf("unexpected failure of SplitYAMLDocuments: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
legacyKubeletConfigMap := true
|
clusterCfg := testClusterCfg()
|
||||||
clusterCfg := testClusterCfg(legacyKubeletConfigMap)
|
|
||||||
|
|
||||||
got, err := GetVersionStates(clusterCfg, client, docmap)
|
got, err := GetVersionStates(clusterCfg, client, docmap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/version"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
kubeletconfig "k8s.io/kubelet/config/v1beta1"
|
kubeletconfig "k8s.io/kubelet/config/v1beta1"
|
||||||
@ -71,29 +70,12 @@ var kubeletHandler = handler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func kubeletConfigFromCluster(h *handler, clientset clientset.Interface, clusterCfg *kubeadmapi.ClusterConfiguration) (kubeadmapi.ComponentConfig, error) {
|
func kubeletConfigFromCluster(h *handler, clientset clientset.Interface, clusterCfg *kubeadmapi.ClusterConfiguration) (kubeadmapi.ComponentConfig, error) {
|
||||||
// Read the ConfigMap from the cluster based on what version the kubelet is
|
configMapName := constants.KubeletBaseConfigurationConfigMap
|
||||||
k8sVersion, err := version.ParseGeneric(clusterCfg.KubernetesVersion)
|
klog.V(1).Infof("attempting to download the KubeletConfiguration from ConfigMap %q", configMapName)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
// During the first "kubeadm upgrade apply" when the feature gate goes "true" by default and
|
|
||||||
// a preferred user value is missing in the ClusterConfiguration, "kubeadm upgrade apply" will try
|
|
||||||
// to fetch using the new format and that CM will not exist yet.
|
|
||||||
// Tollerate both the old a new format until UnversionedKubeletConfigMap goes GA and is locked.
|
|
||||||
// This makes it easier for the users and the code base (avoids changes in /cmd/upgrade/common.go#enforceRequirements).
|
|
||||||
configMapNameLegacy := constants.GetKubeletConfigMapName(k8sVersion, true)
|
|
||||||
configMapName := constants.GetKubeletConfigMapName(k8sVersion, false)
|
|
||||||
klog.V(1).Infof("attempting to download the KubeletConfiguration from the new format location (UnversionedKubeletConfigMap=true)")
|
|
||||||
cm, err := h.fromConfigMap(clientset, configMapName, constants.KubeletBaseConfigurationConfigMapKey, true)
|
cm, err := h.fromConfigMap(clientset, configMapName, constants.KubeletBaseConfigurationConfigMapKey, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(1).Infof("attempting to download the KubeletConfiguration from the DEPRECATED location (UnversionedKubeletConfigMap=false)")
|
return nil, errors.Wrapf(err, "could not download the kubelet configuration from ConfigMap %q",
|
||||||
cm, err = h.fromConfigMap(clientset, configMapNameLegacy, constants.KubeletBaseConfigurationConfigMapKey, true)
|
configMapName)
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "could not download the kubelet configuration from ConfigMap %q or %q",
|
|
||||||
configMapName, configMapNameLegacy)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return cm, nil
|
return cm, nil
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,10 @@ import (
|
|||||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: cleanup after UnversionedKubeletConfigMap goes GA:
|
func testKubeletConfigMap(contents string) *v1.ConfigMap {
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
func testKubeletConfigMap(contents string, legacyKubeletConfigMap bool) *v1.ConfigMap {
|
|
||||||
return &v1.ConfigMap{
|
return &v1.ConfigMap{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: constants.GetKubeletConfigMapName(constants.CurrentKubernetesVersion, legacyKubeletConfigMap),
|
Name: constants.KubeletBaseConfigurationConfigMap,
|
||||||
Namespace: metav1.NamespaceSystem,
|
Namespace: metav1.NamespaceSystem,
|
||||||
},
|
},
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
@ -285,16 +283,8 @@ func TestKubeletFromDocumentMap(t *testing.T) {
|
|||||||
func TestKubeletFromCluster(t *testing.T) {
|
func TestKubeletFromCluster(t *testing.T) {
|
||||||
runKubeletFromTest(t, func(_ schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) {
|
runKubeletFromTest(t, func(_ schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) {
|
||||||
client := clientsetfake.NewSimpleClientset(
|
client := clientsetfake.NewSimpleClientset(
|
||||||
testKubeletConfigMap(yaml, true),
|
testKubeletConfigMap(yaml),
|
||||||
)
|
)
|
||||||
legacyKubeletConfigMap := true
|
return kubeletHandler.FromCluster(client, testClusterCfg())
|
||||||
return kubeletHandler.FromCluster(client, testClusterCfg(legacyKubeletConfigMap))
|
|
||||||
})
|
|
||||||
runKubeletFromTest(t, func(_ schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) {
|
|
||||||
client := clientsetfake.NewSimpleClientset(
|
|
||||||
testKubeletConfigMap(yaml, false),
|
|
||||||
)
|
|
||||||
legacyKubeletConfigMap := false
|
|
||||||
return kubeletHandler.FromCluster(client, testClusterCfg(legacyKubeletConfigMap))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,6 @@ func TestKubeProxyFromCluster(t *testing.T) {
|
|||||||
testKubeProxyConfigMap(yaml),
|
testKubeProxyConfigMap(yaml),
|
||||||
)
|
)
|
||||||
|
|
||||||
legacyKubeletConfigMap := true
|
return kubeProxyHandler.FromCluster(client, testClusterCfg())
|
||||||
return kubeProxyHandler.FromCluster(client, testClusterCfg(legacyKubeletConfigMap))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -189,10 +189,6 @@ const (
|
|||||||
// system:nodes group subject is removed if present.
|
// system:nodes group subject is removed if present.
|
||||||
NodesClusterRoleBinding = "system:node"
|
NodesClusterRoleBinding = "system:node"
|
||||||
|
|
||||||
// KubeletBaseConfigMapRolePrefix defines the base kubelet configuration ConfigMap.
|
|
||||||
// TODO: Remove once UnversionedKubeletConfigMap graduates to GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
KubeletBaseConfigMapRolePrefix = "kubeadm:kubelet-config-"
|
|
||||||
// KubeletBaseConfigMapRolePrefix defines the base kubelet configuration ConfigMap.
|
// KubeletBaseConfigMapRolePrefix defines the base kubelet configuration ConfigMap.
|
||||||
KubeletBaseConfigMapRole = "kubeadm:kubelet-config"
|
KubeletBaseConfigMapRole = "kubeadm:kubelet-config"
|
||||||
// KubeProxyClusterRoleBindingName sets the name for the kube-proxy CluterRoleBinding
|
// KubeProxyClusterRoleBindingName sets the name for the kube-proxy CluterRoleBinding
|
||||||
@ -286,11 +282,6 @@ const (
|
|||||||
// KubeProxyConfigMapKey specifies in what ConfigMap key the component config of kube-proxy should be stored
|
// KubeProxyConfigMapKey specifies in what ConfigMap key the component config of kube-proxy should be stored
|
||||||
KubeProxyConfigMapKey = "config.conf"
|
KubeProxyConfigMapKey = "config.conf"
|
||||||
|
|
||||||
// KubeletBaseConfigurationConfigMapPrefix specifies in what ConfigMap in the kube-system namespace the initial remote configuration of kubelet should be stored
|
|
||||||
// TODO: Remove once UnversionedKubeletConfigMap graduates to GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
KubeletBaseConfigurationConfigMapPrefix = "kubelet-config-"
|
|
||||||
|
|
||||||
// KubeletBaseConfigurationConfigMap specifies in what ConfigMap in the kube-system namespace the initial remote configuration of kubelet should be stored
|
// KubeletBaseConfigurationConfigMap specifies in what ConfigMap in the kube-system namespace the initial remote configuration of kubelet should be stored
|
||||||
KubeletBaseConfigurationConfigMap = "kubelet-config"
|
KubeletBaseConfigurationConfigMap = "kubelet-config"
|
||||||
|
|
||||||
@ -698,13 +689,3 @@ func GetAPIServerVirtualIP(svcSubnetList string) (net.IP, error) {
|
|||||||
}
|
}
|
||||||
return internalAPIServerVirtualIP, nil
|
return internalAPIServerVirtualIP, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKubeletConfigMapName returns the right ConfigMap name for the right branch of k8s
|
|
||||||
// TODO: Remove the legacy arg once UnversionedKubeletConfigMap graduates to GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
func GetKubeletConfigMapName(k8sVersion *version.Version, legacy bool) string {
|
|
||||||
if !legacy {
|
|
||||||
return KubeletBaseConfigurationConfigMap
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s%d.%d", KubeletBaseConfigurationConfigMapPrefix, k8sVersion.Major(), k8sVersion.Minor())
|
|
||||||
}
|
|
||||||
|
@ -33,7 +33,7 @@ const (
|
|||||||
PublicKeysECDSA = "PublicKeysECDSA"
|
PublicKeysECDSA = "PublicKeysECDSA"
|
||||||
// RootlessControlPlane is expected to be in alpha in v1.22
|
// RootlessControlPlane is expected to be in alpha in v1.22
|
||||||
RootlessControlPlane = "RootlessControlPlane"
|
RootlessControlPlane = "RootlessControlPlane"
|
||||||
// UnversionedKubeletConfigMap is expected to be beta in 1.24
|
// UnversionedKubeletConfigMap is expected to be GA in 1.25
|
||||||
UnversionedKubeletConfigMap = "UnversionedKubeletConfigMap"
|
UnversionedKubeletConfigMap = "UnversionedKubeletConfigMap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ const (
|
|||||||
var InitFeatureGates = FeatureList{
|
var InitFeatureGates = FeatureList{
|
||||||
PublicKeysECDSA: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
PublicKeysECDSA: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||||
RootlessControlPlane: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
RootlessControlPlane: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||||
UnversionedKubeletConfigMap: {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Beta}},
|
UnversionedKubeletConfigMap: {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Beta, LockToDefault: true}},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Feature represents a feature being gated
|
// Feature represents a feature being gated
|
||||||
|
@ -26,13 +26,11 @@ import (
|
|||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/version"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/features"
|
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,23 +57,8 @@ func WriteConfigToDisk(cfg *kubeadmapi.ClusterConfiguration, kubeletDir string)
|
|||||||
// CreateConfigMap creates a ConfigMap with the generic kubelet configuration.
|
// CreateConfigMap creates a ConfigMap with the generic kubelet configuration.
|
||||||
// Used at "kubeadm init" and "kubeadm upgrade" time
|
// Used at "kubeadm init" and "kubeadm upgrade" time
|
||||||
func CreateConfigMap(cfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) error {
|
func CreateConfigMap(cfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) error {
|
||||||
|
configMapName := kubeadmconstants.KubeletBaseConfigurationConfigMap
|
||||||
k8sVersion, err := version.ParseSemantic(cfg.KubernetesVersion)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: cleanup after UnversionedKubeletConfigMap goes GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
legacyKubeletCM := !features.Enabled(cfg.FeatureGates, features.UnversionedKubeletConfigMap)
|
|
||||||
configMapName := kubeadmconstants.GetKubeletConfigMapName(k8sVersion, legacyKubeletCM)
|
|
||||||
fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem)
|
fmt.Printf("[kubelet] Creating a ConfigMap %q in namespace %s with the configuration for the kubelets in the cluster\n", configMapName, metav1.NamespaceSystem)
|
||||||
if legacyKubeletCM {
|
|
||||||
fmt.Printf("NOTE: The %q naming of the kubelet ConfigMap is deprecated. "+
|
|
||||||
"Once the UnversionedKubeletConfigMap feature gate graduates to Beta the default name will become just %q. "+
|
|
||||||
"Kubeadm upgrade will handle this transition transparently.\n",
|
|
||||||
configMapName, kubeadmconstants.KubeletBaseConfigurationConfigMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeletCfg, ok := cfg.ComponentConfigs[componentconfigs.KubeletGroup]
|
kubeletCfg, ok := cfg.ComponentConfigs[componentconfigs.KubeletGroup]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -105,19 +88,17 @@ func CreateConfigMap(cfg *kubeadmapi.ClusterConfiguration, client clientset.Inte
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createConfigMapRBACRules(client, k8sVersion, legacyKubeletCM); err != nil {
|
if err := createConfigMapRBACRules(client); err != nil {
|
||||||
return errors.Wrap(err, "error creating kubelet configuration configmap RBAC rules")
|
return errors.Wrap(err, "error creating kubelet configuration configmap RBAC rules")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createConfigMapRBACRules creates the RBAC rules for exposing the base kubelet ConfigMap in the kube-system namespace to unauthenticated users
|
// createConfigMapRBACRules creates the RBAC rules for exposing the base kubelet ConfigMap in the kube-system namespace to unauthenticated users
|
||||||
// TODO: Remove the legacy arg once UnversionedKubeletConfigMap graduates to GA:
|
func createConfigMapRBACRules(client clientset.Interface) error {
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Version, legacy bool) error {
|
|
||||||
if err := apiclient.CreateOrUpdateRole(client, &rbac.Role{
|
if err := apiclient.CreateOrUpdateRole(client, &rbac.Role{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: configMapRBACName(k8sVersion, legacy),
|
Name: kubeadmconstants.KubeletBaseConfigMapRole,
|
||||||
Namespace: metav1.NamespaceSystem,
|
Namespace: metav1.NamespaceSystem,
|
||||||
},
|
},
|
||||||
Rules: []rbac.PolicyRule{
|
Rules: []rbac.PolicyRule{
|
||||||
@ -125,7 +106,7 @@ func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Ve
|
|||||||
Verbs: []string{"get"},
|
Verbs: []string{"get"},
|
||||||
APIGroups: []string{""},
|
APIGroups: []string{""},
|
||||||
Resources: []string{"configmaps"},
|
Resources: []string{"configmaps"},
|
||||||
ResourceNames: []string{kubeadmconstants.GetKubeletConfigMapName(k8sVersion, legacy)},
|
ResourceNames: []string{kubeadmconstants.KubeletBaseConfigurationConfigMap},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -134,13 +115,13 @@ func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Ve
|
|||||||
|
|
||||||
return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
|
return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: configMapRBACName(k8sVersion, legacy),
|
Name: kubeadmconstants.KubeletBaseConfigMapRole,
|
||||||
Namespace: metav1.NamespaceSystem,
|
Namespace: metav1.NamespaceSystem,
|
||||||
},
|
},
|
||||||
RoleRef: rbac.RoleRef{
|
RoleRef: rbac.RoleRef{
|
||||||
APIGroup: rbac.GroupName,
|
APIGroup: rbac.GroupName,
|
||||||
Kind: "Role",
|
Kind: "Role",
|
||||||
Name: configMapRBACName(k8sVersion, legacy),
|
Name: kubeadmconstants.KubeletBaseConfigMapRole,
|
||||||
},
|
},
|
||||||
Subjects: []rbac.Subject{
|
Subjects: []rbac.Subject{
|
||||||
{
|
{
|
||||||
@ -155,16 +136,6 @@ func createConfigMapRBACRules(client clientset.Interface, k8sVersion *version.Ve
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// configMapRBACName returns the name for the Role/RoleBinding for the kubelet config configmap for the right branch of k8s
|
|
||||||
// TODO: Remove the legacy arg once UnversionedKubeletConfigMap graduates to GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
func configMapRBACName(k8sVersion *version.Version, legacy bool) string {
|
|
||||||
if !legacy {
|
|
||||||
return kubeadmconstants.KubeletBaseConfigMapRole
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s%d.%d", kubeadmconstants.KubeletBaseConfigMapRolePrefix, k8sVersion.Major(), k8sVersion.Minor())
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeConfigBytesToDisk writes a byte slice down to disk at the specific location of the kubelet config file
|
// writeConfigBytesToDisk writes a byte slice down to disk at the specific location of the kubelet config file
|
||||||
func writeConfigBytesToDisk(b []byte, kubeletDir string) error {
|
func writeConfigBytesToDisk(b []byte, kubeletDir string) error {
|
||||||
configFile := filepath.Join(kubeletDir, kubeadmconstants.KubeletConfigurationFileName)
|
configFile := filepath.Join(kubeletDir, kubeadmconstants.KubeletConfigurationFileName)
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/version"
|
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
core "k8s.io/client-go/testing"
|
core "k8s.io/client-go/testing"
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ func TestCreateConfigMapRBACRules(t *testing.T) {
|
|||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := createConfigMapRBACRules(client, version.MustParseSemantic("v1.11.0"), false); err != nil {
|
if err := createConfigMapRBACRules(client); err != nil {
|
||||||
t.Errorf("createConfigMapRBACRules: unexpected error %v", err)
|
t.Errorf("createConfigMapRBACRules: unexpected error %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import (
|
|||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/version"
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
clientsetfake "k8s.io/client-go/kubernetes/fake"
|
||||||
clienttesting "k8s.io/client-go/testing"
|
clienttesting "k8s.io/client-go/testing"
|
||||||
@ -46,7 +45,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var k8sVersionString = kubeadmconstants.MinimumControlPlaneVersion.String()
|
var k8sVersionString = kubeadmconstants.MinimumControlPlaneVersion.String()
|
||||||
var k8sVersion = version.MustParseGeneric(k8sVersionString)
|
|
||||||
var nodeName = "mynode"
|
var nodeName = "mynode"
|
||||||
var cfgFiles = map[string][]byte{
|
var cfgFiles = map[string][]byte{
|
||||||
"InitConfiguration_v1beta2": []byte(fmt.Sprintf(`
|
"InitConfiguration_v1beta2": []byte(fmt.Sprintf(`
|
||||||
@ -544,7 +542,7 @@ func TestGetInitConfigurationFromCluster(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion, false), // Kubelet component config from corresponding ConfigMap.
|
Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, // Kubelet component config from corresponding ConfigMap.
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||||
},
|
},
|
||||||
@ -588,7 +586,7 @@ func TestGetInitConfigurationFromCluster(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion, false), // Kubelet component config from corresponding ConfigMap.
|
Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, // Kubelet component config from corresponding ConfigMap.
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||||
},
|
},
|
||||||
@ -621,7 +619,7 @@ func TestGetInitConfigurationFromCluster(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion, false), // Kubelet component config from corresponding ConfigMap.
|
Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, // Kubelet component config from corresponding ConfigMap.
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||||
},
|
},
|
||||||
@ -665,7 +663,7 @@ func TestGetInitConfigurationFromCluster(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: kubeadmconstants.GetKubeletConfigMapName(k8sVersion, false), // Kubelet component config from corresponding ConfigMap.
|
Name: kubeadmconstants.KubeletBaseConfigurationConfigMap, // Kubelet component config from corresponding ConfigMap.
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
kubeadmconstants.KubeletBaseConfigurationConfigMapKey: string(cfgFiles["Kubelet_componentconfig"]),
|
||||||
},
|
},
|
||||||
|
@ -17,12 +17,7 @@ limitations under the License.
|
|||||||
package kubeadm
|
package kubeadm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/util/version"
|
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
admissionapi "k8s.io/pod-security-admission/api"
|
admissionapi "k8s.io/pod-security-admission/api"
|
||||||
|
|
||||||
@ -38,13 +33,6 @@ var (
|
|||||||
kubeletConfigConfigMapName string
|
kubeletConfigConfigMapName string
|
||||||
kubeletConfigRoleName string
|
kubeletConfigRoleName string
|
||||||
kubeletConfigRoleBindingName string
|
kubeletConfigRoleBindingName string
|
||||||
|
|
||||||
// TODO: remove these versioned strings and related logic once the UnversionedKubeletConfigMap
|
|
||||||
// feature gate goes GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
kubeletConfigConfigMapNameVersioned string
|
|
||||||
kubeletConfigRoleNameVersioned string
|
|
||||||
kubeletConfigRoleBindingNameVersioned string
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Define container for all the test specification aimed at verifying
|
// Define container for all the test specification aimed at verifying
|
||||||
@ -68,68 +56,19 @@ var _ = Describe("kubelet-config ConfigMap", func() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets the ClusterConfiguration from the kubeadm kubeadm-config ConfigMap as a untyped map
|
|
||||||
m := getClusterConfiguration(f.ClientSet)
|
|
||||||
|
|
||||||
// Extract the kubernetesVersion
|
|
||||||
// TODO: remove this after the UnversionedKubeletConfigMap feature gate goes GA:
|
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
// At that point parsing the k8s version will no longer be needed in this test.
|
|
||||||
gomega.Expect(m).To(gomega.HaveKey("kubernetesVersion"))
|
|
||||||
k8sVersionString := m["kubernetesVersion"].(string)
|
|
||||||
k8sVersion, err := version.ParseSemantic(k8sVersionString)
|
|
||||||
if err != nil {
|
|
||||||
framework.Failf("error reading kubernetesVersion from %s ConfigMap: %v", kubeadmConfigName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeletConfigConfigMapName = "kubelet-config"
|
kubeletConfigConfigMapName = "kubelet-config"
|
||||||
kubeletConfigRoleName = "kubeadm:kubelet-config"
|
kubeletConfigRoleName = "kubeadm:kubelet-config"
|
||||||
kubeletConfigRoleBindingName = kubeletConfigRoleName
|
kubeletConfigRoleBindingName = kubeletConfigRoleName
|
||||||
|
|
||||||
kubeletConfigConfigMapNameVersioned = fmt.Sprintf("kubelet-config-%d.%d", k8sVersion.Major(), k8sVersion.Minor())
|
|
||||||
kubeletConfigRoleNameVersioned = fmt.Sprintf("kubeadm:kubelet-config-%d.%d", k8sVersion.Major(), k8sVersion.Minor())
|
|
||||||
kubeletConfigRoleBindingNameVersioned = kubeletConfigRoleNameVersioned
|
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.It("should exist and be properly configured", func() {
|
ginkgo.It("should exist and be properly configured", func() {
|
||||||
// TODO: switch to GetConfigMap once UnversionedKubeletConfigMap feature gate goes GA:
|
cm := GetConfigMap(f.ClientSet, kubeSystemNamespace, kubeletConfigConfigMapName)
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
|
||||||
cm, err := f.ClientSet.CoreV1().
|
|
||||||
ConfigMaps(kubeSystemNamespace).
|
|
||||||
Get(context.TODO(), kubeletConfigConfigMapName, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
cm, err = f.ClientSet.CoreV1().
|
|
||||||
ConfigMaps(kubeSystemNamespace).
|
|
||||||
Get(context.TODO(), kubeletConfigConfigMapNameVersioned, metav1.GetOptions{})
|
|
||||||
framework.ExpectNoError(err, "error getting ConfigMap %q or %q from namespace %q",
|
|
||||||
kubeletConfigConfigMapName, kubeletConfigConfigMapNameVersioned, kubeSystemNamespace)
|
|
||||||
}
|
|
||||||
gomega.Expect(cm.Data).To(gomega.HaveKey(kubeletConfigConfigMapKey))
|
gomega.Expect(cm.Data).To(gomega.HaveKey(kubeletConfigConfigMapKey))
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.It("should have related Role and RoleBinding", func() {
|
ginkgo.It("should have related Role and RoleBinding", func() {
|
||||||
// TODO: switch to ExpectRole(Binding) once UnversionedKubeletConfigMap feature gate goes GA:
|
ExpectRole(f.ClientSet, kubeSystemNamespace, kubeletConfigRoleName)
|
||||||
// https://github.com/kubernetes/kubeadm/issues/1582
|
ExpectRoleBinding(f.ClientSet, kubeSystemNamespace, kubeletConfigRoleBindingName)
|
||||||
_, err := f.ClientSet.RbacV1().
|
|
||||||
Roles(kubeSystemNamespace).
|
|
||||||
Get(context.TODO(), kubeletConfigRoleName, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
_, err = f.ClientSet.RbacV1().
|
|
||||||
Roles(kubeSystemNamespace).
|
|
||||||
Get(context.TODO(), kubeletConfigRoleNameVersioned, metav1.GetOptions{})
|
|
||||||
framework.ExpectNoError(err, "error getting Role %q or %q from namespace %q",
|
|
||||||
kubeletConfigRoleName, kubeletConfigRoleNameVersioned, kubeSystemNamespace)
|
|
||||||
}
|
|
||||||
_, err = f.ClientSet.RbacV1().
|
|
||||||
Roles(kubeSystemNamespace).
|
|
||||||
Get(context.TODO(), kubeletConfigRoleBindingName, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
_, err = f.ClientSet.RbacV1().
|
|
||||||
Roles(kubeSystemNamespace).
|
|
||||||
Get(context.TODO(), kubeletConfigRoleBindingNameVersioned, metav1.GetOptions{})
|
|
||||||
framework.ExpectNoError(err, "error getting RoleBinding %q or %q from namespace %q",
|
|
||||||
kubeletConfigRoleBindingName, kubeletConfigRoleBindingNameVersioned, kubeSystemNamespace)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
ginkgo.It("should be accessible for bootstrap tokens", func() {
|
ginkgo.It("should be accessible for bootstrap tokens", func() {
|
||||||
|
Loading…
Reference in New Issue
Block a user