1
16
17 package dualstack
18
19 import (
20 "encoding/json"
21 "fmt"
22 "reflect"
23 "strings"
24 "testing"
25 "time"
26
27 jsonpatch "github.com/evanphx/json-patch"
28
29 v1 "k8s.io/api/core/v1"
30 apierrors "k8s.io/apimachinery/pkg/api/errors"
31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 "k8s.io/apimachinery/pkg/types"
33
34 "k8s.io/apimachinery/pkg/util/intstr"
35 "k8s.io/apimachinery/pkg/util/wait"
36
37 "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
38 "k8s.io/kubernetes/test/integration/framework"
39 "k8s.io/kubernetes/test/utils/ktesting"
40 netutils "k8s.io/utils/net"
41 )
42
43
44 func TestCreateServiceSingleStackIPv4(t *testing.T) {
45
46 serviceCIDR := "10.0.0.0/16"
47
48 tCtx := ktesting.Init(t)
49 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
50 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
51 opts.ServiceClusterIPRanges = serviceCIDR
52 },
53 })
54 defer tearDownFn()
55
56
57 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
58 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
59 if err != nil && !apierrors.IsNotFound(err) {
60 return false, err
61 }
62 return !apierrors.IsNotFound(err), nil
63 }); err != nil {
64 t.Fatalf("creating kubernetes service timed out")
65 }
66
67 var testcases = []struct {
68 name string
69 serviceType v1.ServiceType
70 clusterIPs []string
71 ipFamilies []v1.IPFamily
72 ipFamilyPolicy v1.IPFamilyPolicy
73 expectedIPFamilies []v1.IPFamily
74 expectError bool
75 }{
76 {
77 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack",
78 serviceType: v1.ServiceTypeClusterIP,
79 clusterIPs: nil,
80 ipFamilies: nil,
81 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
82 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
83 expectError: false,
84 },
85 {
86 name: "Type ClusterIP - Client Allocated IP - Default IP Family - Policy Single Stack",
87 serviceType: v1.ServiceTypeClusterIP,
88 clusterIPs: []string{"10.0.0.16"},
89 ipFamilies: nil,
90 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
91 expectError: false,
92 },
93 {
94 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack",
95 serviceType: v1.ServiceTypeClusterIP,
96 clusterIPs: []string{},
97 ipFamilies: nil,
98 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
99 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
100 expectError: false,
101 },
102 {
103 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack",
104 serviceType: v1.ServiceTypeClusterIP,
105 clusterIPs: nil,
106 ipFamilies: nil,
107 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
108 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
109 expectError: true,
110 },
111 {
112 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack",
113 serviceType: v1.ServiceTypeClusterIP,
114 clusterIPs: nil,
115 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
116 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
117 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
118 expectError: false,
119 },
120 {
121 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack",
122 serviceType: v1.ServiceTypeClusterIP,
123 clusterIPs: nil,
124 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
125 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
126 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
127 expectError: false,
128 },
129 {
130 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack",
131 serviceType: v1.ServiceTypeClusterIP,
132 clusterIPs: nil,
133 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
134 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
135 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
136 expectError: true,
137 },
138 {
139 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack",
140 serviceType: v1.ServiceTypeClusterIP,
141 clusterIPs: nil,
142 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
143 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
144 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
145 expectError: true,
146 },
147 {
148 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack",
149 serviceType: v1.ServiceTypeClusterIP,
150 clusterIPs: nil,
151 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
152 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
153 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
154 expectError: true,
155 },
156 {
157 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack",
158 serviceType: v1.ServiceTypeClusterIP,
159 clusterIPs: nil,
160 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
161 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
162 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
163 expectError: true,
164 },
165 {
166 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Single Stack",
167 serviceType: v1.ServiceTypeClusterIP,
168 clusterIPs: nil,
169 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
170 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
171 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
172 expectError: true,
173 },
174 {
175 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack",
176 serviceType: v1.ServiceTypeClusterIP,
177 clusterIPs: nil,
178 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
179 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
180 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
181 expectError: true,
182 },
183 {
184 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack",
185 serviceType: v1.ServiceTypeClusterIP,
186 clusterIPs: nil,
187 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
188 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
189 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
190 expectError: true,
191 },
192 {
193 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack",
194 serviceType: v1.ServiceTypeClusterIP,
195 clusterIPs: nil,
196 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
197 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
198 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
199 expectError: true,
200 },
201 {
202 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack",
203 serviceType: v1.ServiceTypeClusterIP,
204 clusterIPs: nil,
205 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
206 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
207 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
208 expectError: true,
209 },
210 {
211 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack",
212 serviceType: v1.ServiceTypeClusterIP,
213 clusterIPs: nil,
214 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
215 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
216 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
217 expectError: true,
218 },
219 }
220
221 for i, tc := range testcases {
222 tc := tc
223 t.Run(tc.name, func(t *testing.T) {
224
225 svc := &v1.Service{
226 ObjectMeta: metav1.ObjectMeta{
227 Name: fmt.Sprintf("svc-test-%d", i),
228 },
229 Spec: v1.ServiceSpec{
230 Type: tc.serviceType,
231 ClusterIPs: tc.clusterIPs,
232 IPFamilies: tc.ipFamilies,
233 Ports: []v1.ServicePort{
234 {
235 Port: 443,
236 TargetPort: intstr.FromInt32(443),
237 },
238 },
239 },
240 }
241
242 if len(tc.ipFamilyPolicy) > 0 {
243 svc.Spec.IPFamilyPolicy = &tc.ipFamilyPolicy
244 }
245
246 if len(tc.clusterIPs) > 0 {
247 svc.Spec.ClusterIP = tc.clusterIPs[0]
248 }
249
250
251 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
252 if (err != nil) != tc.expectError {
253 t.Errorf("Test failed expected result: %v received %v ", tc.expectError, err)
254 }
255
256 if err != nil {
257 return
258 }
259
260 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
261 if err != nil {
262 t.Errorf("Unexpected error to get the service %s %v", svc.Name, err)
263 }
264 if err := validateServiceAndClusterIPFamily(svc, tc.expectedIPFamilies); err != nil {
265 t.Errorf("Unexpected error validating the service %s\n%+v\n%v", svc.Name, svc, err)
266 }
267 })
268 }
269 }
270
271
272 func TestCreateServiceDualStackIPv6(t *testing.T) {
273
274 serviceCIDR := "2001:db8:1::/112"
275
276 tCtx := ktesting.Init(t)
277 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
278 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
279 opts.ServiceClusterIPRanges = serviceCIDR
280 opts.GenericServerRunOptions.AdvertiseAddress = netutils.ParseIPSloppy("2001:db8::10")
281 },
282 })
283 defer tearDownFn()
284
285
286 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
287 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
288 if err != nil && !apierrors.IsNotFound(err) {
289 return false, err
290 }
291 return !apierrors.IsNotFound(err), nil
292 }); err != nil {
293 t.Fatalf("creating kubernetes service timed out")
294 }
295
296 var testcases = []struct {
297 name string
298 serviceType v1.ServiceType
299 clusterIPs []string
300 ipFamilies []v1.IPFamily
301 expectedIPFamilies []v1.IPFamily
302 ipFamilyPolicy v1.IPFamilyPolicy
303 expectError bool
304 }{
305 {
306 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack",
307 serviceType: v1.ServiceTypeClusterIP,
308 clusterIPs: []string{},
309 ipFamilies: nil,
310 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol},
311 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
312 expectError: false,
313 },
314 {
315 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack",
316 serviceType: v1.ServiceTypeClusterIP,
317 clusterIPs: []string{},
318 ipFamilies: nil,
319 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol},
320 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
321 expectError: false,
322 },
323 {
324 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack",
325 serviceType: v1.ServiceTypeClusterIP,
326 clusterIPs: []string{},
327 ipFamilies: nil,
328 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
329 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
330 expectError: true,
331 },
332 {
333 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack",
334 serviceType: v1.ServiceTypeClusterIP,
335 clusterIPs: []string{},
336 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
337 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
338 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
339 expectError: true,
340 },
341 {
342 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack",
343 serviceType: v1.ServiceTypeClusterIP,
344 clusterIPs: []string{},
345 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
346 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
347 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
348 expectError: true,
349 },
350 {
351 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack",
352 serviceType: v1.ServiceTypeClusterIP,
353 clusterIPs: []string{},
354 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
355 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
356 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
357 expectError: true,
358 },
359 {
360 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack",
361 serviceType: v1.ServiceTypeClusterIP,
362 clusterIPs: []string{},
363 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
364 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol},
365 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
366 expectError: false,
367 },
368 {
369 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack",
370 serviceType: v1.ServiceTypeClusterIP,
371 clusterIPs: []string{},
372 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
373 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol},
374 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
375 expectError: false,
376 },
377 {
378 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack",
379 serviceType: v1.ServiceTypeClusterIP,
380 clusterIPs: []string{},
381 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
382 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
383 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
384 expectError: true,
385 },
386 {
387 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Single Stack",
388 serviceType: v1.ServiceTypeClusterIP,
389 clusterIPs: []string{},
390 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
391 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
392 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
393 expectError: true,
394 },
395 {
396 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack",
397 serviceType: v1.ServiceTypeClusterIP,
398 clusterIPs: []string{},
399 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
400 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
401 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
402 expectError: true,
403 },
404 {
405 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack",
406 serviceType: v1.ServiceTypeClusterIP,
407 clusterIPs: []string{},
408 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
409 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
410 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
411 expectError: true,
412 },
413 {
414 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack",
415 serviceType: v1.ServiceTypeClusterIP,
416 clusterIPs: []string{},
417 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
418 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
419 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
420 expectError: true,
421 },
422 {
423 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack",
424 serviceType: v1.ServiceTypeClusterIP,
425 clusterIPs: []string{},
426 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
427 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
428 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
429 expectError: true,
430 },
431 {
432 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack",
433 serviceType: v1.ServiceTypeClusterIP,
434 clusterIPs: []string{},
435 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
436 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
437 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
438 expectError: true,
439 },
440 }
441
442 for i, tc := range testcases {
443 tc := tc
444 t.Run(tc.name, func(t *testing.T) {
445
446 svc := &v1.Service{
447 ObjectMeta: metav1.ObjectMeta{
448 Name: fmt.Sprintf("svc-test-%d", i),
449 },
450 Spec: v1.ServiceSpec{
451 Type: tc.serviceType,
452 ClusterIPs: tc.clusterIPs,
453 IPFamilies: tc.ipFamilies,
454 IPFamilyPolicy: &tc.ipFamilyPolicy,
455 Ports: []v1.ServicePort{
456 {
457 Name: fmt.Sprintf("port-test-%d", i),
458 Port: 443,
459 TargetPort: intstr.IntOrString{IntVal: 443},
460 Protocol: "TCP",
461 },
462 },
463 },
464 }
465
466
467 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
468 if (err != nil) != tc.expectError {
469 t.Errorf("Test failed expected result: %v received %v ", tc.expectError, err)
470 }
471
472 if err != nil {
473 return
474 }
475
476 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
477 if err != nil {
478 t.Errorf("Unexpected error to get the service %s %v", svc.Name, err)
479 }
480 if err := validateServiceAndClusterIPFamily(svc, tc.expectedIPFamilies); err != nil {
481 t.Errorf("Unexpected error validating the service %s %v", svc.Name, err)
482 }
483 })
484 }
485 }
486
487
488 func TestCreateServiceDualStackIPv4IPv6(t *testing.T) {
489
490 serviceCIDR := "10.0.0.0/16"
491 secondaryServiceCIDR := "2001:db8:1::/112"
492
493 tCtx := ktesting.Init(t)
494 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
495 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
496 opts.ServiceClusterIPRanges = fmt.Sprintf("%s,%s", serviceCIDR, secondaryServiceCIDR)
497 },
498 })
499 defer tearDownFn()
500
501
502 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
503 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
504 if err != nil && !apierrors.IsNotFound(err) {
505 return false, err
506 }
507 return !apierrors.IsNotFound(err), nil
508 }); err != nil {
509 t.Fatalf("creating kubernetes service timed out")
510 }
511
512 var testcases = []struct {
513 name string
514 serviceType v1.ServiceType
515 clusterIPs []string
516 ipFamilies []v1.IPFamily
517 expectedIPFamilies []v1.IPFamily
518 ipFamilyPolicy v1.IPFamilyPolicy
519 expectError bool
520 }{
521 {
522 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack",
523 serviceType: v1.ServiceTypeClusterIP,
524 clusterIPs: []string{},
525 ipFamilies: nil,
526 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
527 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
528 expectError: false,
529 },
530 {
531 name: "Type ClusterIP - Client Allocated IP - IPv4 Family",
532 serviceType: v1.ServiceTypeClusterIP,
533 clusterIPs: []string{"10.0.0.16"},
534 ipFamilies: nil,
535 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
536 expectError: false,
537 },
538 {
539 name: "Type ClusterIP - Client Allocated IP - IPv6 Family",
540 serviceType: v1.ServiceTypeClusterIP,
541 clusterIPs: []string{"2001:db8:1::16"},
542 ipFamilies: nil,
543 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol},
544 expectError: false,
545 },
546 {
547 name: "Type ClusterIP - Client Allocated IP - IPv4 IPv6 Family ",
548 serviceType: v1.ServiceTypeClusterIP,
549 clusterIPs: []string{"10.0.0.17", "2001:db8:1::17"},
550 ipFamilies: nil,
551 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
552 expectError: true,
553 },
554 {
555 name: "Type ClusterIP - Client Allocated IP - IPv4 IPv6 Family ",
556 serviceType: v1.ServiceTypeClusterIP,
557 clusterIPs: []string{"10.0.0.17", "2001:db8:1::17"},
558 ipFamilies: nil,
559 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
560 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
561 expectError: false,
562 },
563 {
564 name: "Type ClusterIP - Client Allocated IP - IPv4 IPv6 Family ",
565 serviceType: v1.ServiceTypeClusterIP,
566 clusterIPs: []string{"10.0.0.18", "2001:db8:1::18"},
567 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
568 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
569 expectError: true,
570 },
571 {
572 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack",
573 serviceType: v1.ServiceTypeClusterIP,
574 clusterIPs: []string{},
575 ipFamilies: nil,
576 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
577 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
578 expectError: false,
579 },
580 {
581 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack",
582 serviceType: v1.ServiceTypeClusterIP,
583 clusterIPs: []string{},
584 ipFamilies: nil,
585 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
586 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
587 expectError: false,
588 },
589 {
590 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack",
591 serviceType: v1.ServiceTypeClusterIP,
592 clusterIPs: []string{},
593 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
594 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol},
595 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
596 expectError: false,
597 },
598 {
599 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack",
600 serviceType: v1.ServiceTypeClusterIP,
601 clusterIPs: []string{},
602 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
603 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
604 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
605 expectError: false,
606 },
607 {
608 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack",
609 serviceType: v1.ServiceTypeClusterIP,
610 clusterIPs: []string{},
611 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
612 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
613 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
614 expectError: false,
615 },
616 {
617 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack",
618 serviceType: v1.ServiceTypeClusterIP,
619 clusterIPs: []string{},
620 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
621 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol},
622 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
623 expectError: false,
624 },
625 {
626 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack",
627 serviceType: v1.ServiceTypeClusterIP,
628 clusterIPs: []string{},
629 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
630 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
631 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
632 expectError: false,
633 },
634 {
635 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack",
636 serviceType: v1.ServiceTypeClusterIP,
637 clusterIPs: []string{},
638 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
639 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
640 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
641 expectError: false,
642 },
643
644 {
645 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Single Stack",
646 serviceType: v1.ServiceTypeClusterIP,
647 clusterIPs: []string{},
648 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
649 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
650 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
651 expectError: true,
652 },
653 {
654 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack",
655 serviceType: v1.ServiceTypeClusterIP,
656 clusterIPs: []string{},
657 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
658 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
659 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
660 expectError: false,
661 },
662 {
663 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack",
664 serviceType: v1.ServiceTypeClusterIP,
665 clusterIPs: []string{},
666 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
667 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
668 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
669 expectError: false,
670 },
671 {
672 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack",
673 serviceType: v1.ServiceTypeClusterIP,
674 clusterIPs: []string{},
675 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
676 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
677 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
678 expectError: true,
679 },
680 {
681 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack",
682 serviceType: v1.ServiceTypeClusterIP,
683 clusterIPs: []string{},
684 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
685 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
686 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
687 expectError: false,
688 },
689 {
690 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack",
691 serviceType: v1.ServiceTypeClusterIP,
692 clusterIPs: []string{},
693 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
694 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
695 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
696 expectError: false,
697 },
698 }
699
700 for i, tc := range testcases {
701 tc := tc
702 t.Run(tc.name, func(t *testing.T) {
703
704 svc := &v1.Service{
705 ObjectMeta: metav1.ObjectMeta{
706 Name: fmt.Sprintf("svc-test-%d", i),
707 },
708 Spec: v1.ServiceSpec{
709 Type: tc.serviceType,
710 ClusterIPs: tc.clusterIPs,
711 IPFamilies: tc.ipFamilies,
712 Ports: []v1.ServicePort{
713 {
714 Port: 443,
715 TargetPort: intstr.FromInt32(443),
716 },
717 },
718 },
719 }
720
721 if len(tc.ipFamilyPolicy) > 0 {
722 svc.Spec.IPFamilyPolicy = &tc.ipFamilyPolicy
723 }
724
725 if len(tc.clusterIPs) > 0 {
726 svc.Spec.ClusterIP = tc.clusterIPs[0]
727 }
728
729
730 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
731 if (err != nil) != tc.expectError {
732 t.Errorf("Test failed expected result: %v received %v ", tc.expectError, err)
733 }
734
735 if err != nil {
736 return
737 }
738
739 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
740 if err != nil {
741 t.Errorf("Unexpected error to get the service %s %v", svc.Name, err)
742 }
743
744 if err := validateServiceAndClusterIPFamily(svc, tc.expectedIPFamilies); err != nil {
745 t.Errorf("Unexpected error validating the service %s %v", svc.Name, err)
746 }
747 })
748 }
749 }
750
751
752 func TestCreateServiceDualStackIPv6IPv4(t *testing.T) {
753
754 serviceCIDR := "2001:db8:1::/112"
755 secondaryServiceCIDR := "10.0.0.0/16"
756
757 tCtx := ktesting.Init(t)
758 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
759 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
760 opts.ServiceClusterIPRanges = fmt.Sprintf("%s,%s", serviceCIDR, secondaryServiceCIDR)
761 opts.GenericServerRunOptions.AdvertiseAddress = netutils.ParseIPSloppy("2001:db8::10")
762 },
763 })
764 defer tearDownFn()
765
766
767 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
768 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
769 if err != nil && !apierrors.IsNotFound(err) {
770 return false, err
771 }
772 return !apierrors.IsNotFound(err), nil
773 }); err != nil {
774 t.Fatalf("creating kubernetes service timed out")
775 }
776
777
778 if err := wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) {
779 _, err := client.CoreV1().Endpoints("default").Get(tCtx, "kubernetes", metav1.GetOptions{})
780 if err != nil {
781 t.Logf("error fetching endpoints: %v", err)
782 return false, nil
783 }
784 return true, nil
785 }); err != nil {
786 t.Errorf("server without enabled endpoints failed to register: %v", err)
787 }
788
789 var testcases = []struct {
790 name string
791 serviceType v1.ServiceType
792 clusterIPs []string
793 ipFamilies []v1.IPFamily
794 expectedIPFamilies []v1.IPFamily
795 ipFamilyPolicy v1.IPFamilyPolicy
796 expectError bool
797 }{
798 {
799 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Single Stack",
800 serviceType: v1.ServiceTypeClusterIP,
801 clusterIPs: []string{},
802 ipFamilies: nil,
803 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol},
804 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
805 expectError: false,
806 },
807 {
808 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Prefer Dual Stack",
809 serviceType: v1.ServiceTypeClusterIP,
810 clusterIPs: []string{},
811 ipFamilies: nil,
812 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
813 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
814 expectError: false,
815 },
816 {
817 name: "Type ClusterIP - Server Allocated IP - Default IP Family - Policy Required Dual Stack",
818 serviceType: v1.ServiceTypeClusterIP,
819 clusterIPs: []string{},
820 ipFamilies: nil,
821 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
822 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
823 expectError: false,
824 },
825 {
826 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Single Stack",
827 serviceType: v1.ServiceTypeClusterIP,
828 clusterIPs: []string{},
829 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
830 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
831 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
832 expectError: true,
833 },
834 {
835 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Prefer Dual Stack",
836 serviceType: v1.ServiceTypeClusterIP,
837 clusterIPs: []string{},
838 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
839 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
840 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
841 expectError: false,
842 },
843 {
844 name: "Type ClusterIP - Server Allocated IP - IPv4 Family - Policy Required Dual Stack",
845 serviceType: v1.ServiceTypeClusterIP,
846 clusterIPs: []string{},
847 ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
848 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
849 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
850 expectError: false,
851 },
852 {
853 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Single Stack",
854 serviceType: v1.ServiceTypeClusterIP,
855 clusterIPs: []string{},
856 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
857 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
858 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
859 expectError: true,
860 },
861 {
862 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Prefer Dual Stack",
863 serviceType: v1.ServiceTypeClusterIP,
864 clusterIPs: []string{},
865 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
866 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
867 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
868 expectError: false,
869 },
870 {
871 name: "Type ClusterIP - Server Allocated IP - IPv6 Family - Policy Required Dual Stack",
872 serviceType: v1.ServiceTypeClusterIP,
873 clusterIPs: []string{},
874 ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
875 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
876 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
877 expectError: false,
878 },
879
880 {
881 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Prefer Dual Stack",
882 serviceType: v1.ServiceTypeClusterIP,
883 clusterIPs: []string{},
884 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
885 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
886 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
887 expectError: false,
888 },
889 {
890 name: "Type ClusterIP - Server Allocated IP - IPv4 IPv6 Family - Policy Required Dual Stack",
891 serviceType: v1.ServiceTypeClusterIP,
892 clusterIPs: []string{},
893 ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
894 expectedIPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
895 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
896 expectError: false,
897 },
898 {
899 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Single Stack",
900 serviceType: v1.ServiceTypeClusterIP,
901 clusterIPs: []string{},
902 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
903 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
904 ipFamilyPolicy: v1.IPFamilyPolicySingleStack,
905 expectError: true,
906 },
907 {
908 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Prefer Dual Stack",
909 serviceType: v1.ServiceTypeClusterIP,
910 clusterIPs: []string{},
911 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
912 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
913 ipFamilyPolicy: v1.IPFamilyPolicyPreferDualStack,
914 expectError: false,
915 },
916 {
917 name: "Type ClusterIP - Server Allocated IP - IPv6 IPv4 Family - Policy Required Dual Stack",
918 serviceType: v1.ServiceTypeClusterIP,
919 clusterIPs: []string{},
920 ipFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
921 expectedIPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
922 ipFamilyPolicy: v1.IPFamilyPolicyRequireDualStack,
923 expectError: false,
924 },
925 }
926
927 for i, tc := range testcases {
928 tc := tc
929 t.Run(tc.name, func(t *testing.T) {
930
931 svc := &v1.Service{
932 ObjectMeta: metav1.ObjectMeta{
933 Name: fmt.Sprintf("svc-test-%d", i),
934 },
935 Spec: v1.ServiceSpec{
936 Type: tc.serviceType,
937 ClusterIPs: tc.clusterIPs,
938 IPFamilies: tc.ipFamilies,
939 IPFamilyPolicy: &tc.ipFamilyPolicy,
940 Ports: []v1.ServicePort{
941 {
942 Port: 443,
943 TargetPort: intstr.FromInt32(443),
944 },
945 },
946 },
947 }
948
949
950 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
951 if (err != nil) != tc.expectError {
952 t.Errorf("Test failed expected result: %v received %v ", tc.expectError, err)
953 }
954
955 if err != nil {
956 return
957 }
958
959 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
960 if err != nil {
961 t.Errorf("Unexpected error to get the service %s %v", svc.Name, err)
962 }
963
964 if err := validateServiceAndClusterIPFamily(svc, tc.expectedIPFamilies); err != nil {
965 t.Errorf("Unexpected error validating the service %s %v", svc.Name, err)
966 }
967 })
968 }
969 }
970
971
972 func TestUpgradeDowngrade(t *testing.T) {
973
974 serviceCIDR := "10.0.0.0/16"
975 secondaryServiceCIDR := "2001:db8:1::/112"
976
977 tCtx := ktesting.Init(t)
978 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
979 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
980 opts.ServiceClusterIPRanges = fmt.Sprintf("%s,%s", serviceCIDR, secondaryServiceCIDR)
981 },
982 })
983 defer tearDownFn()
984
985
986 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
987 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
988 if err != nil && !apierrors.IsNotFound(err) {
989 return false, err
990 }
991 return !apierrors.IsNotFound(err), nil
992 }); err != nil {
993 t.Fatalf("creating kubernetes service timed out")
994 }
995
996 upgradeServiceName := "svc-upgrade"
997
998 svc := &v1.Service{
999 ObjectMeta: metav1.ObjectMeta{
1000 Name: upgradeServiceName,
1001 },
1002 Spec: v1.ServiceSpec{
1003 Type: v1.ServiceTypeClusterIP,
1004 Ports: []v1.ServicePort{
1005 {
1006 Port: 443,
1007 TargetPort: intstr.FromInt32(443),
1008 },
1009 },
1010 },
1011 }
1012
1013
1014 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
1015 if err != nil {
1016 t.Fatalf("unexpected error while creating service:%v", err)
1017 }
1018
1019 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1020 if err != nil {
1021 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1022 }
1023
1024 if err := validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol} ); err != nil {
1025 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1026 }
1027
1028
1029 requireDualStack := v1.IPFamilyPolicyRequireDualStack
1030 svc.Spec.IPFamilyPolicy = &requireDualStack
1031 upgraded, err := client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, svc, metav1.UpdateOptions{})
1032 if err != nil {
1033 t.Fatalf("unexpected error upgrading service to dual stack. %v", err)
1034 }
1035 if err := validateServiceAndClusterIPFamily(upgraded, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol} ); err != nil {
1036 t.Fatalf("Unexpected error validating the service(after upgrade) %s %v", svc.Name, err)
1037 }
1038
1039
1040 singleStack := v1.IPFamilyPolicySingleStack
1041 upgraded.Spec.IPFamilyPolicy = &singleStack
1042 upgraded.Spec.ClusterIPs = upgraded.Spec.ClusterIPs[0:1]
1043 upgraded.Spec.IPFamilies = upgraded.Spec.IPFamilies[0:1]
1044 downgraded, err := client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, upgraded, metav1.UpdateOptions{})
1045 if err != nil {
1046 t.Fatalf("unexpected error downgrading service to single stack. %v", err)
1047 }
1048 if err := validateServiceAndClusterIPFamily(downgraded, []v1.IPFamily{v1.IPv4Protocol} ); err != nil {
1049 t.Fatalf("unexpected error validating the service(after downgrade) %s %v", svc.Name, err)
1050 }
1051
1052
1053 downgraded.Spec.IPFamilyPolicy = &requireDualStack
1054 upgradedAgain, err := client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, downgraded, metav1.UpdateOptions{})
1055 if err != nil {
1056 t.Fatalf("unexpected error upgrading service to dual stack. %v", err)
1057 }
1058 if err := validateServiceAndClusterIPFamily(upgradedAgain, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol} ); err != nil {
1059 t.Fatalf("Unexpected error validating the service(after upgrade) %s %v", svc.Name, err)
1060 }
1061
1062 upgradedAgain.Spec.IPFamilyPolicy = &singleStack
1063
1064
1065 downgradedAgain, err := client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, upgradedAgain, metav1.UpdateOptions{})
1066 if err != nil {
1067 t.Fatalf("unexpected error downgrading service to single stack. %v", err)
1068 }
1069 if err := validateServiceAndClusterIPFamily(downgradedAgain, []v1.IPFamily{v1.IPv4Protocol} ); err != nil {
1070 t.Fatalf("unexpected error validating the service(after downgrade) %s %v", svc.Name, err)
1071 }
1072 }
1073
1074
1075
1076 func TestConvertToFromExternalName(t *testing.T) {
1077
1078 serviceCIDR := "10.0.0.0/16"
1079 secondaryServiceCIDR := "2001:db8:1::/112"
1080
1081 tCtx := ktesting.Init(t)
1082 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
1083 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
1084 opts.ServiceClusterIPRanges = fmt.Sprintf("%s,%s", serviceCIDR, secondaryServiceCIDR)
1085 },
1086 })
1087 defer tearDownFn()
1088
1089
1090 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
1091 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
1092 if err != nil && !apierrors.IsNotFound(err) {
1093 return false, err
1094 }
1095 return !apierrors.IsNotFound(err), nil
1096 }); err != nil {
1097 t.Fatalf("creating kubernetes service timed out")
1098 }
1099
1100 serviceName := "svc-ext-name"
1101 svc := &v1.Service{
1102 ObjectMeta: metav1.ObjectMeta{
1103 Name: serviceName,
1104 },
1105 Spec: v1.ServiceSpec{
1106 Type: v1.ServiceTypeClusterIP,
1107 Ports: []v1.ServicePort{
1108 {
1109 Port: 443,
1110 TargetPort: intstr.FromInt32(443),
1111 },
1112 },
1113 },
1114 }
1115
1116
1117 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
1118 if err != nil {
1119 t.Fatalf("unexpected error while creating service:%v", err)
1120 }
1121
1122 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1123 if err != nil {
1124 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1125 }
1126
1127 if err := validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol}); err != nil {
1128 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1129 }
1130
1131
1132 svc.Spec.Type = v1.ServiceTypeExternalName
1133 svc.Spec.ClusterIP = ""
1134 svc.Spec.ExternalName = "something.somewhere"
1135
1136 externalNameSvc, err := client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, svc, metav1.UpdateOptions{})
1137 if err != nil {
1138 t.Fatalf("unexpected error converting service to external name. %v", err)
1139 }
1140
1141 if len(externalNameSvc.Spec.ClusterIPs) > 0 || len(externalNameSvc.Spec.ClusterIP) > 0 || len(externalNameSvc.Spec.IPFamilies) > 0 {
1142 t.Fatalf("unpexpected externalname service with ClusterIPs %v or ClusterIP %v or IPFamilies %v", externalNameSvc.Spec.ClusterIPs, externalNameSvc.Spec.ClusterIP, externalNameSvc.Spec.IPFamilies)
1143 }
1144
1145
1146 externalNameSvc.Spec.Type = v1.ServiceTypeClusterIP
1147 externalNameSvc.Spec.ExternalName = ""
1148 clusterIPSvc, err := client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, externalNameSvc, metav1.UpdateOptions{})
1149 if err != nil {
1150 t.Fatalf("unexpected error converting service to ClusterIP. %v", err)
1151 }
1152 if err := validateServiceAndClusterIPFamily(clusterIPSvc, []v1.IPFamily{v1.IPv4Protocol}); err != nil {
1153 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1154 }
1155 }
1156
1157
1158 func TestPreferDualStack(t *testing.T) {
1159
1160 serviceCIDR := "10.0.0.0/16"
1161 secondaryServiceCIDR := "2001:db8:1::/112"
1162
1163 tCtx := ktesting.Init(t)
1164 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
1165 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
1166 opts.ServiceClusterIPRanges = fmt.Sprintf("%s,%s", serviceCIDR, secondaryServiceCIDR)
1167 },
1168 })
1169 defer tearDownFn()
1170
1171
1172 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
1173 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
1174 if err != nil && !apierrors.IsNotFound(err) {
1175 return false, err
1176 }
1177 return !apierrors.IsNotFound(err), nil
1178 }); err != nil {
1179 t.Fatalf("creating kubernetes service timed out")
1180 }
1181
1182 preferDualStack := v1.IPFamilyPolicyPreferDualStack
1183
1184 serviceName := "svc-upgrade"
1185
1186 svc := &v1.Service{
1187 ObjectMeta: metav1.ObjectMeta{
1188 Name: serviceName,
1189 },
1190 Spec: v1.ServiceSpec{
1191 Type: v1.ServiceTypeClusterIP,
1192 IPFamilyPolicy: &preferDualStack,
1193 Ports: []v1.ServicePort{
1194 {
1195 Port: 443,
1196 TargetPort: intstr.FromInt32(443),
1197 },
1198 },
1199 },
1200 }
1201
1202
1203 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
1204 if err != nil {
1205 t.Fatalf("unexpected error while creating service:%v", err)
1206 }
1207
1208 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1209 if err != nil {
1210 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1211 }
1212
1213 if err := validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}); err != nil {
1214 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1215 }
1216
1217
1218 svc.Spec.Selector = map[string]string{"foo": "bar"}
1219 upgraded, err := client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, svc, metav1.UpdateOptions{})
1220 if err != nil {
1221 t.Fatalf("unexpected error upgrading service to dual stack. %v", err)
1222 }
1223 if err := validateServiceAndClusterIPFamily(upgraded, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}); err != nil {
1224 t.Fatalf("Unexpected error validating the service(after upgrade) %s %v", svc.Name, err)
1225 }
1226 }
1227
1228 type labelsForMergePatch struct {
1229 Labels map[string]string `json:"lables,omitempty"`
1230 }
1231
1232
1233 func TestServiceUpdate(t *testing.T) {
1234
1235 serviceCIDR := "10.0.0.0/16"
1236
1237 tCtx := ktesting.Init(t)
1238 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
1239 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
1240 opts.ServiceClusterIPRanges = serviceCIDR
1241 },
1242 })
1243 defer tearDownFn()
1244
1245
1246 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
1247 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
1248 if err != nil && !apierrors.IsNotFound(err) {
1249 return false, err
1250 }
1251 return !apierrors.IsNotFound(err), nil
1252 }); err != nil {
1253 t.Fatalf("creating kubernetes service timed out")
1254 }
1255
1256 serviceName := "test-service"
1257 svc := &v1.Service{
1258 ObjectMeta: metav1.ObjectMeta{
1259 Name: serviceName,
1260 },
1261 Spec: v1.ServiceSpec{
1262 Type: v1.ServiceTypeClusterIP,
1263 Ports: []v1.ServicePort{
1264 {
1265 Port: 443,
1266 TargetPort: intstr.FromInt32(443),
1267 },
1268 },
1269 },
1270 }
1271
1272
1273 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
1274
1275 if err != nil {
1276 t.Errorf("unexpected error creating service:%v", err)
1277 return
1278 }
1279
1280 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1281 if err != nil {
1282 t.Errorf("Unexpected error to get the service %s %v", svc.Name, err)
1283 }
1284
1285
1286 svc.Labels = map[string]string{"x": "y"}
1287 _, err = client.CoreV1().Services(metav1.NamespaceDefault).Update(tCtx, svc, metav1.UpdateOptions{})
1288 if err != nil {
1289 t.Errorf("Unexpected error updating the service %s %v", svc.Name, err)
1290 }
1291
1292 _, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1293 if err != nil {
1294 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1295 }
1296
1297
1298 labels := labelsForMergePatch{
1299 Labels: map[string]string{"foo": "bar"},
1300 }
1301
1302 patchBytes, err := json.Marshal(&labels)
1303 if err != nil {
1304 t.Fatalf("failed to json.Marshal labels: %v", err)
1305 }
1306
1307 _, err = client.CoreV1().Services(metav1.NamespaceDefault).Patch(tCtx, svc.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
1308 if err != nil {
1309 t.Fatalf("unexpected error patching service using strategic merge patch. %v", err)
1310 }
1311
1312 current, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1313 if err != nil {
1314 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1315 }
1316
1317
1318 toUpdate := current.DeepCopy()
1319 currentJSON, err := json.Marshal(current)
1320 if err != nil {
1321 t.Fatalf("unexpected error marshal current service. %v", err)
1322 }
1323 toUpdate.Labels = map[string]string{"alpha": "bravo"}
1324 toUpdateJSON, err := json.Marshal(toUpdate)
1325 if err != nil {
1326 t.Fatalf("unexpected error marshal toupdate service. %v", err)
1327 }
1328
1329 patchBytes, err = jsonpatch.CreateMergePatch(currentJSON, toUpdateJSON)
1330 if err != nil {
1331 t.Fatalf("unexpected error creating json patch. %v", err)
1332 }
1333
1334 _, err = client.CoreV1().Services(metav1.NamespaceDefault).Patch(tCtx, svc.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{})
1335 if err != nil {
1336 t.Fatalf("unexpected error patching service using merge patch. %v", err)
1337 }
1338
1339
1340 _, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1341 if err != nil {
1342 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1343 }
1344 }
1345
1346
1347 func validateServiceAndClusterIPFamily(svc *v1.Service, expectedIPFamilies []v1.IPFamily) error {
1348
1349 var errstrings []string
1350
1351 if svc.Spec.IPFamilies == nil {
1352 return fmt.Errorf("service ip family nil for service %s/%s", svc.Namespace, svc.Name)
1353 }
1354 if !reflect.DeepEqual(svc.Spec.IPFamilies, expectedIPFamilies) {
1355 return fmt.Errorf("ip families mismatch for service: %s/%s, expected: %s, actual: %s", svc.Namespace, svc.Name, expectedIPFamilies, svc.Spec.IPFamilies)
1356 }
1357
1358 if len(svc.Spec.ClusterIPs) == 0 {
1359 return fmt.Errorf("svc %s is invalid it does not have ClusterIP", svc.Name)
1360 }
1361
1362
1363 if len(svc.Spec.ClusterIPs) > 0 && svc.Spec.ClusterIPs[0] != v1.ClusterIPNone {
1364 if len(svc.Spec.ClusterIPs) != len(svc.Spec.IPFamilies) {
1365 return fmt.Errorf("svc %v is invalid len(ClusterIPs:%v) != len(IPFamilies:%v)", svc.Name, svc.Spec.ClusterIPs, svc.Spec.IPFamilies)
1366 }
1367 }
1368
1369 for j, ip := range svc.Spec.ClusterIPs {
1370
1371 if ip == v1.ClusterIPNone && len(svc.Spec.ClusterIPs) > 1 {
1372 errstrings = append(errstrings, fmt.Sprintf("Error validating Service: %s, None is used with +1 clusterIPs (%v)", svc.Name, svc.Spec.ClusterIPs))
1373 }
1374
1375 if ip == v1.ClusterIPNone {
1376 break
1377 }
1378
1379
1380 if netutils.IsIPv6String(ip) != (expectedIPFamilies[j] == v1.IPv6Protocol) {
1381 errstrings = append(errstrings, fmt.Sprintf("got unexpected service ip %s, should belong to %s ip family", ip, expectedIPFamilies[j]))
1382 }
1383 }
1384
1385 if len(errstrings) > 0 {
1386 errstrings = append(errstrings, fmt.Sprintf("Error validating Service: %s, ClusterIPs: %v Expected IPFamilies %v", svc.Name, svc.Spec.ClusterIPs, expectedIPFamilies))
1387 return fmt.Errorf(strings.Join(errstrings, "\n"))
1388 }
1389
1390 return nil
1391 }
1392
1393 func TestUpgradeServicePreferToDualStack(t *testing.T) {
1394 sharedEtcd := framework.SharedEtcd()
1395
1396 tCtx := ktesting.Init(t)
1397
1398
1399 serviceCIDR := "192.168.0.0/24"
1400
1401 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
1402 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
1403 opts.Etcd.StorageConfig = *sharedEtcd
1404 opts.ServiceClusterIPRanges = serviceCIDR
1405 },
1406 })
1407
1408
1409 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
1410 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
1411 if err != nil && !apierrors.IsNotFound(err) {
1412 return false, err
1413 }
1414 return !apierrors.IsNotFound(err), nil
1415 }); err != nil {
1416 t.Fatalf("creating kubernetes service timed out")
1417 }
1418
1419 preferDualStack := v1.IPFamilyPolicyPreferDualStack
1420 svc := &v1.Service{
1421 ObjectMeta: metav1.ObjectMeta{
1422 Name: "svc-prefer-dual",
1423 },
1424 Spec: v1.ServiceSpec{
1425 Type: v1.ServiceTypeClusterIP,
1426 ClusterIPs: nil,
1427 IPFamilies: nil,
1428 IPFamilyPolicy: &preferDualStack,
1429 Ports: []v1.ServicePort{
1430 {
1431 Name: "svc-port-1",
1432 Port: 443,
1433 TargetPort: intstr.IntOrString{IntVal: 443},
1434 Protocol: "TCP",
1435 },
1436 },
1437 },
1438 }
1439
1440
1441 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
1442 if err != nil {
1443 t.Fatalf("Unexpected error: %v", err)
1444 }
1445
1446 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1447 if err != nil {
1448 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1449 }
1450 if err := validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol}); err != nil {
1451 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1452 }
1453
1454
1455 tearDownFn()
1456
1457 secondaryServiceCIDR := "2001:db8:1::/112"
1458
1459 client, _, tearDownFn = framework.StartTestServer(tCtx, t, framework.TestServerSetup{
1460 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
1461 opts.Etcd.StorageConfig = *sharedEtcd
1462 opts.ServiceClusterIPRanges = fmt.Sprintf("%s,%s", serviceCIDR, secondaryServiceCIDR)
1463 },
1464 })
1465 defer tearDownFn()
1466
1467
1468 if err = wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
1469 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
1470 if err != nil && !apierrors.IsNotFound(err) {
1471 return false, err
1472 }
1473 return !apierrors.IsNotFound(err), nil
1474 }); err != nil {
1475 t.Fatalf("creating kubernetes service timed out")
1476 }
1477
1478 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1479 if err != nil {
1480 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1481 }
1482
1483 if err = validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol}); err != nil {
1484 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1485 }
1486 }
1487
1488 func TestDowngradeServicePreferToDualStack(t *testing.T) {
1489 sharedEtcd := framework.SharedEtcd()
1490
1491 tCtx := ktesting.Init(t)
1492
1493
1494 serviceCIDR := "192.168.0.0/24"
1495 secondaryServiceCIDR := "2001:db8:1::/112"
1496
1497 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
1498 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
1499 opts.Etcd.StorageConfig = *sharedEtcd
1500 opts.ServiceClusterIPRanges = fmt.Sprintf("%s,%s", serviceCIDR, secondaryServiceCIDR)
1501 },
1502 })
1503
1504
1505 if err := wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
1506 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
1507 if err != nil && !apierrors.IsNotFound(err) {
1508 return false, err
1509 }
1510 return !apierrors.IsNotFound(err), nil
1511 }); err != nil {
1512 t.Fatalf("creating kubernetes service timed out")
1513 }
1514 preferDualStack := v1.IPFamilyPolicyPreferDualStack
1515 svc := &v1.Service{
1516 ObjectMeta: metav1.ObjectMeta{
1517 Name: "svc-prefer-dual01",
1518 },
1519 Spec: v1.ServiceSpec{
1520 Type: v1.ServiceTypeClusterIP,
1521 ClusterIPs: nil,
1522 IPFamilies: nil,
1523 IPFamilyPolicy: &preferDualStack,
1524 Ports: []v1.ServicePort{
1525 {
1526 Name: "svc-port-1",
1527 Port: 443,
1528 TargetPort: intstr.IntOrString{IntVal: 443},
1529 Protocol: "TCP",
1530 },
1531 },
1532 },
1533 }
1534
1535 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(tCtx, svc, metav1.CreateOptions{})
1536 if err != nil {
1537 t.Fatalf("Unexpected error: %v", err)
1538 }
1539
1540 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1541 if err != nil {
1542 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1543 }
1544 if err := validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}); err != nil {
1545 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1546 }
1547
1548 tearDownFn()
1549
1550
1551 client, _, tearDownFn = framework.StartTestServer(tCtx, t, framework.TestServerSetup{
1552 ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
1553 opts.Etcd.StorageConfig = *sharedEtcd
1554 opts.ServiceClusterIPRanges = serviceCIDR
1555 },
1556 })
1557 defer tearDownFn()
1558
1559
1560 if err = wait.Poll(250*time.Millisecond, time.Minute, func() (bool, error) {
1561 _, err := client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, "kubernetes", metav1.GetOptions{})
1562 if err != nil && !apierrors.IsNotFound(err) {
1563 return false, err
1564 }
1565 return !apierrors.IsNotFound(err), nil
1566 }); err != nil {
1567 t.Fatalf("creating kubernetes service timed out")
1568 }
1569
1570 svc, err = client.CoreV1().Services(metav1.NamespaceDefault).Get(tCtx, svc.Name, metav1.GetOptions{})
1571 if err != nil {
1572 t.Fatalf("Unexpected error to get the service %s %v", svc.Name, err)
1573 }
1574
1575 if err = validateServiceAndClusterIPFamily(svc, []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}); err != nil {
1576 t.Fatalf("Unexpected error validating the service %s %v", svc.Name, err)
1577 }
1578 }
1579
1580 type serviceMergePatch struct {
1581 Spec specMergePatch `json:"spec,omitempty"`
1582 }
1583 type specMergePatch struct {
1584 Type v1.ServiceType `json:"type,omitempty"`
1585 ExternalName string `json:"externalName,omitempty"`
1586 }
1587
1588
1589 func Test_ServiceChangeTypeHeadlessToExternalNameWithPatch(t *testing.T) {
1590 tCtx := ktesting.Init(t)
1591 client, _, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{})
1592 defer tearDownFn()
1593
1594 ns := framework.CreateNamespaceOrDie(client, "test-service-allocate-node-ports", t)
1595 defer framework.DeleteNamespaceOrDie(client, ns, t)
1596
1597 service := &v1.Service{
1598 ObjectMeta: metav1.ObjectMeta{
1599 Name: "test-123",
1600 },
1601 Spec: v1.ServiceSpec{
1602 Type: v1.ServiceTypeClusterIP,
1603 ClusterIP: "None",
1604 Selector: map[string]string{"foo": "bar"},
1605 },
1606 }
1607
1608 var err error
1609 service, err = client.CoreV1().Services(ns.Name).Create(tCtx, service, metav1.CreateOptions{})
1610 if err != nil {
1611 t.Fatalf("Error creating test service: %v", err)
1612 }
1613
1614 serviceMergePatch := serviceMergePatch{
1615 Spec: specMergePatch{
1616 Type: v1.ServiceTypeExternalName,
1617 ExternalName: "foo.bar",
1618 },
1619 }
1620 patchBytes, err := json.Marshal(&serviceMergePatch)
1621 if err != nil {
1622 t.Fatalf("failed to json.Marshal ports: %v", err)
1623 }
1624
1625 _, err = client.CoreV1().Services(ns.Name).Patch(tCtx, service.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
1626 if err != nil {
1627 t.Fatalf("unexpected error patching service using strategic merge patch. %v", err)
1628 }
1629 }
1630
View as plain text