...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs/kubelet_test.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs

     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  	var resolverConfig *string
    53  	if isSystemdResolvedActive, _ := isServiceActive("systemd-resolved"); isSystemdResolvedActive {
    54  		// If systemd-resolved is active, we need to set the default resolver config
    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  			// This is the same for all test cases so we set it here
   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  // runKubeletFromTest holds common test case data and evaluation code for kubeletHandler.From* functions
   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