...

Source file src/k8s.io/kubernetes/test/e2e_node/kubelet_config_dir_test.go

Documentation: k8s.io/kubernetes/test/e2e_node

     1  /*
     2  Copyright 2023 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 e2enode
    18  
    19  import (
    20  	"context"
    21  	"os"
    22  	"path/filepath"
    23  	"time"
    24  
    25  	"github.com/onsi/ginkgo/v2"
    26  	"github.com/onsi/gomega"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
    29  	"k8s.io/kubernetes/test/e2e/framework"
    30  	"k8s.io/kubernetes/test/e2e/nodefeature"
    31  )
    32  
    33  var _ = SIGDescribe("Kubelet Config", framework.WithSlow(), framework.WithSerial(), framework.WithDisruptive(), nodefeature.KubeletConfigDropInDir, func() {
    34  	f := framework.NewDefaultFramework("kubelet-config-drop-in-dir-test")
    35  	ginkgo.Context("when merging drop-in configs", func() {
    36  		var oldcfg *kubeletconfig.KubeletConfiguration
    37  		ginkgo.BeforeEach(func(ctx context.Context) {
    38  			var err error
    39  			oldcfg, err = getCurrentKubeletConfig(ctx)
    40  			framework.ExpectNoError(err)
    41  		})
    42  		ginkgo.AfterEach(func(ctx context.Context) {
    43  			files, err := filepath.Glob(filepath.Join(framework.TestContext.KubeletConfigDropinDir, "*"+".conf"))
    44  			framework.ExpectNoError(err)
    45  			for _, file := range files {
    46  				err := os.Remove(file)
    47  				framework.ExpectNoError(err)
    48  			}
    49  			updateKubeletConfig(ctx, f, oldcfg, true)
    50  		})
    51  		ginkgo.It("should merge kubelet configs correctly", func(ctx context.Context) {
    52  			// Get the initial kubelet configuration
    53  			initialConfig, err := getCurrentKubeletConfig(ctx)
    54  			framework.ExpectNoError(err)
    55  
    56  			ginkgo.By("Stopping the kubelet")
    57  			restartKubelet := stopKubelet()
    58  
    59  			// wait until the kubelet health check will fail
    60  			gomega.Eventually(ctx, func() bool {
    61  				return kubeletHealthCheck(kubeletHealthCheckURL)
    62  			}, f.Timeouts.PodStart, f.Timeouts.Poll).Should(gomega.BeFalse())
    63  
    64  			configDir := framework.TestContext.KubeletConfigDropinDir
    65  
    66  			contents := []byte(`apiVersion: kubelet.config.k8s.io/v1beta1
    67  kind: KubeletConfiguration
    68  port: 10255
    69  readOnlyPort: 10257
    70  clusterDNS:
    71  - 192.168.1.10
    72  systemReserved:
    73    memory: 1Gi
    74  authorization:
    75    mode: Webhook
    76    webhook:
    77      cacheAuthorizedTTL: "5m"
    78      cacheUnauthorizedTTL: "30s"
    79  staticPodURLHeader:
    80    kubelet-api-support:
    81    - "Authorization: 234APSDFA"
    82    - "X-Custom-Header: 123"
    83    custom-static-pod:
    84    - "Authorization: 223EWRWER"
    85    - "X-Custom-Header: 456"
    86  shutdownGracePeriodByPodPriority:
    87    - priority: 1
    88      shutdownGracePeriodSeconds: 60
    89    - priority: 2
    90      shutdownGracePeriodSeconds: 45
    91    - priority: 3
    92      shutdownGracePeriodSeconds: 30
    93  featureGates:
    94    DisableKubeletCloudCredentialProviders: true
    95    PodAndContainerStatsFromCRI: true`)
    96  			framework.ExpectNoError(os.WriteFile(filepath.Join(configDir, "10-kubelet.conf"), contents, 0755))
    97  			contents = []byte(`apiVersion: kubelet.config.k8s.io/v1beta1
    98  kind: KubeletConfiguration
    99  clusterDNS:
   100  - 192.168.1.1
   101  - 192.168.1.5
   102  - 192.168.1.8
   103  port: 8080
   104  cpuManagerReconcilePeriod: 0s
   105  systemReserved:
   106    memory: 2Gi
   107  authorization:
   108    mode: Webhook
   109    webhook:
   110      cacheAuthorizedTTL: "6m"
   111      cacheUnauthorizedTTL: "40s"
   112  staticPodURLHeader:
   113    kubelet-api-support:
   114    - "Authorization: 8945AFSG1"
   115    - "X-Custom-Header: 987"
   116    custom-static-pod:
   117    - "Authorization: 223EWRWER"
   118    - "X-Custom-Header: 345"
   119  shutdownGracePeriodByPodPriority:
   120    - priority: 1
   121      shutdownGracePeriodSeconds: 19
   122    - priority: 2
   123      shutdownGracePeriodSeconds: 41
   124    - priority: 6
   125      shutdownGracePeriodSeconds: 30
   126  featureGates:
   127    PodAndContainerStatsFromCRI: false
   128    DynamicResourceAllocation: true`)
   129  			framework.ExpectNoError(os.WriteFile(filepath.Join(configDir, "20-kubelet.conf"), contents, 0755))
   130  			ginkgo.By("Restarting the kubelet")
   131  			restartKubelet()
   132  			// wait until the kubelet health check will succeed
   133  			gomega.Eventually(ctx, func() bool {
   134  				return kubeletHealthCheck(kubeletHealthCheckURL)
   135  			}, f.Timeouts.PodStart, f.Timeouts.Poll).Should(gomega.BeTrue())
   136  
   137  			mergedConfig, err := getCurrentKubeletConfig(ctx)
   138  			framework.ExpectNoError(err)
   139  
   140  			// Replace specific fields in the initial configuration with expectedConfig values
   141  			initialConfig.Port = int32(8080)                  // not overridden by second file, should be retained.
   142  			initialConfig.ReadOnlyPort = int32(10257)         // overridden by second file.
   143  			initialConfig.SystemReserved = map[string]string{ // overridden by map in second file.
   144  				"memory": "2Gi",
   145  			}
   146  			initialConfig.ClusterDNS = []string{"192.168.1.1", "192.168.1.5", "192.168.1.8"} // overridden by slice in second file.
   147  			// This value was explicitly set in the drop-in, make sure it is retained
   148  			initialConfig.CPUManagerReconcilePeriod = metav1.Duration{Duration: time.Duration(0)}
   149  			// Meanwhile, this value was not explicitly set, but could have been overridden by a "default" of 0 for the type.
   150  			// Ensure the true default persists.
   151  			initialConfig.CPUCFSQuotaPeriod = metav1.Duration{Duration: time.Duration(100000000)}
   152  			// This covers the case for a map with the list of values.
   153  			initialConfig.StaticPodURLHeader = map[string][]string{
   154  				"kubelet-api-support": {"Authorization: 8945AFSG1", "X-Custom-Header: 987"},
   155  				"custom-static-pod":   {"Authorization: 223EWRWER", "X-Custom-Header: 345"},
   156  			}
   157  			// This covers the case where the fields within the list of structs are overridden.
   158  			initialConfig.ShutdownGracePeriodByPodPriority = []kubeletconfig.ShutdownGracePeriodByPodPriority{
   159  				{Priority: 1, ShutdownGracePeriodSeconds: 19},
   160  				{Priority: 2, ShutdownGracePeriodSeconds: 41},
   161  				{Priority: 6, ShutdownGracePeriodSeconds: 30},
   162  			}
   163  			// This covers the case where the fields within the struct are overridden.
   164  			initialConfig.Authorization = kubeletconfig.KubeletAuthorization{
   165  				Mode: "Webhook",
   166  				Webhook: kubeletconfig.KubeletWebhookAuthorization{
   167  					CacheAuthorizedTTL:   metav1.Duration{Duration: time.Duration(6 * time.Minute)},
   168  					CacheUnauthorizedTTL: metav1.Duration{Duration: time.Duration(40 * time.Second)},
   169  				},
   170  			}
   171  			// This covers the case where the fields within the map are overridden.
   172  			initialConfig.FeatureGates = map[string]bool{"DisableKubeletCloudCredentialProviders": true, "PodAndContainerStatsFromCRI": false, "DynamicResourceAllocation": true}
   173  			// Compare the expected config with the merged config
   174  			gomega.Expect(initialConfig).To(gomega.BeComparableTo(mergedConfig), "Merged kubelet config does not match the expected configuration.")
   175  		})
   176  	})
   177  
   178  })
   179  

View as plain text