1
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 var resolverConfig *string
53 if isSystemdResolvedActive, _ := isServiceActive("systemd-resolved"); isSystemdResolvedActive {
54
55 resolverConfig = ptr.To(kubeletSystemdResolverConfig)
56 }
57
58 tests := []struct {
59 name string
60 clusterCfg kubeadmapi.ClusterConfiguration
61 expected kubeletConfig
62 }{
63 {
64 name: "No specific defaulting works",
65 clusterCfg: kubeadmapi.ClusterConfiguration{},
66 expected: kubeletConfig{
67 config: kubeletconfig.KubeletConfiguration{
68 FeatureGates: map[string]bool{},
69 StaticPodPath: kubeadmapiv1.DefaultManifestsDir,
70 ClusterDNS: []string{kubeadmapiv1.DefaultClusterDNSIP},
71 Authentication: kubeletconfig.KubeletAuthentication{
72 X509: kubeletconfig.KubeletX509Authentication{
73 ClientCAFile: constants.CACertName,
74 },
75 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
76 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled),
77 },
78 Webhook: kubeletconfig.KubeletWebhookAuthentication{
79 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled),
80 },
81 },
82 Authorization: kubeletconfig.KubeletAuthorization{
83 Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
84 },
85 HealthzBindAddress: kubeletHealthzBindAddress,
86 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort),
87 RotateCertificates: kubeletRotateCertificates,
88 ResolverConfig: resolverConfig,
89 CgroupDriver: constants.CgroupDriverSystemd,
90 },
91 },
92 },
93 {
94 name: "Service subnet, no dual stack defaulting works",
95 clusterCfg: kubeadmapi.ClusterConfiguration{
96 Networking: kubeadmapi.Networking{
97 ServiceSubnet: "192.168.0.0/16",
98 },
99 },
100 expected: kubeletConfig{
101 config: kubeletconfig.KubeletConfiguration{
102 FeatureGates: map[string]bool{},
103 StaticPodPath: kubeadmapiv1.DefaultManifestsDir,
104 ClusterDNS: []string{"192.168.0.10"},
105 Authentication: kubeletconfig.KubeletAuthentication{
106 X509: kubeletconfig.KubeletX509Authentication{
107 ClientCAFile: constants.CACertName,
108 },
109 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
110 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled),
111 },
112 Webhook: kubeletconfig.KubeletWebhookAuthentication{
113 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled),
114 },
115 },
116 Authorization: kubeletconfig.KubeletAuthorization{
117 Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
118 },
119 HealthzBindAddress: kubeletHealthzBindAddress,
120 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort),
121 RotateCertificates: kubeletRotateCertificates,
122 ResolverConfig: resolverConfig,
123 CgroupDriver: constants.CgroupDriverSystemd,
124 },
125 },
126 },
127 {
128 name: "Service subnet, enabled dual stack defaulting works",
129 clusterCfg: kubeadmapi.ClusterConfiguration{
130 Networking: kubeadmapi.Networking{
131 ServiceSubnet: "192.168.0.0/16",
132 },
133 },
134 expected: kubeletConfig{
135 config: kubeletconfig.KubeletConfiguration{
136 FeatureGates: map[string]bool{},
137 StaticPodPath: kubeadmapiv1.DefaultManifestsDir,
138 ClusterDNS: []string{"192.168.0.10"},
139 Authentication: kubeletconfig.KubeletAuthentication{
140 X509: kubeletconfig.KubeletX509Authentication{
141 ClientCAFile: constants.CACertName,
142 },
143 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
144 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled),
145 },
146 Webhook: kubeletconfig.KubeletWebhookAuthentication{
147 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled),
148 },
149 },
150 Authorization: kubeletconfig.KubeletAuthorization{
151 Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
152 },
153 HealthzBindAddress: kubeletHealthzBindAddress,
154 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort),
155 RotateCertificates: kubeletRotateCertificates,
156 ResolverConfig: resolverConfig,
157 CgroupDriver: constants.CgroupDriverSystemd,
158 },
159 },
160 },
161 {
162 name: "DNS domain defaulting works",
163 clusterCfg: kubeadmapi.ClusterConfiguration{
164 Networking: kubeadmapi.Networking{
165 DNSDomain: "example.com",
166 },
167 },
168 expected: kubeletConfig{
169 config: kubeletconfig.KubeletConfiguration{
170 FeatureGates: map[string]bool{},
171 StaticPodPath: kubeadmapiv1.DefaultManifestsDir,
172 ClusterDNS: []string{kubeadmapiv1.DefaultClusterDNSIP},
173 ClusterDomain: "example.com",
174 Authentication: kubeletconfig.KubeletAuthentication{
175 X509: kubeletconfig.KubeletX509Authentication{
176 ClientCAFile: constants.CACertName,
177 },
178 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
179 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled),
180 },
181 Webhook: kubeletconfig.KubeletWebhookAuthentication{
182 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled),
183 },
184 },
185 Authorization: kubeletconfig.KubeletAuthorization{
186 Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
187 },
188 HealthzBindAddress: kubeletHealthzBindAddress,
189 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort),
190 RotateCertificates: kubeletRotateCertificates,
191 ResolverConfig: resolverConfig,
192 CgroupDriver: constants.CgroupDriverSystemd,
193 },
194 },
195 },
196 {
197 name: "CertificatesDir defaulting works",
198 clusterCfg: kubeadmapi.ClusterConfiguration{
199 CertificatesDir: "/path/to/certs",
200 },
201 expected: kubeletConfig{
202 config: kubeletconfig.KubeletConfiguration{
203 FeatureGates: map[string]bool{},
204 StaticPodPath: kubeadmapiv1.DefaultManifestsDir,
205 ClusterDNS: []string{kubeadmapiv1.DefaultClusterDNSIP},
206 Authentication: kubeletconfig.KubeletAuthentication{
207 X509: kubeletconfig.KubeletX509Authentication{
208 ClientCAFile: filepath.Join("/path/to/certs", constants.CACertName),
209 },
210 Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
211 Enabled: ptr.To(kubeletAuthenticationAnonymousEnabled),
212 },
213 Webhook: kubeletconfig.KubeletWebhookAuthentication{
214 Enabled: ptr.To(kubeletAuthenticationWebhookEnabled),
215 },
216 },
217 Authorization: kubeletconfig.KubeletAuthorization{
218 Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
219 },
220 HealthzBindAddress: kubeletHealthzBindAddress,
221 HealthzPort: ptr.To[int32](constants.KubeletHealthzPort),
222 RotateCertificates: kubeletRotateCertificates,
223 ResolverConfig: resolverConfig,
224 CgroupDriver: constants.CgroupDriverSystemd,
225 },
226 },
227 },
228 }
229
230 for _, test := range tests {
231 t.Run(test.name, func(t *testing.T) {
232
233 expected := test.expected
234 expected.configBase.GroupVersion = kubeletconfig.SchemeGroupVersion
235
236 got := &kubeletConfig{
237 configBase: configBase{
238 GroupVersion: kubeletconfig.SchemeGroupVersion,
239 },
240 }
241 got.Default(&test.clusterCfg, &kubeadmapi.APIEndpoint{}, &kubeadmapi.NodeRegistrationOptions{})
242
243 if !reflect.DeepEqual(got, &expected) {
244 t.Fatalf("Missmatch between expected and got:\nExpected:\n%v\n---\nGot:\n%v", expected, *got)
245 }
246 })
247 }
248 }
249
250
251 func runKubeletFromTest(t *testing.T, perform func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error)) {
252 const (
253 kind = "KubeletConfiguration"
254 clusterDomain = "foo.bar"
255 )
256
257 gvk := kubeletHandler.GroupVersion.WithKind(kind)
258 yaml := fmt.Sprintf("apiVersion: %s\nkind: %s\nclusterDomain: %s", kubeletHandler.GroupVersion, kind, clusterDomain)
259
260 cfg, err := perform(gvk, yaml)
261
262 if err != nil {
263 t.Fatalf("unexpected failure: %v", err)
264 }
265 if cfg == nil {
266 t.Fatal("no config loaded where it should have been")
267 }
268 if kubeletCfg, ok := cfg.(*kubeletConfig); !ok {
269 t.Fatalf("found different object type than expected: %s", reflect.TypeOf(cfg))
270 } else if kubeletCfg.config.ClusterDomain != clusterDomain {
271 t.Fatalf("unexpected control value (clusterDomain):\n\tgot: %q\n\texpected: %q", kubeletCfg.config.ClusterDomain, clusterDomain)
272 }
273 }
274
275 func TestKubeletFromDocumentMap(t *testing.T) {
276 runKubeletFromTest(t, func(gvk schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) {
277 return kubeletHandler.FromDocumentMap(kubeadmapi.DocumentMap{
278 gvk: []byte(yaml),
279 })
280 })
281 }
282
283 func TestKubeletFromCluster(t *testing.T) {
284 runKubeletFromTest(t, func(_ schema.GroupVersionKind, yaml string) (kubeadmapi.ComponentConfig, error) {
285 client := clientsetfake.NewSimpleClientset(
286 testKubeletConfigMap(yaml),
287 )
288 return kubeletHandler.FromCluster(client, testClusterCfg())
289 })
290 }
291
View as plain text