1
16
17 package expose
18
19 import (
20 "net/http"
21 "strings"
22 "testing"
23
24 "github.com/stretchr/testify/require"
25 corev1 "k8s.io/api/core/v1"
26 apiequality "k8s.io/apimachinery/pkg/api/equality"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apimachinery/pkg/util/intstr"
31 "k8s.io/cli-runtime/pkg/genericiooptions"
32 "k8s.io/client-go/rest/fake"
33 cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
34 "k8s.io/kubectl/pkg/scheme"
35 )
36
37 func TestRunExposeService(t *testing.T) {
38 tests := []struct {
39 name string
40 args []string
41 ns string
42 calls map[string]string
43 input runtime.Object
44 flags map[string]string
45 output runtime.Object
46 expected string
47 status int
48 }{
49 {
50 name: "expose-service-from-service-no-selector-defined",
51 args: []string{"service", "baz"},
52 ns: "test",
53 calls: map[string]string{
54 "GET": "/namespaces/test/services/baz",
55 "POST": "/namespaces/test/services",
56 },
57 input: &corev1.Service{
58 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
59 Spec: corev1.ServiceSpec{
60 Selector: map[string]string{"app": "go"},
61 },
62 },
63 flags: map[string]string{"protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test"},
64 output: &corev1.Service{
65 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
66 Spec: corev1.ServiceSpec{
67 Ports: []corev1.ServicePort{
68 {
69 Protocol: corev1.ProtocolUDP,
70 Port: 14,
71 TargetPort: intstr.FromInt32(14),
72 },
73 },
74 Selector: map[string]string{"app": "go"},
75 },
76 },
77 expected: "service/foo exposed",
78 status: 200,
79 },
80 {
81 name: "expose-service-from-service",
82 args: []string{"service", "baz"},
83 ns: "test",
84 calls: map[string]string{
85 "GET": "/namespaces/test/services/baz",
86 "POST": "/namespaces/test/services",
87 },
88 input: &corev1.Service{
89 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
90 Spec: corev1.ServiceSpec{
91 Selector: map[string]string{"app": "go"},
92 },
93 },
94 flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test"},
95 output: &corev1.Service{
96 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
97 Spec: corev1.ServiceSpec{
98 Ports: []corev1.ServicePort{
99 {
100 Protocol: corev1.ProtocolUDP,
101 Port: 14,
102 TargetPort: intstr.FromInt32(14),
103 },
104 },
105 Selector: map[string]string{"func": "stream"},
106 },
107 },
108 expected: "service/foo exposed",
109 status: 200,
110 },
111 {
112 name: "no-name-passed-from-the-cli",
113 args: []string{"service", "mayor"},
114 ns: "default",
115 calls: map[string]string{
116 "GET": "/namespaces/default/services/mayor",
117 "POST": "/namespaces/default/services",
118 },
119 input: &corev1.Service{
120 ObjectMeta: metav1.ObjectMeta{Name: "mayor", Namespace: "default", ResourceVersion: "12"},
121 Spec: corev1.ServiceSpec{
122 Selector: map[string]string{"run": "this"},
123 },
124 },
125
126 flags: map[string]string{"selector": "run=this", "port": "80", "labels": "runas=amayor"},
127 output: &corev1.Service{
128 ObjectMeta: metav1.ObjectMeta{Name: "mayor", Namespace: "", Labels: map[string]string{"runas": "amayor"}},
129 Spec: corev1.ServiceSpec{
130 Ports: []corev1.ServicePort{
131 {
132 Protocol: corev1.ProtocolTCP,
133 Port: 80,
134 TargetPort: intstr.FromInt32(80),
135 },
136 },
137 Selector: map[string]string{"run": "this"},
138 },
139 },
140 expected: "service/mayor exposed",
141 status: 200,
142 },
143 {
144 name: "expose-service",
145 args: []string{"service", "baz"},
146 ns: "test",
147 calls: map[string]string{
148 "GET": "/namespaces/test/services/baz",
149 "POST": "/namespaces/test/services",
150 },
151 input: &corev1.Service{
152 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
153 Spec: corev1.ServiceSpec{
154 Selector: map[string]string{"app": "go"},
155 },
156 },
157 flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "type": "LoadBalancer", "dry-run": "client"},
158 output: &corev1.Service{
159 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
160 Spec: corev1.ServiceSpec{
161 Ports: []corev1.ServicePort{
162 {
163 Protocol: corev1.ProtocolUDP,
164 Port: 14,
165 TargetPort: intstr.FromInt32(14),
166 },
167 },
168 Selector: map[string]string{"func": "stream"},
169 Type: corev1.ServiceTypeLoadBalancer,
170 },
171 },
172 expected: "service/foo exposed (dry run)",
173 status: 200,
174 },
175 {
176 name: "expose-affinity-service",
177 args: []string{"service", "baz"},
178 ns: "test",
179 calls: map[string]string{
180 "GET": "/namespaces/test/services/baz",
181 "POST": "/namespaces/test/services",
182 },
183 input: &corev1.Service{
184 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
185 Spec: corev1.ServiceSpec{
186 Selector: map[string]string{"app": "go"},
187 },
188 },
189 flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "type": "LoadBalancer", "session-affinity": "ClientIP", "dry-run": "client"},
190 output: &corev1.Service{
191 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
192 Spec: corev1.ServiceSpec{
193 Ports: []corev1.ServicePort{
194 {
195 Protocol: corev1.ProtocolUDP,
196 Port: 14,
197 TargetPort: intstr.FromInt32(14),
198 },
199 },
200 Selector: map[string]string{"func": "stream"},
201 Type: corev1.ServiceTypeLoadBalancer,
202 SessionAffinity: corev1.ServiceAffinityClientIP,
203 },
204 },
205 expected: "service/foo exposed (dry run)",
206 status: 200,
207 },
208 {
209 name: "expose-service-cluster-ip",
210 args: []string{"service", "baz"},
211 ns: "test",
212 calls: map[string]string{
213 "GET": "/namespaces/test/services/baz",
214 "POST": "/namespaces/test/services",
215 },
216 input: &corev1.Service{
217 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
218 Spec: corev1.ServiceSpec{
219 Selector: map[string]string{"app": "go"},
220 },
221 },
222 flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "cluster-ip": "10.10.10.10", "dry-run": "client"},
223 output: &corev1.Service{
224 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
225 Spec: corev1.ServiceSpec{
226 Ports: []corev1.ServicePort{
227 {
228 Protocol: corev1.ProtocolUDP,
229 Port: 14,
230 TargetPort: intstr.FromInt32(14),
231 },
232 },
233 Selector: map[string]string{"func": "stream"},
234 ClusterIP: "10.10.10.10",
235 },
236 },
237 expected: "service/foo exposed (dry run)",
238 status: 200,
239 },
240 {
241 name: "expose-headless-service",
242 args: []string{"service", "baz"},
243 ns: "test",
244 calls: map[string]string{
245 "GET": "/namespaces/test/services/baz",
246 "POST": "/namespaces/test/services",
247 },
248 input: &corev1.Service{
249 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
250 Spec: corev1.ServiceSpec{
251 Selector: map[string]string{"app": "go"},
252 },
253 },
254 flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "cluster-ip": "None", "dry-run": "client"},
255 output: &corev1.Service{
256 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
257 Spec: corev1.ServiceSpec{
258 Ports: []corev1.ServicePort{
259 {
260 Protocol: corev1.ProtocolUDP,
261 Port: 14,
262 TargetPort: intstr.FromInt32(14),
263 },
264 },
265 Selector: map[string]string{"func": "stream"},
266 ClusterIP: corev1.ClusterIPNone,
267 },
268 },
269 expected: "service/foo exposed (dry run)",
270 status: 200,
271 },
272 {
273 name: "expose-headless-service-no-port",
274 args: []string{"service", "baz"},
275 ns: "test",
276 calls: map[string]string{
277 "GET": "/namespaces/test/services/baz",
278 "POST": "/namespaces/test/services",
279 },
280 input: &corev1.Service{
281 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
282 Spec: corev1.ServiceSpec{
283 Selector: map[string]string{"app": "go"},
284 },
285 },
286 flags: map[string]string{"selector": "func=stream", "name": "foo", "labels": "svc=test", "cluster-ip": "None", "dry-run": "client"},
287 output: &corev1.Service{
288 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
289 Spec: corev1.ServiceSpec{
290 Ports: []corev1.ServicePort{},
291 Selector: map[string]string{"func": "stream"},
292 ClusterIP: corev1.ClusterIPNone,
293 },
294 },
295 expected: "service/foo exposed (dry run)",
296 status: 200,
297 },
298 {
299 name: "expose-from-file",
300 args: []string{},
301 ns: "test",
302 calls: map[string]string{
303 "GET": "/namespaces/test/services/redis-master",
304 "POST": "/namespaces/test/services",
305 },
306 input: &corev1.Service{
307 ObjectMeta: metav1.ObjectMeta{Name: "redis-master", Namespace: "test", ResourceVersion: "12"},
308 Spec: corev1.ServiceSpec{
309 Selector: map[string]string{"app": "go"},
310 },
311 },
312 flags: map[string]string{"filename": "../../../testdata/redis-master-service.yaml", "selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "dry-run": "client"},
313 output: &corev1.Service{
314 ObjectMeta: metav1.ObjectMeta{Name: "foo", Labels: map[string]string{"svc": "test"}},
315 Spec: corev1.ServiceSpec{
316 Ports: []corev1.ServicePort{
317 {
318 Protocol: corev1.ProtocolUDP,
319 Port: 14,
320 TargetPort: intstr.FromInt32(14),
321 },
322 },
323 Selector: map[string]string{"func": "stream"},
324 },
325 },
326 expected: "service/foo exposed (dry run)",
327 status: 200,
328 },
329 {
330 name: "truncate-name",
331 args: []string{"pod", "a-name-that-is-toooo-big-for-a-service-because-it-can-only-handle-63-characters"},
332 ns: "test",
333 calls: map[string]string{
334 "GET": "/namespaces/test/pods/a-name-that-is-toooo-big-for-a-service-because-it-can-only-handle-63-characters",
335 "POST": "/namespaces/test/services",
336 },
337 input: &corev1.Pod{
338 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
339 },
340 flags: map[string]string{"selector": "svc=frompod", "port": "90", "labels": "svc=frompod", "generator": "service/v2"},
341 output: &corev1.Service{
342 ObjectMeta: metav1.ObjectMeta{Name: "a-name-that-is-toooo-big-for-a-service-because-it-can-only-handle-63-characters"[:63], Namespace: "", Labels: map[string]string{"svc": "frompod"}},
343 Spec: corev1.ServiceSpec{
344 Ports: []corev1.ServicePort{
345 {
346 Protocol: corev1.ProtocolTCP,
347 Port: 90,
348 TargetPort: intstr.FromInt32(90),
349 },
350 },
351 Selector: map[string]string{"svc": "frompod"},
352 },
353 },
354 expected: "service/a-name-that-is-toooo-big-for-a-service-because-it-can-only-hand exposed",
355 status: 200,
356 },
357 {
358 name: "expose-multiport-object",
359 args: []string{"service", "foo"},
360 ns: "test",
361 calls: map[string]string{
362 "GET": "/namespaces/test/services/foo",
363 "POST": "/namespaces/test/services",
364 },
365 input: &corev1.Service{
366 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "multiport"}},
367 Spec: corev1.ServiceSpec{
368 Ports: []corev1.ServicePort{
369 {
370 Protocol: corev1.ProtocolTCP,
371 Port: 80,
372 TargetPort: intstr.FromInt32(80),
373 },
374 {
375 Protocol: corev1.ProtocolTCP,
376 Port: 443,
377 TargetPort: intstr.FromInt32(443),
378 },
379 },
380 },
381 },
382 flags: map[string]string{"selector": "svc=fromfoo", "generator": "service/v2", "name": "fromfoo", "dry-run": "client"},
383 output: &corev1.Service{
384 ObjectMeta: metav1.ObjectMeta{Name: "fromfoo", Namespace: "", Labels: map[string]string{"svc": "multiport"}},
385 Spec: corev1.ServiceSpec{
386 Ports: []corev1.ServicePort{
387 {
388 Name: "port-1",
389 Protocol: corev1.ProtocolTCP,
390 Port: 80,
391 TargetPort: intstr.FromInt32(80),
392 },
393 {
394 Name: "port-2",
395 Protocol: corev1.ProtocolTCP,
396 Port: 443,
397 TargetPort: intstr.FromInt32(443),
398 },
399 },
400 Selector: map[string]string{"svc": "fromfoo"},
401 },
402 },
403 expected: "service/fromfoo exposed (dry run)",
404 status: 200,
405 },
406 {
407 name: "expose-multiprotocol-object",
408 args: []string{"service", "foo"},
409 ns: "test",
410 calls: map[string]string{
411 "GET": "/namespaces/test/services/foo",
412 "POST": "/namespaces/test/services",
413 },
414 input: &corev1.Service{
415 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "multiport"}},
416 Spec: corev1.ServiceSpec{
417 Ports: []corev1.ServicePort{
418 {
419 Protocol: corev1.ProtocolTCP,
420 Port: 80,
421 TargetPort: intstr.FromInt32(80),
422 },
423 {
424 Protocol: corev1.ProtocolUDP,
425 Port: 8080,
426 TargetPort: intstr.FromInt32(8080),
427 },
428 {
429 Protocol: corev1.ProtocolUDP,
430 Port: 8081,
431 TargetPort: intstr.FromInt32(8081),
432 },
433 {
434 Protocol: corev1.ProtocolSCTP,
435 Port: 8082,
436 TargetPort: intstr.FromInt32(8082),
437 },
438 },
439 },
440 },
441 flags: map[string]string{"selector": "svc=fromfoo", "generator": "service/v2", "name": "fromfoo", "dry-run": "client"},
442 output: &corev1.Service{
443 ObjectMeta: metav1.ObjectMeta{Name: "fromfoo", Namespace: "", Labels: map[string]string{"svc": "multiport"}},
444 Spec: corev1.ServiceSpec{
445 Ports: []corev1.ServicePort{
446 {
447 Name: "port-1",
448 Protocol: corev1.ProtocolTCP,
449 Port: 80,
450 TargetPort: intstr.FromInt32(80),
451 },
452 {
453 Name: "port-2",
454 Protocol: corev1.ProtocolUDP,
455 Port: 8080,
456 TargetPort: intstr.FromInt32(8080),
457 },
458 {
459 Name: "port-3",
460 Protocol: corev1.ProtocolUDP,
461 Port: 8081,
462 TargetPort: intstr.FromInt32(8081),
463 },
464 {
465 Name: "port-4",
466 Protocol: corev1.ProtocolSCTP,
467 Port: 8082,
468 TargetPort: intstr.FromInt32(8082),
469 },
470 },
471 Selector: map[string]string{"svc": "fromfoo"},
472 },
473 },
474 expected: "service/fromfoo exposed (dry run)",
475 status: 200,
476 },
477 {
478 name: "expose-service-from-service-no-selector-defined-sctp",
479 args: []string{"service", "baz"},
480 ns: "test",
481 calls: map[string]string{
482 "GET": "/namespaces/test/services/baz",
483 "POST": "/namespaces/test/services",
484 },
485 input: &corev1.Service{
486 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
487 Spec: corev1.ServiceSpec{
488 Selector: map[string]string{"app": "go"},
489 },
490 },
491 flags: map[string]string{"protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test"},
492 output: &corev1.Service{
493 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
494 Spec: corev1.ServiceSpec{
495 Ports: []corev1.ServicePort{
496 {
497 Protocol: corev1.ProtocolSCTP,
498 Port: 14,
499 TargetPort: intstr.FromInt32(14),
500 },
501 },
502 Selector: map[string]string{"app": "go"},
503 },
504 },
505 expected: "service/foo exposed",
506 status: 200,
507 },
508 {
509 name: "expose-service-from-service-sctp",
510 args: []string{"service", "baz"},
511 ns: "test",
512 calls: map[string]string{
513 "GET": "/namespaces/test/services/baz",
514 "POST": "/namespaces/test/services",
515 },
516 input: &corev1.Service{
517 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
518 Spec: corev1.ServiceSpec{
519 Selector: map[string]string{"app": "go"},
520 },
521 },
522 flags: map[string]string{"selector": "func=stream", "protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test"},
523 output: &corev1.Service{
524 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
525 Spec: corev1.ServiceSpec{
526 Ports: []corev1.ServicePort{
527 {
528 Protocol: corev1.ProtocolSCTP,
529 Port: 14,
530 TargetPort: intstr.FromInt32(14),
531 },
532 },
533 Selector: map[string]string{"func": "stream"},
534 },
535 },
536 expected: "service/foo exposed",
537 status: 200,
538 },
539 {
540 name: "expose-service-cluster-ip-sctp",
541 args: []string{"service", "baz"},
542 ns: "test",
543 calls: map[string]string{
544 "GET": "/namespaces/test/services/baz",
545 "POST": "/namespaces/test/services",
546 },
547 input: &corev1.Service{
548 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
549 Spec: corev1.ServiceSpec{
550 Selector: map[string]string{"app": "go"},
551 },
552 },
553 flags: map[string]string{"selector": "func=stream", "protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test", "cluster-ip": "10.10.10.10", "dry-run": "client"},
554 output: &corev1.Service{
555 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
556 Spec: corev1.ServiceSpec{
557 Ports: []corev1.ServicePort{
558 {
559 Protocol: corev1.ProtocolSCTP,
560 Port: 14,
561 TargetPort: intstr.FromInt32(14),
562 },
563 },
564 Selector: map[string]string{"func": "stream"},
565 ClusterIP: "10.10.10.10",
566 },
567 },
568 expected: "service/foo exposed (dry run)",
569 status: 200,
570 },
571 {
572 name: "expose-headless-service-sctp",
573 args: []string{"service", "baz"},
574 ns: "test",
575 calls: map[string]string{
576 "GET": "/namespaces/test/services/baz",
577 "POST": "/namespaces/test/services",
578 },
579 input: &corev1.Service{
580 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
581 Spec: corev1.ServiceSpec{
582 Selector: map[string]string{"app": "go"},
583 },
584 },
585 flags: map[string]string{"selector": "func=stream", "protocol": "SCTP", "port": "14", "name": "foo", "labels": "svc=test", "cluster-ip": "None", "dry-run": "client"},
586 output: &corev1.Service{
587 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
588 Spec: corev1.ServiceSpec{
589 Ports: []corev1.ServicePort{
590 {
591 Protocol: corev1.ProtocolSCTP,
592 Port: 14,
593 TargetPort: intstr.FromInt32(14),
594 },
595 },
596 Selector: map[string]string{"func": "stream"},
597 ClusterIP: corev1.ClusterIPNone,
598 },
599 },
600 expected: "service/foo exposed (dry run)",
601 status: 200,
602 },
603 {
604 name: "namespace-yaml",
605 args: []string{"service", "baz"},
606 ns: "testns",
607 calls: map[string]string{
608 "GET": "/namespaces/testns/services/baz",
609 "POST": "/namespaces/testns/services",
610 },
611 input: &corev1.Service{
612 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "testns", ResourceVersion: "12"},
613 Spec: corev1.ServiceSpec{
614 Selector: map[string]string{"app": "go"},
615 },
616 },
617 flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "type": "LoadBalancer", "dry-run": "client", "output": "yaml"},
618 output: &corev1.Service{
619 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
620 Spec: corev1.ServiceSpec{
621 Ports: []corev1.ServicePort{
622 {
623 Protocol: corev1.ProtocolUDP,
624 Port: 14,
625 TargetPort: intstr.FromInt32(14),
626 },
627 },
628 Selector: map[string]string{"func": "stream"},
629 Type: corev1.ServiceTypeLoadBalancer,
630 },
631 },
632 expected: "namespace: testns",
633 status: 200,
634 },
635 }
636
637 for _, test := range tests {
638 t.Run(test.name, func(t *testing.T) {
639 tf := cmdtesting.NewTestFactory().WithNamespace(test.ns)
640 defer tf.Cleanup()
641
642 codec := runtime.NewCodec(scheme.DefaultJSONEncoder(), scheme.Codecs.UniversalDecoder(scheme.Scheme.PrioritizedVersionsAllGroups()...))
643 ns := scheme.Codecs.WithoutConversion()
644
645 tf.Client = &fake.RESTClient{
646 GroupVersion: schema.GroupVersion{Version: "v1"},
647 NegotiatedSerializer: ns,
648 Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
649 switch p, m := req.URL.Path, req.Method; {
650 case p == test.calls[m] && m == "GET":
651 return &http.Response{StatusCode: test.status, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, test.input)}, nil
652 case p == test.calls[m] && m == "POST":
653 return &http.Response{StatusCode: test.status, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, test.output)}, nil
654 default:
655 t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
656 return nil, nil
657 }
658 }),
659 }
660
661 ioStreams, _, buf, _ := genericiooptions.NewTestIOStreams()
662 cmd := NewCmdExposeService(tf, ioStreams)
663 cmd.SetOut(buf)
664 cmd.SetErr(buf)
665 for flag, value := range test.flags {
666 cmd.Flags().Set(flag, value)
667 }
668 cmd.Run(cmd, test.args)
669
670 out := buf.String()
671
672 if test.expected == "" {
673 t.Errorf("%s: Invalid test case. Specify expected result.\n", test.name)
674 }
675
676 if !strings.Contains(out, test.expected) {
677 t.Errorf("%s: Unexpected output! Expected\n%s\ngot\n%s", test.name, test.expected, out)
678 }
679 })
680 }
681 }
682
683 func TestExposeOverride(t *testing.T) {
684 tests := []struct {
685 name string
686 overrides string
687 overrideType string
688 expected string
689 }{
690 {
691 name: "expose with merge override type should replace the entire spec",
692 overrides: `{"spec": {"ports": [{"protocol": "TCP", "port": 1111, "targetPort": 2222}]}, "selector": {"app": "go"}}`,
693 overrideType: "merge",
694 expected: `apiVersion: v1
695 kind: Service
696 metadata:
697 creationTimestamp: null
698 labels:
699 svc: test
700 name: foo
701 namespace: test
702 spec:
703 ports:
704 - port: 1111
705 protocol: TCP
706 targetPort: 2222
707 selector:
708 app: go
709 status:
710 loadBalancer: {}
711 `,
712 },
713 {
714 name: "expose with strategic override type should add port before existing port",
715 overrides: `{"spec": {"ports": [{"protocol": "TCP", "port": 1111, "targetPort": 2222}]}}`,
716 overrideType: "strategic",
717 expected: `apiVersion: v1
718 kind: Service
719 metadata:
720 creationTimestamp: null
721 labels:
722 svc: test
723 name: foo
724 namespace: test
725 spec:
726 ports:
727 - port: 1111
728 protocol: TCP
729 targetPort: 2222
730 - port: 14
731 protocol: UDP
732 targetPort: 14
733 selector:
734 app: go
735 status:
736 loadBalancer: {}
737 `,
738 },
739 {
740 name: "expose with json override type should add port before existing port",
741 overrides: `[
742 {"op": "add", "path": "/spec/ports/0", "value": {"port": 1111, "protocol": "TCP", "targetPort": 2222}}
743 ]`,
744 overrideType: "json",
745 expected: `apiVersion: v1
746 kind: Service
747 metadata:
748 creationTimestamp: null
749 labels:
750 svc: test
751 name: foo
752 namespace: test
753 spec:
754 ports:
755 - port: 1111
756 protocol: TCP
757 targetPort: 2222
758 - port: 14
759 protocol: UDP
760 targetPort: 14
761 selector:
762 app: go
763 status:
764 loadBalancer: {}
765 `,
766 },
767 {
768 name: "expose with json override type should add port after existing port",
769 overrides: `[
770 {"op": "add", "path": "/spec/ports/1", "value": {"port": 1111, "protocol": "TCP", "targetPort": 2222}}
771 ]`,
772 overrideType: "json",
773 expected: `apiVersion: v1
774 kind: Service
775 metadata:
776 creationTimestamp: null
777 labels:
778 svc: test
779 name: foo
780 namespace: test
781 spec:
782 ports:
783 - port: 14
784 protocol: UDP
785 targetPort: 14
786 - port: 1111
787 protocol: TCP
788 targetPort: 2222
789 selector:
790 app: go
791 status:
792 loadBalancer: {}
793 `,
794 },
795 }
796 for _, test := range tests {
797 t.Run(test.name, func(t *testing.T) {
798 tf := cmdtesting.NewTestFactory().WithNamespace("test")
799 defer tf.Cleanup()
800
801 codec := runtime.NewCodec(scheme.DefaultJSONEncoder(), scheme.Codecs.UniversalDecoder(scheme.Scheme.PrioritizedVersionsAllGroups()...))
802 ns := scheme.Codecs.WithoutConversion()
803
804 tf.Client = &fake.RESTClient{
805 GroupVersion: schema.GroupVersion{Version: "v1"},
806 NegotiatedSerializer: ns,
807 Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
808 switch p, m := req.URL.Path, req.Method; {
809 case p == "/namespaces/test/services/baz" && m == "GET":
810 return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.Service{
811 ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
812 Spec: corev1.ServiceSpec{
813 Selector: map[string]string{"app": "go"},
814 },
815 })}, nil
816 case p == "/namespaces/test/services" && m == "POST":
817 return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.Service{
818 ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "", Labels: map[string]string{"svc": "test"}},
819 Spec: corev1.ServiceSpec{
820 Ports: []corev1.ServicePort{
821 {
822 Protocol: corev1.ProtocolUDP,
823 Port: 14,
824 TargetPort: intstr.FromInt32(14),
825 },
826 },
827 Selector: map[string]string{"app": "go"},
828 },
829 })}, nil
830 default:
831 t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
832 return nil, nil
833 }
834 }),
835 }
836
837 ioStreams, _, buf, _ := genericiooptions.NewTestIOStreams()
838 cmd := NewCmdExposeService(tf, ioStreams)
839 cmd.SetOut(buf)
840 cmd.Flags().Set("protocol", "UDP")
841 cmd.Flags().Set("port", "14")
842 cmd.Flags().Set("name", "foo")
843 cmd.Flags().Set("labels", "svc=test")
844 cmd.Flags().Set("dry-run", "client")
845 cmd.Flags().Set("overrides", test.overrides)
846 cmd.Flags().Set("override-type", test.overrideType)
847 cmd.Flags().Set("output", "yaml")
848 cmd.Run(cmd, []string{"service", "baz"})
849
850 out := buf.String()
851
852 if test.expected == "" {
853 t.Errorf("%s: Invalid test case. Specify expected result.\n", test.name)
854 }
855
856 if !strings.Contains(out, test.expected) {
857 t.Errorf("%s: Unexpected output! Expected\n%s\ngot\n%s", test.name, test.expected, out)
858 }
859 })
860 }
861 }
862
863 func TestGenerateService(t *testing.T) {
864 tests := map[string]struct {
865 selector string
866 name string
867 port string
868 protocol string
869 protocols string
870 targetPort string
871 clusterIP string
872 labels string
873 externalIP string
874 serviceType string
875 sessionAffinity string
876 setup func(t *testing.T, exposeServiceOptions *ExposeServiceOptions) func()
877
878 expected *corev1.Service
879 expectErr string
880 }{
881 "test1": {
882 selector: "foo=bar,baz=blah",
883 name: "test",
884 port: "80",
885 protocol: "TCP",
886 targetPort: "1234",
887 expected: &corev1.Service{
888 ObjectMeta: metav1.ObjectMeta{
889 Name: "test",
890 },
891 Spec: corev1.ServiceSpec{
892 Selector: map[string]string{
893 "foo": "bar",
894 "baz": "blah",
895 },
896 Ports: []corev1.ServicePort{
897 {
898 Port: 80,
899 Protocol: "TCP",
900 TargetPort: intstr.FromInt32(1234),
901 },
902 },
903 },
904 },
905 },
906 "test2": {
907 selector: "foo=bar,baz=blah",
908 name: "test",
909 port: "80",
910 protocol: "UDP",
911 targetPort: "foobar",
912 expected: &corev1.Service{
913 ObjectMeta: metav1.ObjectMeta{
914 Name: "test",
915 },
916 Spec: corev1.ServiceSpec{
917 Selector: map[string]string{
918 "foo": "bar",
919 "baz": "blah",
920 },
921 Ports: []corev1.ServicePort{
922 {
923 Port: 80,
924 Protocol: "UDP",
925 TargetPort: intstr.FromString("foobar"),
926 },
927 },
928 },
929 },
930 },
931 "test3": {
932 selector: "foo=bar,baz=blah",
933 labels: "key1=value1,key2=value2",
934 name: "test",
935 port: "80",
936 protocol: "TCP",
937 targetPort: "1234",
938 expected: &corev1.Service{
939 ObjectMeta: metav1.ObjectMeta{
940 Name: "test",
941 Labels: map[string]string{
942 "key1": "value1",
943 "key2": "value2",
944 },
945 },
946 Spec: corev1.ServiceSpec{
947 Selector: map[string]string{
948 "foo": "bar",
949 "baz": "blah",
950 },
951 Ports: []corev1.ServicePort{
952 {
953 Port: 80,
954 Protocol: "TCP",
955 TargetPort: intstr.FromInt32(1234),
956 },
957 },
958 },
959 },
960 },
961 "test4": {
962 selector: "foo=bar,baz=blah",
963 name: "test",
964 port: "80",
965 protocol: "UDP",
966 externalIP: "1.2.3.4",
967 targetPort: "foobar",
968 expected: &corev1.Service{
969 ObjectMeta: metav1.ObjectMeta{
970 Name: "test",
971 },
972 Spec: corev1.ServiceSpec{
973 Selector: map[string]string{
974 "foo": "bar",
975 "baz": "blah",
976 },
977 Ports: []corev1.ServicePort{
978 {
979 Port: 80,
980 Protocol: "UDP",
981 TargetPort: intstr.FromString("foobar"),
982 },
983 },
984 ExternalIPs: []string{"1.2.3.4"},
985 },
986 },
987 },
988 "test5": {
989 selector: "foo=bar,baz=blah",
990 name: "test",
991 port: "80",
992 protocol: "UDP",
993 externalIP: "1.2.3.4",
994 serviceType: "LoadBalancer",
995 targetPort: "foobar",
996 expected: &corev1.Service{
997 ObjectMeta: metav1.ObjectMeta{
998 Name: "test",
999 },
1000 Spec: corev1.ServiceSpec{
1001 Selector: map[string]string{
1002 "foo": "bar",
1003 "baz": "blah",
1004 },
1005 Ports: []corev1.ServicePort{
1006 {
1007 Port: 80,
1008 Protocol: "UDP",
1009 TargetPort: intstr.FromString("foobar"),
1010 },
1011 },
1012 Type: corev1.ServiceTypeLoadBalancer,
1013 ExternalIPs: []string{"1.2.3.4"},
1014 },
1015 },
1016 },
1017 "test6": {
1018 selector: "foo=bar,baz=blah",
1019 name: "test",
1020 port: "80",
1021 protocol: "UDP",
1022 targetPort: "foobar",
1023 serviceType: string(corev1.ServiceTypeNodePort),
1024 expected: &corev1.Service{
1025 ObjectMeta: metav1.ObjectMeta{
1026 Name: "test",
1027 },
1028 Spec: corev1.ServiceSpec{
1029 Selector: map[string]string{
1030 "foo": "bar",
1031 "baz": "blah",
1032 },
1033 Ports: []corev1.ServicePort{
1034 {
1035 Port: 80,
1036 Protocol: "UDP",
1037 TargetPort: intstr.FromString("foobar"),
1038 },
1039 },
1040 Type: corev1.ServiceTypeNodePort,
1041 },
1042 },
1043 },
1044 "test7": {
1045 selector: "foo=bar,baz=blah",
1046 name: "test",
1047 port: "80",
1048 protocol: "UDP",
1049 targetPort: "foobar",
1050 serviceType: string(corev1.ServiceTypeNodePort),
1051 expected: &corev1.Service{
1052 ObjectMeta: metav1.ObjectMeta{
1053 Name: "test",
1054 },
1055 Spec: corev1.ServiceSpec{
1056 Selector: map[string]string{
1057 "foo": "bar",
1058 "baz": "blah",
1059 },
1060 Ports: []corev1.ServicePort{
1061 {
1062 Port: 80,
1063 Protocol: "UDP",
1064 TargetPort: intstr.FromString("foobar"),
1065 },
1066 },
1067 Type: corev1.ServiceTypeNodePort,
1068 },
1069 },
1070 },
1071 "test8": {
1072 selector: "foo=bar,baz=blah",
1073 name: "test",
1074 port: "80",
1075 protocol: "TCP",
1076 targetPort: "1234",
1077 expected: &corev1.Service{
1078 ObjectMeta: metav1.ObjectMeta{
1079 Name: "test",
1080 },
1081 Spec: corev1.ServiceSpec{
1082 Selector: map[string]string{
1083 "foo": "bar",
1084 "baz": "blah",
1085 },
1086 Ports: []corev1.ServicePort{
1087 {
1088 Port: 80,
1089 Protocol: "TCP",
1090 TargetPort: intstr.FromInt32(1234),
1091 },
1092 },
1093 },
1094 },
1095 },
1096 "test9": {
1097 selector: "foo=bar,baz=blah",
1098 name: "test",
1099 port: "80",
1100 protocol: "TCP",
1101 sessionAffinity: "ClientIP",
1102 targetPort: "1234",
1103 expected: &corev1.Service{
1104 ObjectMeta: metav1.ObjectMeta{
1105 Name: "test",
1106 },
1107 Spec: corev1.ServiceSpec{
1108 Selector: map[string]string{
1109 "foo": "bar",
1110 "baz": "blah",
1111 },
1112 Ports: []corev1.ServicePort{
1113 {
1114 Port: 80,
1115 Protocol: "TCP",
1116 TargetPort: intstr.FromInt32(1234),
1117 },
1118 },
1119 SessionAffinity: corev1.ServiceAffinityClientIP,
1120 },
1121 },
1122 },
1123 "test10": {
1124 selector: "foo=bar,baz=blah",
1125 name: "test",
1126 port: "80",
1127 protocol: "TCP",
1128 clusterIP: "10.10.10.10",
1129 targetPort: "1234",
1130 expected: &corev1.Service{
1131 ObjectMeta: metav1.ObjectMeta{
1132 Name: "test",
1133 },
1134 Spec: corev1.ServiceSpec{
1135 Selector: map[string]string{
1136 "foo": "bar",
1137 "baz": "blah",
1138 },
1139 Ports: []corev1.ServicePort{
1140 {
1141
1142 Port: 80,
1143 Protocol: "TCP",
1144 TargetPort: intstr.FromInt32(1234),
1145 },
1146 },
1147 ClusterIP: "10.10.10.10",
1148 },
1149 },
1150 },
1151 "test11": {
1152 selector: "foo=bar,baz=blah",
1153 name: "test",
1154 port: "80",
1155 protocol: "TCP",
1156 clusterIP: "None",
1157 targetPort: "1234",
1158 expected: &corev1.Service{
1159 ObjectMeta: metav1.ObjectMeta{
1160 Name: "test",
1161 },
1162 Spec: corev1.ServiceSpec{
1163 Selector: map[string]string{
1164 "foo": "bar",
1165 "baz": "blah",
1166 },
1167 Ports: []corev1.ServicePort{
1168 {
1169
1170 Port: 80,
1171 Protocol: "TCP",
1172 TargetPort: intstr.FromInt32(1234),
1173 },
1174 },
1175 ClusterIP: corev1.ClusterIPNone,
1176 },
1177 },
1178 },
1179 "test12": {
1180 selector: "foo=bar",
1181 name: "test",
1182 port: "80,443",
1183 protocol: "TCP",
1184 targetPort: "foobar",
1185 expected: &corev1.Service{
1186 ObjectMeta: metav1.ObjectMeta{
1187 Name: "test",
1188 },
1189 Spec: corev1.ServiceSpec{
1190 Selector: map[string]string{
1191 "foo": "bar",
1192 },
1193 Ports: []corev1.ServicePort{
1194 {
1195 Name: "port-1",
1196 Port: 80,
1197 Protocol: corev1.ProtocolTCP,
1198 TargetPort: intstr.FromString("foobar"),
1199 },
1200 {
1201 Name: "port-2",
1202 Port: 443,
1203 Protocol: corev1.ProtocolTCP,
1204 TargetPort: intstr.FromString("foobar"),
1205 },
1206 },
1207 },
1208 },
1209 },
1210 "test13": {
1211 selector: "foo=bar",
1212 name: "test",
1213 port: "80,443",
1214 protocol: "UDP",
1215 targetPort: "1234",
1216 expected: &corev1.Service{
1217 ObjectMeta: metav1.ObjectMeta{
1218 Name: "test",
1219 },
1220 Spec: corev1.ServiceSpec{
1221 Selector: map[string]string{
1222 "foo": "bar",
1223 },
1224 Ports: []corev1.ServicePort{
1225 {
1226 Name: "port-1",
1227 Port: 80,
1228 Protocol: corev1.ProtocolUDP,
1229 TargetPort: intstr.FromInt32(1234),
1230 },
1231 {
1232 Name: "port-2",
1233 Port: 443,
1234 Protocol: corev1.ProtocolUDP,
1235 TargetPort: intstr.FromInt32(1234),
1236 },
1237 },
1238 },
1239 },
1240 },
1241 "test14": {
1242 selector: "foo=bar",
1243 name: "test",
1244 port: "80,443",
1245 protocol: "TCP",
1246 expected: &corev1.Service{
1247 ObjectMeta: metav1.ObjectMeta{
1248 Name: "test",
1249 },
1250 Spec: corev1.ServiceSpec{
1251 Selector: map[string]string{
1252 "foo": "bar",
1253 },
1254 Ports: []corev1.ServicePort{
1255 {
1256 Name: "port-1",
1257 Port: 80,
1258 Protocol: corev1.ProtocolTCP,
1259 TargetPort: intstr.FromInt32(80),
1260 },
1261 {
1262 Name: "port-2",
1263 Port: 443,
1264 Protocol: corev1.ProtocolTCP,
1265 TargetPort: intstr.FromInt32(443),
1266 },
1267 },
1268 },
1269 },
1270 },
1271 "test15": {
1272 selector: "foo=bar",
1273 name: "test",
1274 port: "80,8080",
1275 protocols: "8080/UDP",
1276 expected: &corev1.Service{
1277 ObjectMeta: metav1.ObjectMeta{
1278 Name: "test",
1279 },
1280 Spec: corev1.ServiceSpec{
1281 Selector: map[string]string{
1282 "foo": "bar",
1283 },
1284 Ports: []corev1.ServicePort{
1285 {
1286 Name: "port-1",
1287 Port: 80,
1288 Protocol: corev1.ProtocolTCP,
1289 TargetPort: intstr.FromInt32(80),
1290 },
1291 {
1292 Name: "port-2",
1293 Port: 8080,
1294 Protocol: corev1.ProtocolUDP,
1295 TargetPort: intstr.FromInt32(8080),
1296 },
1297 },
1298 },
1299 },
1300 },
1301 "test16": {
1302 selector: "foo=bar",
1303 name: "test",
1304 port: "80,8080,8081",
1305 protocols: "8080/UDP,8081/TCP",
1306 expected: &corev1.Service{
1307 ObjectMeta: metav1.ObjectMeta{
1308 Name: "test",
1309 },
1310 Spec: corev1.ServiceSpec{
1311 Selector: map[string]string{
1312 "foo": "bar",
1313 },
1314 Ports: []corev1.ServicePort{
1315 {
1316 Name: "port-1",
1317 Port: 80,
1318 Protocol: corev1.ProtocolTCP,
1319 TargetPort: intstr.FromInt32(80),
1320 },
1321 {
1322 Name: "port-2",
1323 Port: 8080,
1324 Protocol: corev1.ProtocolUDP,
1325 TargetPort: intstr.FromInt32(8080),
1326 },
1327 {
1328 Name: "port-3",
1329 Port: 8081,
1330 Protocol: corev1.ProtocolTCP,
1331 TargetPort: intstr.FromInt32(8081),
1332 },
1333 },
1334 },
1335 },
1336 },
1337 "test17": {
1338 selector: "foo=bar,baz=blah",
1339 name: "test",
1340 protocol: "TCP",
1341 clusterIP: "None",
1342 expected: &corev1.Service{
1343 ObjectMeta: metav1.ObjectMeta{
1344 Name: "test",
1345 },
1346 Spec: corev1.ServiceSpec{
1347 Selector: map[string]string{
1348 "foo": "bar",
1349 "baz": "blah",
1350 },
1351 Ports: []corev1.ServicePort{},
1352 ClusterIP: corev1.ClusterIPNone,
1353 },
1354 },
1355 },
1356 "test18": {
1357 selector: "foo=bar",
1358 name: "test",
1359 clusterIP: "None",
1360 expected: &corev1.Service{
1361 ObjectMeta: metav1.ObjectMeta{
1362 Name: "test",
1363 },
1364 Spec: corev1.ServiceSpec{
1365 Selector: map[string]string{
1366 "foo": "bar",
1367 },
1368 Ports: []corev1.ServicePort{},
1369 ClusterIP: corev1.ClusterIPNone,
1370 },
1371 },
1372 },
1373 "test19": {
1374 selector: "foo=bar,baz=blah",
1375 name: "test",
1376 port: "80",
1377 protocol: "SCTP",
1378 targetPort: "1234",
1379 expected: &corev1.Service{
1380 ObjectMeta: metav1.ObjectMeta{
1381 Name: "test",
1382 },
1383 Spec: corev1.ServiceSpec{
1384 Selector: map[string]string{
1385 "foo": "bar",
1386 "baz": "blah",
1387 },
1388 Ports: []corev1.ServicePort{
1389 {
1390
1391 Port: 80,
1392 Protocol: "SCTP",
1393 TargetPort: intstr.FromInt32(1234),
1394 },
1395 },
1396 },
1397 },
1398 },
1399 "test20": {
1400 selector: "foo=bar,baz=blah",
1401 labels: "key1=value1,key2=value2",
1402 name: "test",
1403 port: "80",
1404 protocol: "SCTP",
1405 targetPort: "1234",
1406 expected: &corev1.Service{
1407 ObjectMeta: metav1.ObjectMeta{
1408 Name: "test",
1409 Labels: map[string]string{
1410 "key1": "value1",
1411 "key2": "value2",
1412 },
1413 },
1414 Spec: corev1.ServiceSpec{
1415 Selector: map[string]string{
1416 "foo": "bar",
1417 "baz": "blah",
1418 },
1419 Ports: []corev1.ServicePort{
1420 {
1421
1422 Port: 80,
1423 Protocol: "SCTP",
1424 TargetPort: intstr.FromInt32(1234),
1425 },
1426 },
1427 },
1428 },
1429 },
1430 "test21": {
1431 selector: "foo=bar,baz=blah",
1432 name: "test",
1433 port: "80",
1434 protocol: "SCTP",
1435 targetPort: "1234",
1436 expected: &corev1.Service{
1437 ObjectMeta: metav1.ObjectMeta{
1438 Name: "test",
1439 },
1440 Spec: corev1.ServiceSpec{
1441 Selector: map[string]string{
1442 "foo": "bar",
1443 "baz": "blah",
1444 },
1445 Ports: []corev1.ServicePort{
1446 {
1447
1448 Port: 80,
1449 Protocol: "SCTP",
1450 TargetPort: intstr.FromInt32(1234),
1451 },
1452 },
1453 },
1454 },
1455 },
1456 "test22": {
1457 selector: "foo=bar,baz=blah",
1458 name: "test",
1459 port: "80",
1460 protocol: "SCTP",
1461 sessionAffinity: "ClientIP",
1462 targetPort: "1234",
1463 expected: &corev1.Service{
1464 ObjectMeta: metav1.ObjectMeta{
1465 Name: "test",
1466 },
1467 Spec: corev1.ServiceSpec{
1468 Selector: map[string]string{
1469 "foo": "bar",
1470 "baz": "blah",
1471 },
1472 Ports: []corev1.ServicePort{
1473 {
1474 Port: 80,
1475 Protocol: "SCTP",
1476 TargetPort: intstr.FromInt32(1234),
1477 },
1478 },
1479 SessionAffinity: corev1.ServiceAffinityClientIP,
1480 },
1481 },
1482 },
1483 "test23": {
1484 selector: "foo=bar,baz=blah",
1485 name: "test",
1486 port: "80",
1487 protocol: "SCTP",
1488 clusterIP: "10.10.10.10",
1489 targetPort: "1234",
1490 expected: &corev1.Service{
1491 ObjectMeta: metav1.ObjectMeta{
1492 Name: "test",
1493 },
1494 Spec: corev1.ServiceSpec{
1495 Selector: map[string]string{
1496 "foo": "bar",
1497 "baz": "blah",
1498 },
1499 Ports: []corev1.ServicePort{
1500 {
1501 Port: 80,
1502 Protocol: "SCTP",
1503 TargetPort: intstr.FromInt32(1234),
1504 },
1505 },
1506 ClusterIP: "10.10.10.10",
1507 },
1508 },
1509 },
1510 "test24": {
1511 selector: "foo=bar,baz=blah",
1512 name: "test",
1513 port: "80",
1514 protocol: "SCTP",
1515 clusterIP: "None",
1516 targetPort: "1234",
1517 expected: &corev1.Service{
1518 ObjectMeta: metav1.ObjectMeta{
1519 Name: "test",
1520 },
1521 Spec: corev1.ServiceSpec{
1522 Selector: map[string]string{
1523 "foo": "bar",
1524 "baz": "blah",
1525 },
1526 Ports: []corev1.ServicePort{
1527 {
1528
1529 Port: 80,
1530 Protocol: "SCTP",
1531 TargetPort: intstr.FromInt32(1234),
1532 },
1533 },
1534 ClusterIP: corev1.ClusterIPNone,
1535 },
1536 },
1537 },
1538 "test25": {
1539 selector: "foo=bar",
1540 name: "test",
1541 port: "80,443",
1542 protocol: "SCTP",
1543 targetPort: "foobar",
1544 expected: &corev1.Service{
1545 ObjectMeta: metav1.ObjectMeta{
1546 Name: "test",
1547 },
1548 Spec: corev1.ServiceSpec{
1549 Selector: map[string]string{
1550 "foo": "bar",
1551 },
1552 Ports: []corev1.ServicePort{
1553 {
1554 Name: "port-1",
1555 Port: 80,
1556 Protocol: corev1.ProtocolSCTP,
1557 TargetPort: intstr.FromString("foobar"),
1558 },
1559 {
1560 Name: "port-2",
1561 Port: 443,
1562 Protocol: corev1.ProtocolSCTP,
1563 TargetPort: intstr.FromString("foobar"),
1564 },
1565 },
1566 },
1567 },
1568 },
1569 "test26": {
1570 selector: "foo=bar",
1571 name: "test",
1572 port: "80,443",
1573 protocol: "SCTP",
1574 expected: &corev1.Service{
1575 ObjectMeta: metav1.ObjectMeta{
1576 Name: "test",
1577 },
1578 Spec: corev1.ServiceSpec{
1579 Selector: map[string]string{
1580 "foo": "bar",
1581 },
1582 Ports: []corev1.ServicePort{
1583 {
1584 Name: "port-1",
1585 Port: 80,
1586 Protocol: corev1.ProtocolSCTP,
1587 TargetPort: intstr.FromInt32(80),
1588 },
1589 {
1590 Name: "port-2",
1591 Port: 443,
1592 Protocol: corev1.ProtocolSCTP,
1593 TargetPort: intstr.FromInt32(443),
1594 },
1595 },
1596 },
1597 },
1598 },
1599 "test27": {
1600 selector: "foo=bar",
1601 name: "test",
1602 port: "80,8080",
1603 protocols: "8080/SCTP",
1604 expected: &corev1.Service{
1605 ObjectMeta: metav1.ObjectMeta{
1606 Name: "test",
1607 },
1608 Spec: corev1.ServiceSpec{
1609 Selector: map[string]string{
1610 "foo": "bar",
1611 },
1612 Ports: []corev1.ServicePort{
1613 {
1614 Name: "port-1",
1615 Port: 80,
1616 Protocol: corev1.ProtocolTCP,
1617 TargetPort: intstr.FromInt32(80),
1618 },
1619 {
1620 Name: "port-2",
1621 Port: 8080,
1622 Protocol: corev1.ProtocolSCTP,
1623 TargetPort: intstr.FromInt32(8080),
1624 },
1625 },
1626 },
1627 },
1628 },
1629 "test28": {
1630 selector: "foo=bar",
1631 name: "test",
1632 port: "80,8080,8081,8082",
1633 protocols: "8080/UDP,8081/TCP,8082/SCTP",
1634 expected: &corev1.Service{
1635 ObjectMeta: metav1.ObjectMeta{
1636 Name: "test",
1637 },
1638 Spec: corev1.ServiceSpec{
1639 Selector: map[string]string{
1640 "foo": "bar",
1641 },
1642 Ports: []corev1.ServicePort{
1643 {
1644 Name: "port-1",
1645 Port: 80,
1646 Protocol: corev1.ProtocolTCP,
1647 TargetPort: intstr.FromInt32(80),
1648 },
1649 {
1650 Name: "port-2",
1651 Port: 8080,
1652 Protocol: corev1.ProtocolUDP,
1653 TargetPort: intstr.FromInt32(8080),
1654 },
1655 {
1656 Name: "port-3",
1657 Port: 8081,
1658 Protocol: corev1.ProtocolTCP,
1659 TargetPort: intstr.FromInt32(8081),
1660 },
1661 {
1662 Name: "port-4",
1663 Port: 8082,
1664 Protocol: corev1.ProtocolSCTP,
1665 TargetPort: intstr.FromInt32(8082),
1666 },
1667 },
1668 },
1669 },
1670 },
1671 "test 29": {
1672 selector: "foo=bar,baz=blah",
1673 name: "test",
1674 protocol: "SCTP",
1675 targetPort: "1234",
1676 clusterIP: "None",
1677 expected: &corev1.Service{
1678 ObjectMeta: metav1.ObjectMeta{
1679 Name: "test",
1680 },
1681 Spec: corev1.ServiceSpec{
1682 Selector: map[string]string{
1683 "foo": "bar",
1684 "baz": "blah",
1685 },
1686 Ports: []corev1.ServicePort{},
1687 ClusterIP: corev1.ClusterIPNone,
1688 },
1689 },
1690 },
1691
1692 "test #114402": {
1693 selector: "foo=bar,baz=blah",
1694 name: "test",
1695 clusterIP: "None",
1696 protocols: "53/TCP,53/UDP",
1697 port: "53",
1698 expected: &corev1.Service{
1699 ObjectMeta: metav1.ObjectMeta{
1700 Name: "test",
1701 },
1702 Spec: corev1.ServiceSpec{
1703 Selector: map[string]string{
1704 "foo": "bar",
1705 "baz": "blah",
1706 },
1707 Ports: []corev1.ServicePort{
1708 {
1709 Name: "port-1-tcp",
1710 Port: 53,
1711 Protocol: corev1.ProtocolTCP,
1712 TargetPort: intstr.FromInt32(53),
1713 },
1714 {
1715 Name: "port-1-udp",
1716 Port: 53,
1717 Protocol: corev1.ProtocolUDP,
1718 TargetPort: intstr.FromInt32(53),
1719 },
1720 },
1721 ClusterIP: corev1.ClusterIPNone,
1722 },
1723 },
1724 },
1725 "check selector": {
1726 name: "test",
1727 protocol: "SCTP",
1728 targetPort: "1234",
1729 clusterIP: "None",
1730 expectErr: `selector must be specified`,
1731 },
1732 "check name": {
1733 selector: "foo=bar,baz=blah",
1734 protocol: "SCTP",
1735 targetPort: "1234",
1736 clusterIP: "None",
1737 expectErr: `name must be specified`,
1738 },
1739 }
1740 for name, test := range tests {
1741 t.Run(name, func(t *testing.T) {
1742 exposeServiceOptions := ExposeServiceOptions{
1743 Selector: test.selector,
1744 Name: test.name,
1745 Protocol: test.protocol,
1746 Protocols: test.protocols,
1747 Port: test.port,
1748 ClusterIP: test.clusterIP,
1749 TargetPort: test.targetPort,
1750 Labels: test.labels,
1751 ExternalIP: test.externalIP,
1752 Type: test.serviceType,
1753 SessionAffinity: test.sessionAffinity,
1754 }
1755
1756 service, err := exposeServiceOptions.createService()
1757 if test.expectErr == "" {
1758 require.NoError(t, err)
1759 if !apiequality.Semantic.DeepEqual(service, test.expected) {
1760 t.Errorf("\nexpected:\n%#v\ngot:\n%#v", test.expected, service)
1761 }
1762 } else {
1763 require.Error(t, err)
1764 require.EqualError(t, err, test.expectErr)
1765 }
1766
1767 })
1768
1769 }
1770 }
1771
View as plain text