1
18
19 package xds_test
20
21 import (
22 "context"
23 "fmt"
24 "net"
25 "strconv"
26 "testing"
27 "time"
28
29 "github.com/google/uuid"
30 "google.golang.org/grpc"
31 "google.golang.org/grpc/connectivity"
32 "google.golang.org/grpc/credentials/insecure"
33 xdscreds "google.golang.org/grpc/credentials/xds"
34 "google.golang.org/grpc/internal/testutils"
35 "google.golang.org/grpc/internal/testutils/xds/bootstrap"
36 "google.golang.org/grpc/internal/testutils/xds/e2e"
37 "google.golang.org/grpc/xds"
38 "google.golang.org/protobuf/types/known/wrapperspb"
39
40 v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
41 v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
42 v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
43 v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
44 v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
45 v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
46 testgrpc "google.golang.org/grpc/interop/grpc_testing"
47 testpb "google.golang.org/grpc/interop/grpc_testing"
48 )
49
50
51
52
53
54
55
56
57 func (s) TestServerSideXDS_WithNoCertificateProvidersInBootstrap_Success(t *testing.T) {
58
59 mgmtServer, err := e2e.StartManagementServer(e2e.ManagementServerOptions{AllowResourceSubset: true})
60 if err != nil {
61 t.Fatalf("Failed to start management server: %v", err)
62 }
63 defer mgmtServer.Stop()
64
65
66 nodeID := uuid.New().String()
67 bs, err := bootstrap.Contents(bootstrap.Options{
68 NodeID: nodeID,
69 ServerURI: mgmtServer.Address,
70 ServerListenerResourceNameTemplate: e2e.ServerListenerResourceNameTemplate,
71 })
72 if err != nil {
73 t.Fatalf("Failed to create bootstrap configuration: %v", err)
74 }
75
76
77
78 lis, cleanup := setupGRPCServer(t, bs)
79 defer cleanup()
80
81
82
83
84 host, port, err := hostPortFromListener(lis)
85 if err != nil {
86 t.Fatalf("Failed to retrieve host and port of server: %v", err)
87 }
88 resources := e2e.UpdateOptions{
89 NodeID: nodeID,
90 Listeners: []*v3listenerpb.Listener{e2e.DefaultServerListener(host, port, e2e.SecurityLevelNone, "routeName")},
91 SkipValidation: true,
92 }
93 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
94 defer cancel()
95 if err := mgmtServer.Update(ctx, resources); err != nil {
96 t.Fatal(err)
97 }
98
99
100 cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
101 if err != nil {
102 t.Fatalf("Failed to dial local test server: %v", err)
103 }
104 defer cc.Close()
105
106 client := testgrpc.NewTestServiceClient(cc)
107 if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
108 t.Fatalf("EmptyCall() failed: %v", err)
109 }
110 }
111
112
113
114
115
116
117
118
119
120 func (s) TestServerSideXDS_WithNoCertificateProvidersInBootstrap_Failure(t *testing.T) {
121 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
122 defer cancel()
123
124
125
126 nackCh := make(chan struct{}, 1)
127 mgmtServer, err := e2e.StartManagementServer(e2e.ManagementServerOptions{
128 OnStreamRequest: func(_ int64, req *v3discoverypb.DiscoveryRequest) error {
129 if req.GetTypeUrl() != "type.googleapis.com/envoy.config.listener.v3.Listener" {
130 return nil
131 }
132 if req.GetErrorDetail() == nil {
133 return nil
134 }
135 select {
136 case nackCh <- struct{}{}:
137 case <-ctx.Done():
138 }
139 return nil
140 },
141 AllowResourceSubset: true,
142 })
143 if err != nil {
144 t.Fatalf("Failed to start management server: %v", err)
145 }
146 defer mgmtServer.Stop()
147
148
149 nodeID := uuid.New().String()
150 bs, err := bootstrap.Contents(bootstrap.Options{
151 NodeID: nodeID,
152 ServerURI: mgmtServer.Address,
153 ServerListenerResourceNameTemplate: e2e.ServerListenerResourceNameTemplate,
154 })
155 if err != nil {
156 t.Fatalf("Failed to create bootstrap configuration: %v", err)
157 }
158
159
160
161 creds, err := xdscreds.NewServerCredentials(xdscreds.ServerOptions{FallbackCreds: insecure.NewCredentials()})
162 if err != nil {
163 t.Fatal(err)
164 }
165
166
167
168
169 servingModeCh := make(chan struct{})
170 modeChangeOpt := xds.ServingModeCallback(func(addr net.Addr, args xds.ServingModeChangeArgs) {
171 if args.Mode == connectivity.ServingModeServing {
172 close(servingModeCh)
173 }
174 })
175 server, err := xds.NewGRPCServer(grpc.Creds(creds), modeChangeOpt, xds.BootstrapContentsForTesting(bs))
176 if err != nil {
177 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err)
178 }
179 testgrpc.RegisterTestServiceServer(server, &testService{})
180 defer server.Stop()
181
182
183 lis, err := testutils.LocalTCPListener()
184 if err != nil {
185 t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
186 }
187
188 go func() {
189 if err := server.Serve(lis); err != nil {
190 t.Errorf("Serve() failed: %v", err)
191 }
192 }()
193
194
195
196
197
198 host, port, err := hostPortFromListener(lis)
199 if err != nil {
200 t.Fatalf("Failed to retrieve host and port of server: %v", err)
201 }
202 resources := e2e.UpdateOptions{
203 NodeID: nodeID,
204 Listeners: []*v3listenerpb.Listener{e2e.DefaultServerListener(host, port, e2e.SecurityLevelMTLS, "routeName")},
205 SkipValidation: true,
206 }
207 if err := mgmtServer.Update(ctx, resources); err != nil {
208 t.Fatal(err)
209 }
210
211
212 select {
213 case <-nackCh:
214 case <-ctx.Done():
215 t.Fatal("Timeout when waiting for an NACK from the xDS client for the LDS response")
216 }
217
218
219
220 select {
221 case <-time.After(2 * defaultTestShortTimeout):
222 case <-servingModeCh:
223 t.Fatal("Server changed to serving mode when not expected to")
224 }
225
226
227
228 cc, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
229 if err != nil {
230 t.Fatalf("Failed to dial local test server: %v", err)
231 }
232 defer cc.Close()
233
234 waitForFailedRPCWithStatus(ctx, t, cc, errAcceptAndClose)
235 }
236
237
238
239
240
241
242
243
244
245
246
247
248 func (s) TestServerSideXDS_WithValidAndInvalidSecurityConfiguration(t *testing.T) {
249 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
250 defer cancel()
251
252
253
254 nackCh := make(chan struct{}, 1)
255 mgmtServer, nodeID, bs, _, cleanup := e2e.SetupManagementServer(t, e2e.ManagementServerOptions{
256 OnStreamRequest: func(_ int64, req *v3discoverypb.DiscoveryRequest) error {
257 if req.GetTypeUrl() != "type.googleapis.com/envoy.config.listener.v3.Listener" {
258 return nil
259 }
260 if req.GetErrorDetail() == nil {
261 return nil
262 }
263 select {
264 case nackCh <- struct{}{}:
265 case <-ctx.Done():
266 }
267 return nil
268 },
269 AllowResourceSubset: true,
270 })
271 defer cleanup()
272
273
274 lis1, err := testutils.LocalTCPListener()
275 if err != nil {
276 t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
277 }
278 lis2, err := testutils.LocalTCPListener()
279 if err != nil {
280 t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
281 }
282
283
284
285
286 creds, err := xdscreds.NewServerCredentials(xdscreds.ServerOptions{FallbackCreds: insecure.NewCredentials()})
287 if err != nil {
288 t.Fatal(err)
289 }
290 servingModeCh := make(chan struct{})
291 modeChangeOpt := xds.ServingModeCallback(func(addr net.Addr, args xds.ServingModeChangeArgs) {
292 if addr.String() == lis2.Addr().String() {
293 if args.Mode == connectivity.ServingModeServing {
294 close(servingModeCh)
295 }
296 }
297 })
298 server, err := xds.NewGRPCServer(grpc.Creds(creds), modeChangeOpt, xds.BootstrapContentsForTesting(bs))
299 if err != nil {
300 t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err)
301 }
302 testgrpc.RegisterTestServiceServer(server, &testService{})
303 defer server.Stop()
304
305 go func() {
306 if err := server.Serve(lis1); err != nil {
307 t.Errorf("Serve() failed: %v", err)
308 }
309 }()
310 go func() {
311 if err := server.Serve(lis2); err != nil {
312 t.Errorf("Serve() failed: %v", err)
313 }
314 }()
315
316
317
318
319
320 host1, port1, err := hostPortFromListener(lis1)
321 if err != nil {
322 t.Fatalf("Failed to retrieve host and port of server: %v", err)
323 }
324 resource1 := e2e.DefaultServerListener(host1, port1, e2e.SecurityLevelMTLS, "routeName")
325 host2, port2, err := hostPortFromListener(lis2)
326 if err != nil {
327 t.Fatalf("Failed to retrieve host and port of server: %v", err)
328 }
329 hcm := &v3httppb.HttpConnectionManager{
330 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
331 RouteConfig: &v3routepb.RouteConfiguration{
332 Name: "routeName",
333 VirtualHosts: []*v3routepb.VirtualHost{{
334 Domains: []string{"*"},
335 Routes: []*v3routepb.Route{{
336 Match: &v3routepb.RouteMatch{
337 PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
338 },
339 Action: &v3routepb.Route_NonForwardingAction{},
340 }}}}},
341 },
342 HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
343 }
344 ts := &v3corepb.TransportSocket{
345 Name: "envoy.transport_sockets.tls",
346 ConfigType: &v3corepb.TransportSocket_TypedConfig{
347 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{
348 RequireClientCertificate: &wrapperspb.BoolValue{Value: true},
349 CommonTlsContext: &v3tlspb.CommonTlsContext{
350 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
351 InstanceName: "non-existent-certificate-provider",
352 },
353 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextCertificateProviderInstance{
354 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
355 InstanceName: "non-existent-certificate-provider",
356 },
357 },
358 },
359 }),
360 },
361 }
362 resource2 := &v3listenerpb.Listener{
363 Name: fmt.Sprintf(e2e.ServerListenerResourceNameTemplate, net.JoinHostPort(host2, strconv.Itoa(int(port2)))),
364 Address: &v3corepb.Address{
365 Address: &v3corepb.Address_SocketAddress{
366 SocketAddress: &v3corepb.SocketAddress{
367 Address: host2,
368 PortSpecifier: &v3corepb.SocketAddress_PortValue{
369 PortValue: port2,
370 },
371 },
372 },
373 },
374 FilterChains: []*v3listenerpb.FilterChain{
375 {
376 Name: "v4-wildcard",
377 FilterChainMatch: &v3listenerpb.FilterChainMatch{
378 PrefixRanges: []*v3corepb.CidrRange{
379 {
380 AddressPrefix: "0.0.0.0",
381 PrefixLen: &wrapperspb.UInt32Value{
382 Value: uint32(0),
383 },
384 },
385 },
386 SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
387 SourcePrefixRanges: []*v3corepb.CidrRange{
388 {
389 AddressPrefix: "0.0.0.0",
390 PrefixLen: &wrapperspb.UInt32Value{
391 Value: uint32(0),
392 },
393 },
394 },
395 },
396 Filters: []*v3listenerpb.Filter{
397 {
398 Name: "filter-1",
399 ConfigType: &v3listenerpb.Filter_TypedConfig{TypedConfig: testutils.MarshalAny(t, hcm)},
400 },
401 },
402 TransportSocket: ts,
403 },
404 {
405 Name: "v6-wildcard",
406 FilterChainMatch: &v3listenerpb.FilterChainMatch{
407 PrefixRanges: []*v3corepb.CidrRange{
408 {
409 AddressPrefix: "::",
410 PrefixLen: &wrapperspb.UInt32Value{
411 Value: uint32(0),
412 },
413 },
414 },
415 SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
416 SourcePrefixRanges: []*v3corepb.CidrRange{
417 {
418 AddressPrefix: "::",
419 PrefixLen: &wrapperspb.UInt32Value{
420 Value: uint32(0),
421 },
422 },
423 },
424 },
425 Filters: []*v3listenerpb.Filter{
426 {
427 Name: "filter-1",
428 ConfigType: &v3listenerpb.Filter_TypedConfig{TypedConfig: testutils.MarshalAny(t, hcm)},
429 },
430 },
431 TransportSocket: ts,
432 },
433 },
434 }
435 resources := e2e.UpdateOptions{
436 NodeID: nodeID,
437 Listeners: []*v3listenerpb.Listener{resource1, resource2},
438 SkipValidation: true,
439 }
440 if err := mgmtServer.Update(ctx, resources); err != nil {
441 t.Fatal(err)
442 }
443
444
445 clientCreds := e2e.CreateClientTLSCredentials(t)
446 cc1, err := grpc.NewClient(lis1.Addr().String(), grpc.WithTransportCredentials(clientCreds))
447 if err != nil {
448 t.Fatalf("Failed to dial local test server: %v", err)
449 }
450 defer cc1.Close()
451
452 client1 := testgrpc.NewTestServiceClient(cc1)
453 if _, err := client1.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
454 t.Fatalf("EmptyCall() failed: %v", err)
455 }
456
457
458 select {
459 case <-nackCh:
460 case <-ctx.Done():
461 t.Fatal("Timeout when waiting for an NACK from the xDS client for the LDS response")
462 }
463
464
465
466 select {
467 case <-time.After(2 * defaultTestShortTimeout):
468 case <-servingModeCh:
469 t.Fatal("Server changed to serving mode when not expected to")
470 }
471
472
473
474 cc2, err := grpc.NewClient(lis2.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
475 if err != nil {
476 t.Fatalf("Failed to dial local test server: %v", err)
477 }
478 defer cc2.Close()
479
480 waitForFailedRPCWithStatus(ctx, t, cc2, errAcceptAndClose)
481 }
482
View as plain text