istio

Форк
0
562 строки · 15.1 Кб
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package ambient
16

17
import (
18
	"fmt"
19
	"net/netip"
20
	"testing"
21

22
	v1 "k8s.io/api/core/v1"
23
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24

25
	meshapi "istio.io/api/mesh/v1alpha1"
26
	networking "istio.io/api/networking/v1alpha3"
27
	networkingclient "istio.io/client-go/pkg/apis/networking/v1alpha3"
28
	securityclient "istio.io/client-go/pkg/apis/security/v1beta1"
29
	"istio.io/istio/pilot/pkg/model"
30
	"istio.io/istio/pkg/config/labels"
31
	"istio.io/istio/pkg/config/schema/kind"
32
	"istio.io/istio/pkg/kube/krt"
33
	"istio.io/istio/pkg/network"
34
	"istio.io/istio/pkg/slices"
35
	"istio.io/istio/pkg/test/util/assert"
36
	"istio.io/istio/pkg/workloadapi"
37
)
38

39
func TestPodWorkloads(t *testing.T) {
40
	cases := []struct {
41
		name   string
42
		inputs []any
43
		pod    *v1.Pod
44
		result *workloadapi.Workload
45
	}{
46
		{
47
			name:   "simple pod not running and not have podIP",
48
			inputs: []any{},
49
			pod: &v1.Pod{
50
				TypeMeta: metav1.TypeMeta{},
51
				ObjectMeta: metav1.ObjectMeta{
52
					Name:      "name",
53
					Namespace: "ns",
54
				},
55
				Spec: v1.PodSpec{},
56
				Status: v1.PodStatus{
57
					Phase: v1.PodPending,
58
				},
59
			},
60
			result: nil,
61
		},
62
		{
63
			name:   "simple pod not running but have podIP",
64
			inputs: []any{},
65
			pod: &v1.Pod{
66
				TypeMeta: metav1.TypeMeta{},
67
				ObjectMeta: metav1.ObjectMeta{
68
					Name:      "name",
69
					Namespace: "ns",
70
				},
71
				Spec: v1.PodSpec{},
72
				Status: v1.PodStatus{
73
					Phase: v1.PodPending,
74
					PodIP: "1.2.3.4",
75
				},
76
			},
77
			result: &workloadapi.Workload{
78
				Uid:               "cluster0//Pod/ns/name",
79
				Name:              "name",
80
				Namespace:         "ns",
81
				Addresses:         [][]byte{netip.AddrFrom4([4]byte{1, 2, 3, 4}).AsSlice()},
82
				Network:           testNW,
83
				CanonicalName:     "name",
84
				CanonicalRevision: "latest",
85
				WorkloadType:      workloadapi.WorkloadType_POD,
86
				WorkloadName:      "name",
87
				Status:            workloadapi.WorkloadStatus_UNHEALTHY,
88
				ClusterId:         testC,
89
			},
90
		},
91
		{
92
			name:   "simple pod not ready",
93
			inputs: []any{},
94
			pod: &v1.Pod{
95
				TypeMeta: metav1.TypeMeta{},
96
				ObjectMeta: metav1.ObjectMeta{
97
					Name:      "name",
98
					Namespace: "ns",
99
				},
100
				Spec: v1.PodSpec{},
101
				Status: v1.PodStatus{
102
					Phase: v1.PodRunning,
103
					PodIP: "1.2.3.4",
104
				},
105
			},
106
			result: &workloadapi.Workload{
107
				Uid:               "cluster0//Pod/ns/name",
108
				Name:              "name",
109
				Namespace:         "ns",
110
				Addresses:         [][]byte{netip.AddrFrom4([4]byte{1, 2, 3, 4}).AsSlice()},
111
				Network:           testNW,
112
				CanonicalName:     "name",
113
				CanonicalRevision: "latest",
114
				WorkloadType:      workloadapi.WorkloadType_POD,
115
				WorkloadName:      "name",
116
				Status:            workloadapi.WorkloadStatus_UNHEALTHY,
117
				ClusterId:         testC,
118
			},
119
		},
120
		{
121
			name: "pod with service",
122
			inputs: []any{
123
				model.ServiceInfo{
124
					Service: &workloadapi.Service{
125
						Name:      "svc",
126
						Namespace: "ns",
127
						Hostname:  "hostname",
128
						Ports: []*workloadapi.Port{{
129
							ServicePort: 80,
130
							TargetPort:  8080,
131
						}},
132
					},
133
					LabelSelector: model.NewSelector(map[string]string{"app": "foo"}),
134
				},
135
			},
136
			pod: &v1.Pod{
137
				TypeMeta: metav1.TypeMeta{},
138
				ObjectMeta: metav1.ObjectMeta{
139
					Name:      "name",
140
					Namespace: "ns",
141
					Labels: map[string]string{
142
						"app": "foo",
143
					},
144
				},
145
				Spec: v1.PodSpec{},
146
				Status: v1.PodStatus{
147
					Phase:      v1.PodRunning,
148
					Conditions: podReady,
149
					PodIP:      "1.2.3.4",
150
				},
151
			},
152
			result: &workloadapi.Workload{
153
				Uid:               "cluster0//Pod/ns/name",
154
				Name:              "name",
155
				Namespace:         "ns",
156
				Addresses:         [][]byte{netip.AddrFrom4([4]byte{1, 2, 3, 4}).AsSlice()},
157
				Network:           testNW,
158
				CanonicalName:     "foo",
159
				CanonicalRevision: "latest",
160
				WorkloadType:      workloadapi.WorkloadType_POD,
161
				WorkloadName:      "name",
162
				Status:            workloadapi.WorkloadStatus_HEALTHY,
163
				ClusterId:         testC,
164
				Services: map[string]*workloadapi.PortList{
165
					"ns/hostname": {
166
						Ports: []*workloadapi.Port{{
167
							ServicePort: 80,
168
							TargetPort:  8080,
169
						}},
170
					},
171
				},
172
			},
173
		},
174
		{
175
			name: "pod with service named ports",
176
			inputs: []any{
177
				model.ServiceInfo{
178
					Service: &workloadapi.Service{
179
						Name:      "svc",
180
						Namespace: "ns",
181
						Hostname:  "hostname",
182
						Ports: []*workloadapi.Port{
183
							{
184
								ServicePort: 80,
185
								TargetPort:  8080,
186
							},
187
							{
188
								ServicePort: 81,
189
								TargetPort:  0,
190
							},
191
							{
192
								ServicePort: 82,
193
								TargetPort:  0,
194
							},
195
						},
196
					},
197
					PortNames: map[int32]model.ServicePortName{
198
						// Not a named port
199
						80: {PortName: "80"},
200
						// Named port found in pod
201
						81: {PortName: "81", TargetPortName: "81-target"},
202
						// Named port not found in pod
203
						82: {PortName: "82", TargetPortName: "82-target"},
204
					},
205
					LabelSelector: model.NewSelector(map[string]string{"app": "foo"}),
206
				},
207
			},
208
			pod: &v1.Pod{
209
				TypeMeta: metav1.TypeMeta{},
210
				ObjectMeta: metav1.ObjectMeta{
211
					Name:      "name",
212
					Namespace: "ns",
213
					Labels: map[string]string{
214
						"app": "foo",
215
					},
216
				},
217
				Spec: v1.PodSpec{
218
					Containers: []v1.Container{{Ports: []v1.ContainerPort{
219
						{
220
							Name:          "81-target",
221
							ContainerPort: 9090,
222
							Protocol:      v1.ProtocolTCP,
223
						},
224
					}}},
225
				},
226
				Status: v1.PodStatus{
227
					Phase:      v1.PodRunning,
228
					Conditions: podReady,
229
					PodIP:      "1.2.3.4",
230
				},
231
			},
232
			result: &workloadapi.Workload{
233
				Uid:               "cluster0//Pod/ns/name",
234
				Name:              "name",
235
				Namespace:         "ns",
236
				Addresses:         [][]byte{netip.AddrFrom4([4]byte{1, 2, 3, 4}).AsSlice()},
237
				Network:           testNW,
238
				CanonicalName:     "foo",
239
				CanonicalRevision: "latest",
240
				WorkloadType:      workloadapi.WorkloadType_POD,
241
				WorkloadName:      "name",
242
				Status:            workloadapi.WorkloadStatus_HEALTHY,
243
				ClusterId:         testC,
244
				Services: map[string]*workloadapi.PortList{
245
					"ns/hostname": {
246
						Ports: []*workloadapi.Port{{
247
							ServicePort: 80,
248
							TargetPort:  8080,
249
						}, {
250
							ServicePort: 81,
251
							TargetPort:  9090,
252
						}},
253
					},
254
				},
255
			},
256
		},
257
	}
258
	for _, tt := range cases {
259
		t.Run(tt.name, func(t *testing.T) {
260
			inputs := tt.inputs
261
			a := newAmbientUnitTest()
262
			AuthorizationPolicies := krt.NewStaticCollection(extractType[model.WorkloadAuthorization](&inputs))
263
			PeerAuths := krt.NewStaticCollection(extractType[*securityclient.PeerAuthentication](&inputs))
264
			Waypoints := krt.NewStaticCollection(extractType[Waypoint](&inputs))
265
			WorkloadServices := krt.NewStaticCollection(extractType[model.ServiceInfo](&inputs))
266
			MeshConfig := krt.NewStatic(&MeshConfig{slices.First(extractType[meshapi.MeshConfig](&inputs))})
267
			Namespaces := krt.NewStaticCollection(extractType[*v1.Namespace](&inputs))
268
			assert.Equal(t, len(inputs), 0, fmt.Sprintf("some inputs were not consumed: %v", inputs))
269
			builder := a.podWorkloadBuilder(MeshConfig, AuthorizationPolicies, PeerAuths, Waypoints, WorkloadServices, Namespaces)
270
			wrapper := builder(krt.TestingDummyContext{}, tt.pod)
271
			var res *workloadapi.Workload
272
			if wrapper != nil {
273
				res = wrapper.Workload
274
			}
275
			assert.Equal(t, res, tt.result)
276
		})
277
	}
278
}
279

280
func TestWorkloadEntryWorkloads(t *testing.T) {
281
	cases := []struct {
282
		name   string
283
		inputs []any
284
		we     *networkingclient.WorkloadEntry
285
		result *workloadapi.Workload
286
	}{
287
		{
288
			name: "we with service",
289
			inputs: []any{
290
				model.ServiceInfo{
291
					Service: &workloadapi.Service{
292
						Name:      "svc",
293
						Namespace: "ns",
294
						Hostname:  "hostname",
295
						Ports: []*workloadapi.Port{{
296
							ServicePort: 80,
297
							TargetPort:  8080,
298
						}},
299
					},
300
					LabelSelector: model.NewSelector(map[string]string{"app": "foo"}),
301
				},
302
			},
303
			we: &networkingclient.WorkloadEntry{
304
				TypeMeta: metav1.TypeMeta{},
305
				ObjectMeta: metav1.ObjectMeta{
306
					Name:      "name",
307
					Namespace: "ns",
308
					Labels: map[string]string{
309
						"app": "foo",
310
					},
311
				},
312
				Spec: networking.WorkloadEntry{
313
					Address: "1.2.3.4",
314
				},
315
			},
316
			result: &workloadapi.Workload{
317
				Uid:               "cluster0/networking.istio.io/WorkloadEntry/ns/name",
318
				Name:              "name",
319
				Namespace:         "ns",
320
				Addresses:         [][]byte{netip.AddrFrom4([4]byte{1, 2, 3, 4}).AsSlice()},
321
				Network:           testNW,
322
				CanonicalName:     "foo",
323
				CanonicalRevision: "latest",
324
				WorkloadType:      workloadapi.WorkloadType_POD,
325
				WorkloadName:      "name",
326
				Status:            workloadapi.WorkloadStatus_HEALTHY,
327
				ClusterId:         testC,
328
				Services: map[string]*workloadapi.PortList{
329
					"ns/hostname": {
330
						Ports: []*workloadapi.Port{{
331
							ServicePort: 80,
332
							TargetPort:  8080,
333
						}},
334
					},
335
				},
336
			},
337
		},
338
		{
339
			name: "pod with service named ports",
340
			inputs: []any{
341
				model.ServiceInfo{
342
					Service: &workloadapi.Service{
343
						Name:      "svc",
344
						Namespace: "ns",
345
						Hostname:  "hostname",
346
						Ports: []*workloadapi.Port{
347
							{
348
								ServicePort: 80,
349
								TargetPort:  8080,
350
							},
351
							{
352
								ServicePort: 81,
353
								TargetPort:  0,
354
							},
355
							{
356
								ServicePort: 82,
357
								TargetPort:  0,
358
							},
359
							{
360
								ServicePort: 83,
361
								TargetPort:  0,
362
							},
363
						},
364
					},
365
					PortNames: map[int32]model.ServicePortName{
366
						// Not a named port
367
						80: {PortName: "80"},
368
						// Named port found in WE
369
						81: {PortName: "81", TargetPortName: "81-target"},
370
						// Named port target found in WE
371
						82: {PortName: "82", TargetPortName: "82-target"},
372
						// Named port not found in WE
373
						83: {PortName: "83", TargetPortName: "83-target"},
374
					},
375
					LabelSelector: model.NewSelector(map[string]string{"app": "foo"}),
376
					Source:        kind.Service,
377
				},
378
			},
379
			we: &networkingclient.WorkloadEntry{
380
				TypeMeta: metav1.TypeMeta{},
381
				ObjectMeta: metav1.ObjectMeta{
382
					Name:      "name",
383
					Namespace: "ns",
384
					Labels: map[string]string{
385
						"app": "foo",
386
					},
387
				},
388
				Spec: networking.WorkloadEntry{
389
					Ports: map[string]uint32{
390
						"81":        8180,
391
						"82-target": 8280,
392
					},
393
					Address: "1.2.3.4",
394
				},
395
			},
396
			result: &workloadapi.Workload{
397
				Uid:               "cluster0/networking.istio.io/WorkloadEntry/ns/name",
398
				Name:              "name",
399
				Namespace:         "ns",
400
				Addresses:         [][]byte{netip.AddrFrom4([4]byte{1, 2, 3, 4}).AsSlice()},
401
				Network:           testNW,
402
				CanonicalName:     "foo",
403
				CanonicalRevision: "latest",
404
				WorkloadType:      workloadapi.WorkloadType_POD,
405
				WorkloadName:      "name",
406
				Status:            workloadapi.WorkloadStatus_HEALTHY,
407
				ClusterId:         testC,
408
				Services: map[string]*workloadapi.PortList{
409
					"ns/hostname": {
410
						Ports: []*workloadapi.Port{
411
							{
412
								ServicePort: 80,
413
								TargetPort:  8080,
414
							},
415
							{
416
								ServicePort: 82,
417
								TargetPort:  8280,
418
							},
419
						},
420
					},
421
				},
422
			},
423
		},
424
		{
425
			name: "pod with serviceentry named ports",
426
			inputs: []any{
427
				model.ServiceInfo{
428
					Service: &workloadapi.Service{
429
						Name:      "svc",
430
						Namespace: "ns",
431
						Hostname:  "hostname",
432
						Ports: []*workloadapi.Port{
433
							{
434
								ServicePort: 80,
435
								TargetPort:  8080,
436
							},
437
							{
438
								ServicePort: 81,
439
								TargetPort:  0,
440
							},
441
							{
442
								ServicePort: 82,
443
								TargetPort:  0,
444
							},
445
						},
446
					},
447
					PortNames: map[int32]model.ServicePortName{
448
						// TargetPort explicitly set
449
						80: {PortName: "80"},
450
						// Port name found
451
						81: {PortName: "81"},
452
						// Port name not found
453
						82: {PortName: "82"},
454
					},
455
					LabelSelector: model.NewSelector(map[string]string{"app": "foo"}),
456
					Source:        kind.ServiceEntry,
457
				},
458
			},
459
			we: &networkingclient.WorkloadEntry{
460
				TypeMeta: metav1.TypeMeta{},
461
				ObjectMeta: metav1.ObjectMeta{
462
					Name:      "name",
463
					Namespace: "ns",
464
					Labels: map[string]string{
465
						"app": "foo",
466
					},
467
				},
468
				Spec: networking.WorkloadEntry{
469
					Ports: map[string]uint32{
470
						"81": 8180,
471
					},
472
					Address: "1.2.3.4",
473
				},
474
			},
475
			result: &workloadapi.Workload{
476
				Uid:               "cluster0/networking.istio.io/WorkloadEntry/ns/name",
477
				Name:              "name",
478
				Namespace:         "ns",
479
				Addresses:         [][]byte{netip.AddrFrom4([4]byte{1, 2, 3, 4}).AsSlice()},
480
				Network:           testNW,
481
				CanonicalName:     "foo",
482
				CanonicalRevision: "latest",
483
				WorkloadType:      workloadapi.WorkloadType_POD,
484
				WorkloadName:      "name",
485
				Status:            workloadapi.WorkloadStatus_HEALTHY,
486
				ClusterId:         testC,
487
				Services: map[string]*workloadapi.PortList{
488
					"ns/hostname": {
489
						Ports: []*workloadapi.Port{
490
							{
491
								ServicePort: 80,
492
								TargetPort:  8080,
493
							},
494
							{
495
								ServicePort: 81,
496
								TargetPort:  8180,
497
							},
498
							{
499
								ServicePort: 82,
500
								TargetPort:  82,
501
							},
502
						},
503
					},
504
				},
505
			},
506
		},
507
	}
508
	for _, tt := range cases {
509
		t.Run(tt.name, func(t *testing.T) {
510
			inputs := tt.inputs
511
			a := newAmbientUnitTest()
512
			AuthorizationPolicies := krt.NewStaticCollection(extractType[model.WorkloadAuthorization](&inputs))
513
			PeerAuths := krt.NewStaticCollection(extractType[*securityclient.PeerAuthentication](&inputs))
514
			Waypoints := krt.NewStaticCollection(extractType[Waypoint](&inputs))
515
			WorkloadServices := krt.NewStaticCollection(extractType[model.ServiceInfo](&inputs))
516
			Namespaces := krt.NewStaticCollection(extractType[*v1.Namespace](&inputs))
517
			MeshConfig := krt.NewStatic(&MeshConfig{slices.First(extractType[meshapi.MeshConfig](&inputs))})
518
			assert.Equal(t, len(inputs), 0, fmt.Sprintf("some inputs were not consumed: %v", inputs))
519
			builder := a.workloadEntryWorkloadBuilder(MeshConfig, AuthorizationPolicies, PeerAuths, Waypoints, WorkloadServices, Namespaces)
520
			wrapper := builder(krt.TestingDummyContext{}, tt.we)
521
			var res *workloadapi.Workload
522
			if wrapper != nil {
523
				res = wrapper.Workload
524
			}
525
			assert.Equal(t, res, tt.result)
526
		})
527
	}
528
}
529

530
func newAmbientUnitTest() *index {
531
	return &index{
532
		networkUpdateTrigger: krt.NewRecomputeTrigger(),
533
		ClusterID:            testC,
534
		Network: func(endpointIP string, labels labels.Instance) network.ID {
535
			return testNW
536
		},
537
	}
538
}
539

540
func extractType[T any](items *[]any) []T {
541
	var matched []T
542
	var unmatched []any
543
	arr := *items
544
	for _, val := range arr {
545
		if c, ok := val.(T); ok {
546
			matched = append(matched, c)
547
		} else {
548
			unmatched = append(unmatched, val)
549
		}
550
	}
551

552
	*items = unmatched
553
	return matched
554
}
555

556
var podReady = []v1.PodCondition{
557
	{
558
		Type:               v1.PodReady,
559
		Status:             v1.ConditionTrue,
560
		LastTransitionTime: metav1.Now(),
561
	},
562
}
563

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.