istio

Форк
0
/
delta_test.go 
497 строк · 13.9 Кб
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 adsc
16

17
import (
18
	"context"
19
	"net"
20
	"testing"
21
	"time"
22

23
	cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
24
	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
25
	endpoint "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
26
	listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
27
	route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
28
	hcm "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
29
	tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
30
	discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
31
	"github.com/envoyproxy/go-control-plane/pkg/wellknown"
32
	"github.com/google/go-cmp/cmp"
33
	"google.golang.org/grpc"
34
	"google.golang.org/protobuf/testing/protocmp"
35

36
	authn_model "istio.io/istio/pilot/pkg/security/model"
37
	"istio.io/istio/pilot/pkg/util/protoconv"
38
	v3 "istio.io/istio/pilot/pkg/xds/v3"
39
	"istio.io/istio/pilot/test/xdstest"
40
	"istio.io/istio/pkg/log"
41
	"istio.io/istio/pkg/test/util/assert"
42
	"istio.io/istio/pkg/test/util/retry"
43
)
44

45
type mockDeltaXdsServer struct{}
46

47
var deltaHandler func(stream discovery.AggregatedDiscoveryService_DeltaAggregatedResourcesServer) error
48

49
func (t *mockDeltaXdsServer) StreamAggregatedResources(discovery.AggregatedDiscoveryService_StreamAggregatedResourcesServer) error {
50
	return nil
51
}
52

53
func (t *mockDeltaXdsServer) DeltaAggregatedResources(delta discovery.AggregatedDiscoveryService_DeltaAggregatedResourcesServer) error {
54
	return deltaHandler(delta)
55
}
56

57
var testCluster = &cluster.Cluster{
58
	Name:                 "test-eds",
59
	ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_EDS},
60
	EdsClusterConfig: &cluster.Cluster_EdsClusterConfig{
61
		EdsConfig: &core.ConfigSource{
62
			ConfigSourceSpecifier: &core.ConfigSource_Ads{
63
				Ads: &core.AggregatedConfigSource{},
64
			},
65
		},
66
	},
67
	LbPolicy: cluster.Cluster_ROUND_ROBIN,
68
	TransportSocket: &core.TransportSocket{
69
		Name: wellknown.TransportSocketTLS,
70
		ConfigType: &core.TransportSocket_TypedConfig{
71
			TypedConfig: protoconv.MessageToAny(&tls.UpstreamTlsContext{
72
				CommonTlsContext: &tls.CommonTlsContext{
73
					ValidationContextType: &tls.CommonTlsContext_CombinedValidationContext{
74
						CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{
75
							ValidationContextSdsSecretConfig: &tls.SdsSecretConfig{
76
								Name:      "kubernetes://test",
77
								SdsConfig: authn_model.SDSAdsConfig,
78
							},
79
						},
80
					},
81
				},
82
			}),
83
		},
84
	},
85
}
86

87
var testClusterNoSecret = &cluster.Cluster{
88
	Name:                 "test-eds",
89
	ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_EDS},
90
	EdsClusterConfig: &cluster.Cluster_EdsClusterConfig{
91
		EdsConfig: &core.ConfigSource{
92
			ConfigSourceSpecifier: &core.ConfigSource_Ads{
93
				Ads: &core.AggregatedConfigSource{},
94
			},
95
		},
96
	},
97
	LbPolicy: cluster.Cluster_ROUND_ROBIN,
98
}
99

100
var testListener = &listener.Listener{
101
	Name: "test-listener",
102
	Address: &core.Address{
103
		Address: &core.Address_SocketAddress{
104
			SocketAddress: &core.SocketAddress{
105
				Protocol: core.SocketAddress_TCP,
106
				Address:  "0.0.0.0",
107
				PortSpecifier: &core.SocketAddress_PortValue{
108
					PortValue: 8080,
109
				},
110
			},
111
		},
112
	},
113
	FilterChains: []*listener.FilterChain{
114
		{
115
			Filters: []*listener.Filter{
116
				{
117
					Name: wellknown.HTTPConnectionManager,
118
					ConfigType: &listener.Filter_TypedConfig{
119
						TypedConfig: protoconv.MessageToAny(&hcm.HttpConnectionManager{
120
							RouteSpecifier: &hcm.HttpConnectionManager_Rds{
121
								Rds: &hcm.Rds{
122
									RouteConfigName: "test-rds-config",
123
									ConfigSource: &core.ConfigSource{
124
										ConfigSourceSpecifier: &core.ConfigSource_Ads{
125
											Ads: &core.AggregatedConfigSource{},
126
										},
127
									},
128
								},
129
							},
130
						}),
131
					},
132
				},
133
			},
134
			TransportSocket: &core.TransportSocket{
135
				Name: wellknown.TransportSocketTLS,
136
				ConfigType: &core.TransportSocket_TypedConfig{
137
					TypedConfig: protoconv.MessageToAny(&tls.DownstreamTlsContext{
138
						CommonTlsContext: &tls.CommonTlsContext{
139
							ValidationContextType: &tls.CommonTlsContext_CombinedValidationContext{
140
								CombinedValidationContext: &tls.CommonTlsContext_CombinedCertificateValidationContext{
141
									ValidationContextSdsSecretConfig: &tls.SdsSecretConfig{
142
										Name:      "kubernetes://test",
143
										SdsConfig: authn_model.SDSAdsConfig,
144
									},
145
								},
146
							},
147
						},
148
					}),
149
				},
150
			},
151
		},
152
	},
153
}
154

155
var testListenerNoSecret = &listener.Listener{
156
	Name: "test-listener",
157
	Address: &core.Address{
158
		Address: &core.Address_SocketAddress{
159
			SocketAddress: &core.SocketAddress{
160
				Protocol: core.SocketAddress_TCP,
161
				Address:  "0.0.0.0",
162
				PortSpecifier: &core.SocketAddress_PortValue{
163
					PortValue: 8080,
164
				},
165
			},
166
		},
167
	},
168
	FilterChains: []*listener.FilterChain{
169
		{
170
			Filters: []*listener.Filter{
171
				{
172
					Name: wellknown.HTTPConnectionManager,
173
					ConfigType: &listener.Filter_TypedConfig{
174
						TypedConfig: protoconv.MessageToAny(&hcm.HttpConnectionManager{
175
							RouteSpecifier: &hcm.HttpConnectionManager_Rds{
176
								Rds: &hcm.Rds{
177
									RouteConfigName: "test-rds-config",
178
									ConfigSource: &core.ConfigSource{
179
										ConfigSourceSpecifier: &core.ConfigSource_Ads{
180
											Ads: &core.AggregatedConfigSource{},
181
										},
182
									},
183
								},
184
							},
185
						}),
186
					},
187
				},
188
			},
189
		},
190
	},
191
}
192

193
var testRouteConfig = &route.RouteConfiguration{
194
	Name: "test-route",
195
	// Define the route entries here
196
	VirtualHosts: []*route.VirtualHost{
197
		{
198
			Name:    "test-vhost",
199
			Domains: []string{"*"},
200
			Routes: []*route.Route{
201
				{
202
					Match: &route.RouteMatch{
203
						PathSpecifier: &route.RouteMatch_Prefix{Prefix: "/"},
204
					},
205
					Action: &route.Route_Route{
206
						Route: &route.RouteAction{
207
							ClusterSpecifier: &route.RouteAction_Cluster{Cluster: "test-cluster"},
208
						},
209
					},
210
				},
211
			},
212
		},
213
	},
214
}
215

216
func TestDeltaClient(t *testing.T) {
217
	type testCase struct {
218
		desc                   string
219
		deltaHandler           func(server discovery.AggregatedDiscoveryService_DeltaAggregatedResourcesServer) error
220
		inClient               *Client
221
		expectedDeltaResources *Client
222
		expectedTree           string
223
	}
224

225
	var tests []testCase
226

227
	clusterHandler := Register(func(ctx HandlerContext, resourceName string, resourceVersion string, resourceEntity *cluster.Cluster, event Event) {
228
		if event == EventDelete {
229
			return
230
		}
231
		ctx.RegisterDependency(v3.SecretType, xdstest.ExtractClusterSecretResources(t, resourceEntity)...)
232
		ctx.RegisterDependency(v3.EndpointType, xdstest.ExtractEdsClusterNames([]*cluster.Cluster{resourceEntity})...)
233
	})
234
	endpointsHandler := Register(func(ctx HandlerContext, resourceName string, resourceVersion string, resourceEntity *endpoint.ClusterLoadAssignment,
235
		event Event) {
236
	})
237
	listenerHandler := Register(func(ctx HandlerContext, resourceName string, resourceVersion string, resourceEntity *listener.Listener, event Event) {
238
		if event == EventDelete {
239
			return
240
		}
241
		ctx.RegisterDependency(v3.SecretType, xdstest.ExtractListenerSecretResources(t, resourceEntity)...)
242
		ctx.RegisterDependency(v3.RouteType, xdstest.ExtractRoutesFromListeners([]*listener.Listener{resourceEntity})...)
243
		// TODO: ECDS
244
	})
245
	routesHandler := Register(func(ctx HandlerContext, resourceName string, resourceVersion string, resourceEntity *route.RouteConfiguration, event Event) {
246
	})
247
	secretsHandler := Register(func(ctx HandlerContext, resourceName string, resourceVersion string, resourceEntity *tls.Secret, event Event) {
248
	})
249

250
	handlers := []Option{
251
		clusterHandler,
252
		Watch[*cluster.Cluster]("*"),
253
		listenerHandler,
254
		Watch[*listener.Listener]("*"),
255
		endpointsHandler,
256
		routesHandler,
257
		secretsHandler,
258
	}
259

260
	descs := []struct {
261
		desc            string
262
		inClient        *Client
263
		serverResponses []*discovery.DeltaDiscoveryResponse
264
		expectedTree    string
265
	}{
266
		{
267
			desc: "initial request cluster with no secret",
268
			serverResponses: []*discovery.DeltaDiscoveryResponse{
269
				{
270
					TypeUrl: v3.ClusterType,
271
					Resources: []*discovery.Resource{
272
						{
273
							Name:     "test-eds",
274
							Resource: protoconv.MessageToAny(testClusterNoSecret),
275
						},
276
					},
277
				},
278
			},
279
			expectedTree: `CDS/:
280
  CDS/test-eds:
281
    EDS/test-eds:
282
LDS/:
283
`,
284
		},
285
		{
286
			desc: "initial request cluster with secret",
287
			serverResponses: []*discovery.DeltaDiscoveryResponse{
288
				{
289
					TypeUrl: v3.ClusterType,
290
					Resources: []*discovery.Resource{
291
						{
292
							Name:     "test-eds",
293
							Resource: protoconv.MessageToAny(testCluster),
294
						},
295
					},
296
				},
297
			},
298
			expectedTree: `CDS/:
299
  CDS/test-eds:
300
    EDS/test-eds:
301
    SDS/kubernetes://test:
302
LDS/:
303
`,
304
		},
305
		{
306
			desc: "initial request listener with no secret",
307
			serverResponses: []*discovery.DeltaDiscoveryResponse{
308
				{
309
					TypeUrl: v3.ListenerType,
310
					Resources: []*discovery.Resource{
311
						{
312
							Name:     "test-listener",
313
							Resource: protoconv.MessageToAny(testListenerNoSecret),
314
						},
315
					},
316
				},
317
			},
318
			expectedTree: `CDS/:
319
LDS/:
320
  LDS/test-listener:
321
    RDS/test-rds-config:
322
`,
323
		},
324
		{
325
			desc: "initial request listener with secret",
326
			serverResponses: []*discovery.DeltaDiscoveryResponse{
327
				{
328
					TypeUrl: v3.ListenerType,
329
					Resources: []*discovery.Resource{
330
						{
331
							Name:     "test-listener",
332
							Resource: protoconv.MessageToAny(testListener),
333
						},
334
					},
335
				},
336
			},
337
			expectedTree: `CDS/:
338
LDS/:
339
  LDS/test-listener:
340
    RDS/test-rds-config:
341
    SDS/kubernetes://test:
342
`,
343
		},
344
		{
345
			desc: "put things together",
346
			serverResponses: []*discovery.DeltaDiscoveryResponse{
347
				{
348
					TypeUrl: v3.ClusterType,
349
					Resources: []*discovery.Resource{
350
						{
351
							Name:     "test-eds",
352
							Resource: protoconv.MessageToAny(testCluster),
353
						},
354
					},
355
				},
356
				{
357
					TypeUrl: v3.ListenerType,
358
					Resources: []*discovery.Resource{
359
						{
360
							Name:     "test-listener",
361
							Resource: protoconv.MessageToAny(testListener),
362
						},
363
					},
364
				},
365
				{
366
					TypeUrl: v3.RouteType,
367
					Resources: []*discovery.Resource{
368
						{
369
							Name:     "test-route",
370
							Resource: protoconv.MessageToAny(testRouteConfig),
371
						},
372
					},
373
				},
374
			},
375
			expectedTree: `CDS/:
376
  CDS/test-eds:
377
    EDS/test-eds:
378
    SDS/kubernetes://test:
379
LDS/:
380
  LDS/test-listener:
381
    RDS/test-rds-config:
382
    SDS/kubernetes://test:
383
RDS/test-route:
384
`,
385
		},
386

387
		{
388
			desc: "begin two clusters then remove one",
389
			serverResponses: []*discovery.DeltaDiscoveryResponse{
390
				{
391
					TypeUrl: v3.ClusterType,
392
					Resources: []*discovery.Resource{
393
						{
394
							Name:     "test-cluster1",
395
							Resource: protoconv.MessageToAny(testCluster),
396
						},
397
						{
398
							Name:     "test-cluster2",
399
							Resource: protoconv.MessageToAny(testClusterNoSecret),
400
						},
401
					},
402
				},
403
				{
404
					TypeUrl:          v3.ClusterType,
405
					Resources:        []*discovery.Resource{},
406
					RemovedResources: []string{"test-cluster2"},
407
				},
408
			},
409
			expectedTree: `CDS/:
410
  CDS/test-cluster1:
411
    EDS/test-eds:
412
    SDS/kubernetes://test:
413
LDS/:
414
`,
415
		},
416
	}
417
	for _, item := range descs {
418
		desc := item // avoid refer to on-stack-var
419
		expected := make(map[string]*discovery.DeltaDiscoveryResponse)
420
		for _, response := range item.serverResponses {
421
			expected[response.TypeUrl] = response
422
		}
423
		tc := testCase{
424
			desc:     desc.desc,
425
			inClient: NewDeltaWithBackoffPolicy("", &DeltaADSConfig{}, nil),
426
			deltaHandler: func(delta discovery.AggregatedDiscoveryService_DeltaAggregatedResourcesServer) error {
427
				for _, response := range desc.serverResponses {
428
					_ = delta.Send(response)
429
				}
430
				return nil
431
			},
432
			expectedDeltaResources: &Client{
433
				lastReceived: expected,
434
			},
435
			expectedTree: desc.expectedTree,
436
		}
437
		tests = append(tests, tc)
438
	}
439

440
	for _, tt := range tests {
441
		t.Run(tt.desc, func(t *testing.T) {
442
			deltaHandler = tt.deltaHandler
443
			l, err := net.Listen("tcp", ":0")
444
			if err != nil {
445
				t.Errorf("Unable to listen with tcp err %v", err)
446
				return
447
			}
448
			tt.inClient.cfg.Address = l.Addr().String()
449
			xds := grpc.NewServer()
450
			discovery.RegisterAggregatedDiscoveryServiceServer(xds, new(mockDeltaXdsServer))
451
			go func() {
452
				err = xds.Serve(l)
453
				if err != nil {
454
					log.Error(err)
455
				}
456
			}()
457
			defer xds.GracefulStop()
458
			if err != nil {
459
				t.Errorf("Could not start serving ads server %v", err)
460
				return
461
			}
462

463
			tt.inClient = NewDeltaWithBackoffPolicy(tt.inClient.cfg.Address, tt.inClient.cfg, nil, handlers...)
464
			if err := tt.inClient.Run(context.TODO()); err != nil {
465
				t.Errorf("ADSC: failed running %v", err)
466
				return
467
			}
468
			assert.EventuallyEqual(t, func() bool {
469
				tt.inClient.mutex.Lock()
470
				defer tt.inClient.mutex.Unlock()
471
				rec := tt.inClient.lastReceived
472

473
				if rec == nil && len(rec) != len(tt.expectedDeltaResources.lastReceived) {
474
					return false
475
				}
476
				for tpe, rsrcs := range tt.expectedDeltaResources.lastReceived {
477
					if _, ok := rec[tpe]; !ok {
478
						return false
479
					}
480
					if len(rsrcs.Resources) != len(rec[tpe].Resources) {
481
						return false
482
					}
483
				}
484
				return true
485
			}, true, retry.Timeout(time.Second), retry.Delay(time.Millisecond))
486

487
			if !cmp.Equal(tt.inClient.lastReceived, tt.expectedDeltaResources.lastReceived, protocmp.Transform()) {
488
				t.Errorf("%s: expected recv %v got %v", tt.desc, tt.expectedDeltaResources.lastReceived, tt.inClient.lastReceived)
489
			}
490

491
			tree := tt.inClient.dumpTree()
492
			if diff := cmp.Diff(tt.expectedTree, tree); diff != "" {
493
				t.Errorf("%s: expected tree %v got %v", tt.desc, tt.expectedTree, tree)
494
			}
495
		})
496
	}
497
}
498

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

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

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

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