...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy/proxy_test.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy

     1  /*
     2  Copyright 2017 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 proxy
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"os"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/lithammer/dedent"
    28  
    29  	apps "k8s.io/api/apps/v1"
    30  	v1 "k8s.io/api/core/v1"
    31  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/apimachinery/pkg/runtime"
    34  	clientsetfake "k8s.io/client-go/kubernetes/fake"
    35  	clientsetscheme "k8s.io/client-go/kubernetes/scheme"
    36  	core "k8s.io/client-go/testing"
    37  
    38  	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
    39  	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
    40  	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
    41  )
    42  
    43  func TestCompileManifests(t *testing.T) {
    44  	var tests = []struct {
    45  		name     string
    46  		manifest string
    47  		data     interface{}
    48  	}{
    49  		{
    50  			name:     "KubeProxyConfigMap19",
    51  			manifest: KubeProxyConfigMap19,
    52  			data: struct {
    53  				ControlPlaneEndpoint, ProxyConfig, ProxyConfigMap, ProxyConfigMapKey string
    54  			}{
    55  				ControlPlaneEndpoint: "foo",
    56  				ProxyConfig:          "  bindAddress: 0.0.0.0\n  clusterCIDR: 192.168.1.1\n  enableProfiling: false",
    57  				ProxyConfigMap:       "bar",
    58  				ProxyConfigMapKey:    "baz",
    59  			},
    60  		},
    61  		{
    62  			name:     "KubeProxyDaemonSet19",
    63  			manifest: KubeProxyDaemonSet19,
    64  			data: struct{ Image, ProxyConfigMap, ProxyConfigMapKey string }{
    65  				Image:             "foo",
    66  				ProxyConfigMap:    "bar",
    67  				ProxyConfigMapKey: "baz",
    68  			},
    69  		},
    70  	}
    71  	for _, rt := range tests {
    72  		t.Run(rt.name, func(t *testing.T) {
    73  			_, err := kubeadmutil.ParseTemplate(rt.manifest, rt.data)
    74  			if err != nil {
    75  				t.Errorf("unexpected ParseTemplate failure: %+v", err)
    76  			}
    77  		})
    78  	}
    79  }
    80  
    81  func TestEnsureProxyAddon(t *testing.T) {
    82  	type SimulatedError int
    83  	const (
    84  		NoError SimulatedError = iota
    85  		ServiceAccountError
    86  		InvalidControlPlaneEndpoint
    87  		IPv6SetBindAddress
    88  	)
    89  
    90  	var testCases = []struct {
    91  		name           string
    92  		simError       SimulatedError
    93  		expErrString   string
    94  		expBindAddr    string
    95  		expClusterCIDR string
    96  	}{
    97  		{
    98  			name:           "Successful proxy addon",
    99  			simError:       NoError,
   100  			expErrString:   "",
   101  			expBindAddr:    "0.0.0.0",
   102  			expClusterCIDR: "5.6.7.8/24",
   103  		}, {
   104  			name:           "Simulated service account error",
   105  			simError:       ServiceAccountError,
   106  			expErrString:   "error when creating kube-proxy service account",
   107  			expBindAddr:    "0.0.0.0",
   108  			expClusterCIDR: "5.6.7.8/24",
   109  		}, {
   110  			name:           "IPv6 AdvertiseAddress address",
   111  			simError:       IPv6SetBindAddress,
   112  			expErrString:   "",
   113  			expBindAddr:    "::",
   114  			expClusterCIDR: "2001:101::/96",
   115  		},
   116  	}
   117  
   118  	// Override the default timeouts to be shorter
   119  	defaultTimeouts := kubeadmapi.GetActiveTimeouts()
   120  	defaultAPICallTimeout := defaultTimeouts.KubernetesAPICall
   121  	defaultTimeouts.KubernetesAPICall = &metav1.Duration{Duration: time.Microsecond * 500}
   122  	defer func() {
   123  		defaultTimeouts.KubernetesAPICall = defaultAPICallTimeout
   124  	}()
   125  
   126  	for _, tc := range testCases {
   127  		t.Run(tc.name, func(t *testing.T) {
   128  			// Create a fake client and set up default test configuration
   129  			client := clientsetfake.NewSimpleClientset()
   130  
   131  			// TODO: Consider using a YAML file instead for this that makes it possible to specify YAML documents for the ComponentConfigs
   132  			initConfiguration, err := configutil.DefaultedStaticInitConfiguration()
   133  			if err != nil {
   134  				t.Errorf("test failed to convert external to internal version: %v", err)
   135  				return
   136  			}
   137  
   138  			initConfiguration.LocalAPIEndpoint = kubeadmapi.APIEndpoint{
   139  				AdvertiseAddress: "1.2.3.4",
   140  				BindPort:         1234,
   141  			}
   142  
   143  			initConfiguration.ClusterConfiguration.Networking.PodSubnet = "5.6.7.8/24"
   144  			initConfiguration.ClusterConfiguration.ImageRepository = "someRepo"
   145  
   146  			// Simulate an error if necessary
   147  			switch tc.simError {
   148  			case ServiceAccountError:
   149  				client.PrependReactor("create", "serviceaccounts", func(action core.Action) (bool, runtime.Object, error) {
   150  					return true, nil, apierrors.NewUnauthorized("")
   151  				})
   152  			case InvalidControlPlaneEndpoint:
   153  				initConfiguration.LocalAPIEndpoint.AdvertiseAddress = "1.2.3"
   154  			case IPv6SetBindAddress:
   155  				initConfiguration.LocalAPIEndpoint.AdvertiseAddress = "1:2::3:4"
   156  				initConfiguration.ClusterConfiguration.Networking.PodSubnet = "2001:101::/48"
   157  			}
   158  
   159  			err = EnsureProxyAddon(&initConfiguration.ClusterConfiguration, &initConfiguration.LocalAPIEndpoint, client, os.Stdout, false)
   160  
   161  			// Compare actual to expected errors
   162  			actErr := "No error"
   163  			if err != nil {
   164  				actErr = err.Error()
   165  			}
   166  			expErr := "No error"
   167  			if tc.expErrString != "" {
   168  				expErr = tc.expErrString
   169  			}
   170  			if !strings.Contains(actErr, expErr) {
   171  				t.Errorf(
   172  					"%s test failed, expected: %s, got: %s",
   173  					tc.name,
   174  					expErr,
   175  					actErr)
   176  			}
   177  		})
   178  	}
   179  }
   180  
   181  func TestDaemonSetsHaveSystemNodeCriticalPriorityClassName(t *testing.T) {
   182  	testCases := []struct {
   183  		name     string
   184  		manifest string
   185  		data     interface{}
   186  	}{
   187  		{
   188  			name:     "KubeProxyDaemonSet19",
   189  			manifest: KubeProxyDaemonSet19,
   190  			data: struct{ Image, ProxyConfigMap, ProxyConfigMapKey string }{
   191  				Image:             "foo",
   192  				ProxyConfigMap:    "foo",
   193  				ProxyConfigMapKey: "foo",
   194  			},
   195  		},
   196  	}
   197  	for _, testCase := range testCases {
   198  		t.Run(testCase.name, func(t *testing.T) {
   199  			daemonSetBytes, _ := kubeadmutil.ParseTemplate(testCase.manifest, testCase.data)
   200  			daemonSet := &apps.DaemonSet{}
   201  			if err := runtime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), daemonSetBytes, daemonSet); err != nil {
   202  				t.Errorf("unexpected error: %v", err)
   203  			}
   204  			if daemonSet.Spec.Template.Spec.PriorityClassName != "system-node-critical" {
   205  				t.Errorf("expected to see system-node-critical priority class name. Got %q instead", daemonSet.Spec.Template.Spec.PriorityClassName)
   206  			}
   207  		})
   208  	}
   209  }
   210  
   211  func TestPrintOrCreateKubeProxyObjects(t *testing.T) {
   212  	tests := []struct {
   213  		name          string
   214  		printManifest bool
   215  		wantOut       string
   216  		wantErr       bool
   217  	}{
   218  		{
   219  			name:          "do not print manifest",
   220  			printManifest: false,
   221  			wantOut:       "[addons] Applied essential addon: kube-proxy\n",
   222  			wantErr:       false,
   223  		},
   224  		{
   225  			name:          "print manifest",
   226  			printManifest: true,
   227  			wantOut: dedent.Dedent(`---
   228  apiVersion: v1
   229  kind: ServiceAccount
   230  metadata:
   231    creationTimestamp: null
   232    name: kube-proxy
   233    namespace: kube-system
   234  ---
   235  apiVersion: rbac.authorization.k8s.io/v1
   236  kind: ClusterRoleBinding
   237  metadata:
   238    creationTimestamp: null
   239    name: kubeadm:node-proxier
   240  roleRef:
   241    apiGroup: rbac.authorization.k8s.io
   242    kind: ClusterRole
   243    name: system:node-proxier
   244  subjects:
   245  - kind: ServiceAccount
   246    name: kube-proxy
   247    namespace: kube-system
   248  ---
   249  apiVersion: rbac.authorization.k8s.io/v1
   250  kind: Role
   251  metadata:
   252    creationTimestamp: null
   253    name: kube-proxy
   254    namespace: kube-system
   255  rules:
   256  - apiGroups:
   257    - ""
   258    resourceNames:
   259    - kube-proxy
   260    resources:
   261    - configmaps
   262    verbs:
   263    - get
   264  ---
   265  apiVersion: rbac.authorization.k8s.io/v1
   266  kind: RoleBinding
   267  metadata:
   268    creationTimestamp: null
   269    name: kube-proxy
   270    namespace: kube-system
   271  roleRef:
   272    apiGroup: rbac.authorization.k8s.io
   273    kind: Role
   274    name: kube-proxy
   275  subjects:
   276  - kind: Group
   277    name: system:bootstrappers:kubeadm:default-node-token
   278  ---
   279  foo
   280  ---
   281  bar
   282  `),
   283  			wantErr: false,
   284  		},
   285  	}
   286  	for _, tt := range tests {
   287  		t.Run(tt.name, func(t *testing.T) {
   288  			out := &bytes.Buffer{}
   289  			client := newMockClientForTest(t)
   290  			cmByte := []byte{'\n', 'f', 'o', 'o', '\n'}
   291  			dsByte := []byte{'\n', 'b', 'a', 'r', '\n'}
   292  			if err := printOrCreateKubeProxyObjects(cmByte, dsByte, client, out, tt.printManifest); (err != nil) != tt.wantErr {
   293  				t.Fatalf("printOrCreateKubeProxyObjects() error = %v, wantErr %v", err, tt.wantErr)
   294  			}
   295  			if gotOut := out.String(); gotOut != tt.wantOut {
   296  				t.Fatalf("printOrCreateKubeProxyObjects() = %v, want %v", gotOut, tt.wantOut)
   297  			}
   298  		})
   299  	}
   300  }
   301  
   302  func newMockClientForTest(t *testing.T) *clientsetfake.Clientset {
   303  	client := clientsetfake.NewSimpleClientset()
   304  	_, err := client.AppsV1().DaemonSets(metav1.NamespaceSystem).Create(context.TODO(), &apps.DaemonSet{
   305  		TypeMeta: metav1.TypeMeta{
   306  			Kind:       "DaemonSet",
   307  			APIVersion: "apps/v1",
   308  		},
   309  		ObjectMeta: metav1.ObjectMeta{
   310  			Name:      "kube-proxy",
   311  			Namespace: metav1.NamespaceSystem,
   312  			Labels: map[string]string{
   313  				"k8s-app": "kube-proxy",
   314  			},
   315  		},
   316  		Spec: apps.DaemonSetSpec{
   317  			Template: v1.PodTemplateSpec{},
   318  		},
   319  	}, metav1.CreateOptions{})
   320  	if err != nil {
   321  		t.Fatalf("error creating Daemonset: %v", err)
   322  	}
   323  
   324  	return client
   325  }
   326  

View as plain text