k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/componentconfigs/kubelet_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package componentconfigs 18 19 import ( 20 "fmt" 21 "path/filepath" 22 "reflect" 23 "testing" 24 25 "github.com/lithammer/dedent" 26 27 v1 "k8s.io/api/core/v1" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/runtime/schema" 30 clientsetfake "k8s.io/client-go/kubernetes/fake" 31 kubeletconfig "k8s.io/kubelet/config/v1beta1" 32 "k8s.io/utils/ptr" 33 34 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" 35 kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3" 36 "k8s.io/kubernetes/cmd/kubeadm/app/constants" 37 ) 38 39 func testKubeletConfigMap(contents string) *v1.ConfigMap { 40 return &v1.ConfigMap{ 41 ObjectMeta: metav1.ObjectMeta{ 42 Name: constants.KubeletBaseConfigurationConfigMap, 43 Namespace: metav1.NamespaceSystem, 44 }, 45 Data: map[string]string{ 46 constants.KubeletBaseConfigurationConfigMapKey: dedent.Dedent(contents), 47 }, 48 } 49 } 50 51 func TestKubeletDefault(t *testing.T) { 52 tests := []struct { 53 name string 54 clusterCfg kubeadmapi.ClusterConfiguration 55 expected kubeletConfig 56 }{ 57 { 58 name: "No specific defaulting works", 59 clusterCfg: kubeadmapi.ClusterConfiguration{}, 60 expected: kubeletConfig{ 61 config: kubeletconfig.KubeletConfiguration{ 62 FeatureGates: map[string]bool{}, 63 StaticPodPath: kubeadmapiv1.DefaultManifestsDir, 64 ClusterDNS: []string{kubeadmapiv1.DefaultClusterDNSIP}, 65 Authentication: kubeletconfig.KubeletAuthentication{ 66 X509: kubeletconfig.KubeletX509Authentication{ 67 ClientCAFile: constants.CACertName, 68 }, 69 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{ 70 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled), 71 }, 72 Webhook: kubeletconfig.KubeletWebhookAuthentication{ 73 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled), 74 }, 75 }, 76 Authorization: kubeletconfig.KubeletAuthorization{ 77 Mode: kubeletconfig.KubeletAuthorizationModeWebhook, 78 }, 79 HealthzBindAddress: kubeletHealthzBindAddress, 80 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort), 81 RotateCertificates: kubeletRotateCertificates, 82 CgroupDriver: constants.CgroupDriverSystemd, 83 }, 84 }, 85 }, 86 { 87 name: "Service subnet, no dual stack defaulting works", 88 clusterCfg: kubeadmapi.ClusterConfiguration{ 89 Networking: kubeadmapi.Networking{ 90 ServiceSubnet: "192.168.0.0/16", 91 }, 92 }, 93 expected: kubeletConfig{ 94 config: kubeletconfig.KubeletConfiguration{ 95 FeatureGates: map[string]bool{}, 96 StaticPodPath: kubeadmapiv1.DefaultManifestsDir, 97 ClusterDNS: []string{"192.168.0.10"}, 98 Authentication: kubeletconfig.KubeletAuthentication{ 99 X509: kubeletconfig.KubeletX509Authentication{ 100 ClientCAFile: constants.CACertName, 101 }, 102 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{ 103 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled), 104 }, 105 Webhook: kubeletconfig.KubeletWebhookAuthentication{ 106 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled), 107 }, 108 }, 109 Authorization: kubeletconfig.KubeletAuthorization{ 110 Mode: kubeletconfig.KubeletAuthorizationModeWebhook, 111 }, 112 HealthzBindAddress: kubeletHealthzBindAddress, 113 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort), 114 RotateCertificates: kubeletRotateCertificates, 115 CgroupDriver: constants.CgroupDriverSystemd, 116 }, 117 }, 118 }, 119 { 120 name: "Service subnet, enabled dual stack defaulting works", 121 clusterCfg: kubeadmapi.ClusterConfiguration{ 122 Networking: kubeadmapi.Networking{ 123 ServiceSubnet: "192.168.0.0/16", 124 }, 125 }, 126 expected: kubeletConfig{ 127 config: kubeletconfig.KubeletConfiguration{ 128 FeatureGates: map[string]bool{}, 129 StaticPodPath: kubeadmapiv1.DefaultManifestsDir, 130 ClusterDNS: []string{"192.168.0.10"}, 131 Authentication: kubeletconfig.KubeletAuthentication{ 132 X509: kubeletconfig.KubeletX509Authentication{ 133 ClientCAFile: constants.CACertName, 134 }, 135 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{ 136 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled), 137 }, 138 Webhook: kubeletconfig.KubeletWebhookAuthentication{ 139 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled), 140 }, 141 }, 142 Authorization: kubeletconfig.KubeletAuthorization{ 143 Mode: kubeletconfig.KubeletAuthorizationModeWebhook, 144 }, 145 HealthzBindAddress: kubeletHealthzBindAddress, 146 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort), 147 RotateCertificates: kubeletRotateCertificates, 148 CgroupDriver: constants.CgroupDriverSystemd, 149 }, 150 }, 151 }, 152 { 153 name: "DNS domain defaulting works", 154 clusterCfg: kubeadmapi.ClusterConfiguration{ 155 Networking: kubeadmapi.Networking{ 156 DNSDomain: "example.com", 157 }, 158 }, 159 expected: kubeletConfig{ 160 config: kubeletconfig.KubeletConfiguration{ 161 FeatureGates: map[string]bool{}, 162 StaticPodPath: kubeadmapiv1.DefaultManifestsDir, 163 ClusterDNS: []string{kubeadmapiv1.DefaultClusterDNSIP}, 164 ClusterDomain: "example.com", 165 Authentication: kubeletconfig.KubeletAuthentication{ 166 X509: kubeletconfig.KubeletX509Authentication{ 167 ClientCAFile: constants.CACertName, 168 }, 169 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{ 170 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled), 171 }, 172 Webhook: kubeletconfig.KubeletWebhookAuthentication{ 173 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled), 174 }, 175 }, 176 Authorization: kubeletconfig.KubeletAuthorization{ 177 Mode: kubeletconfig.KubeletAuthorizationModeWebhook, 178 }, 179 HealthzBindAddress: kubeletHealthzBindAddress, 180 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort), 181 RotateCertificates: kubeletRotateCertificates, 182 CgroupDriver: constants.CgroupDriverSystemd, 183 }, 184 }, 185 }, 186 { 187 name: "CertificatesDir defaulting works", 188 clusterCfg: kubeadmapi.ClusterConfiguration{ 189 CertificatesDir: "/path/to/certs", 190 }, 191 expected: kubeletConfig{ 192 config: kubeletconfig.KubeletConfiguration{ 193 FeatureGates: map[string]bool{}, 194 StaticPodPath: kubeadmapiv1.DefaultManifestsDir, 195 ClusterDNS: []string{kubeadmapiv1.DefaultClusterDNSIP}, 196 Authentication: kubeletconfig.KubeletAuthentication{ 197 X509: kubeletconfig.KubeletX509Authentication{ 198 ClientCAFile: filepath.Join("/path/to/certs", constants.CACertName), 199 }, 200 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{ 201 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled), 202 }, 203 Webhook: kubeletconfig.KubeletWebhookAuthentication{ 204 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled), 205 }, 206 }, 207 Authorization: kubeletconfig.KubeletAuthorization{ 208 Mode: kubeletconfig.KubeletAuthorizationModeWebhook, 209 }, 210 HealthzBindAddress: kubeletHealthzBindAddress, 211 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort), 212 RotateCertificates: kubeletRotateCertificates, 213 CgroupDriver: constants.CgroupDriverSystemd, 214 }, 215 }, 216 }, 217 } 218 219 for _, test := range tests { 220 t.Run(test.name, func(t *testing.T) { 221 // This is the same for all test cases so we set it here 222 expected := test.expected 223 expected.configBase.GroupVersion = kubeletconfig.SchemeGroupVersion 224 225 got := &kubeletConfig{ 226 configBase: configBase{ 227 GroupVersion: kubeletconfig.SchemeGroupVersion, 228 }, 229 } 230 got.Default(&test.clusterCfg, &kubeadmapi.APIEndpoint{}, &kubeadmapi.NodeRegistrationOptions{}) 231 232 if !reflect.DeepEqual(got, &expected) { 233 t.Fatalf("Missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", expected, *got) 234 } 235 }) 236 } 237 } 238 239 // runKubeletFromTest holds common test case data and evaluation code for kubeletHandler.From* functions 240 func runKubeletFromTest(t *testing.T, perform func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error)) { 241 const ( 242 kind = "KubeletConfiguration" 243 clusterDomain = "foo.bar" 244 ) 245 246 gvk := kubeletHandler.GroupVersion.WithKind(kind) 247 yaml := fmt.Sprintf("apiVersion: %s\nkind: %s\nclusterDomain: %s", kubeletHandler.GroupVersion, kind, clusterDomain) 248 249 cfg, err := perform(gvk, yaml) 250 251 if err != nil { 252 t.Fatalf("unexpected failure: %v", err) 253 } 254 if cfg == nil { 255 t.Fatal("no config loaded where it should have been") 256 } 257 if kubeletCfg, ok := cfg.(*kubeletConfig); !ok { 258 t.Fatalf("found different object type than expected: %s", reflect.TypeOf(cfg)) 259 } else if kubeletCfg.config.ClusterDomain != clusterDomain { 260 t.Fatalf("unexpected control value (clusterDomain):\n\tgot: %q\n\texpected: %q", kubeletCfg.config.ClusterDomain, clusterDomain) 261 } 262 } 263 264 func TestKubeletFromDocumentMap(t *testing.T) { 265 runKubeletFromTest(t, func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) { 266 return kubeletHandler.FromDocumentMap(kubeadmapi.DocumentMap{ 267 gvk: []byte(yaml), 268 }) 269 }) 270 } 271 272 func TestKubeletFromCluster(t *testing.T) { 273 runKubeletFromTest(t, func(_ schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) { 274 client := clientsetfake.NewSimpleClientset( 275 testKubeletConfigMap(yaml), 276 ) 277 return kubeletHandler.FromCluster(client, testClusterCfg()) 278 }) 279 }