1
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
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
129 client := clientsetfake.NewSimpleClientset()
130
131
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
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
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