1
18
19 package xds_test
20
21 import (
22 "context"
23 "fmt"
24 "strings"
25 "testing"
26
27 "github.com/google/uuid"
28 "google.golang.org/grpc"
29 "google.golang.org/grpc/codes"
30 "google.golang.org/grpc/credentials/insecure"
31 "google.golang.org/grpc/internal"
32 "google.golang.org/grpc/internal/stubserver"
33 "google.golang.org/grpc/internal/testutils"
34 "google.golang.org/grpc/internal/testutils/xds/bootstrap"
35 "google.golang.org/grpc/internal/testutils/xds/e2e"
36 "google.golang.org/grpc/resolver"
37 "google.golang.org/grpc/status"
38
39 v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
40 v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/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 testgrpc "google.golang.org/grpc/interop/grpc_testing"
44 testpb "google.golang.org/grpc/interop/grpc_testing"
45 )
46
47
48
49
50
51
52
53
54
55 func (s) TestClientSideFederation(t *testing.T) {
56
57 serverDefaultAuth, err := e2e.StartManagementServer(e2e.ManagementServerOptions{})
58 if err != nil {
59 t.Fatalf("Failed to spin up the xDS management server: %v", err)
60 }
61 t.Cleanup(serverDefaultAuth.Stop)
62
63
64 const nonDefaultAuth = "non-default-auth"
65 serverAnotherAuth, err := e2e.StartManagementServer(e2e.ManagementServerOptions{})
66 if err != nil {
67 t.Fatalf("Failed to spin up the xDS management server: %v", err)
68 }
69 t.Cleanup(serverAnotherAuth.Stop)
70
71
72 nodeID := uuid.New().String()
73 bootstrapContents, err := bootstrap.Contents(bootstrap.Options{
74 NodeID: nodeID,
75 ServerURI: serverDefaultAuth.Address,
76 ServerListenerResourceNameTemplate: e2e.ServerListenerResourceNameTemplate,
77
78 Authorities: map[string]string{nonDefaultAuth: serverAnotherAuth.Address},
79 })
80 if err != nil {
81 t.Fatalf("Failed to create bootstrap file: %v", err)
82 }
83
84 resolverBuilder := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))
85 resolver, err := resolverBuilder(bootstrapContents)
86 if err != nil {
87 t.Fatalf("Failed to create xDS resolver for testing: %v", err)
88 }
89 server := stubserver.StartTestService(t, nil)
90 defer server.Stop()
91
92 const serviceName = "my-service-client-side-xds"
93
94 ldsName := serviceName
95
96 rdsName := fmt.Sprintf("xdstp://%s/envoy.config.route.v3.RouteConfiguration/%s", nonDefaultAuth, "route-"+serviceName)
97
98 cdsName := "cluster-" + serviceName
99
100 edsName := fmt.Sprintf("xdstp://%s/envoy.config.route.v3.ClusterLoadAssignment/%s", nonDefaultAuth, "endpoints-"+serviceName)
101
102
103
104 resourcesDefault := e2e.UpdateOptions{
105 NodeID: nodeID,
106
107 Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)},
108 Clusters: []*v3clusterpb.Cluster{e2e.DefaultCluster(cdsName, edsName, e2e.SecurityLevelNone)},
109 SkipValidation: true,
110 }
111 resourcesAnother := e2e.UpdateOptions{
112 NodeID: nodeID,
113
114 Routes: []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(rdsName, ldsName, cdsName)},
115 Endpoints: []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(edsName, "localhost", []uint32{testutils.ParsePort(t, server.Address)})},
116 SkipValidation: true,
117 }
118
119 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
120 defer cancel()
121
122 if err := serverDefaultAuth.Update(ctx, resourcesDefault); err != nil {
123 t.Fatal(err)
124 }
125
126 if err := serverAnotherAuth.Update(ctx, resourcesAnother); err != nil {
127 t.Fatal(err)
128 }
129
130
131 cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
132 if err != nil {
133 t.Fatalf("failed to dial local test server: %v", err)
134 }
135 defer cc.Close()
136
137 client := testgrpc.NewTestServiceClient(cc)
138 if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
139 t.Fatalf("rpc EmptyCall() failed: %v", err)
140 }
141 }
142
143
144
145
146
147
148 func (s) TestClientSideFederationWithOnlyXDSTPStyleLDS(t *testing.T) {
149
150 const authority = "traffic-manager.xds.notgoogleapis.com"
151 mgmtServer, err := e2e.StartManagementServer(e2e.ManagementServerOptions{})
152 if err != nil {
153 t.Fatalf("Failed to spin up the xDS management server: %v", err)
154 }
155 t.Cleanup(mgmtServer.Stop)
156
157
158 nodeID := uuid.New().String()
159 bootstrapContents, err := bootstrap.Contents(bootstrap.Options{
160 NodeID: nodeID,
161 ServerURI: mgmtServer.Address,
162 ClientDefaultListenerResourceNameTemplate: fmt.Sprintf("xdstp://%s/envoy.config.listener.v3.Listener/%%s", authority),
163 Authorities: map[string]string{authority: mgmtServer.Address},
164 })
165 if err != nil {
166 t.Fatalf("Failed to create bootstrap file: %v", err)
167 }
168
169 resolverBuilder := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))
170 resolver, err := resolverBuilder(bootstrapContents)
171 if err != nil {
172 t.Fatalf("Failed to create xDS resolver for testing: %v", err)
173 }
174 server := stubserver.StartTestService(t, nil)
175 defer server.Stop()
176
177
178 const serviceName = "my-service-client-side-xds/2nd component"
179
180
181 const rdsName = "route-" + serviceName
182 const cdsName = "cluster-" + serviceName
183 const edsName = "endpoints-" + serviceName
184
185
186 resourceUpdate := e2e.UpdateOptions{
187 NodeID: nodeID,
188 Listeners: func() []*v3listenerpb.Listener {
189
190
191
192 const specialEscapedServiceName = "my-service-client-side-xds/2nd%20component"
193 ldsName := fmt.Sprintf("xdstp://%s/envoy.config.listener.v3.Listener/%s", authority, specialEscapedServiceName)
194 return []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)}
195 }(),
196 Routes: func() []*v3routepb.RouteConfiguration {
197
198
199
200
201 const fullyEscapedServiceName = "my-service-client-side-xds%2F2nd%20component"
202 return []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(rdsName, fullyEscapedServiceName, cdsName)}
203 }(),
204 Clusters: []*v3clusterpb.Cluster{e2e.DefaultCluster(cdsName, edsName, e2e.SecurityLevelNone)},
205 Endpoints: []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(edsName, "localhost", []uint32{testutils.ParsePort(t, server.Address)})},
206 SkipValidation: true,
207 }
208
209 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
210 defer cancel()
211 if err := mgmtServer.Update(ctx, resourceUpdate); err != nil {
212 t.Fatal(err)
213 }
214
215
216 cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
217 if err != nil {
218 t.Fatalf("failed to dial local test server: %v", err)
219 }
220 defer cc.Close()
221
222 client := testgrpc.NewTestServiceClient(cc)
223 if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
224 t.Fatalf("rpc EmptyCall() failed: %v", err)
225 }
226 }
227
228
229
230
231
232 func (s) TestFederation_UnknownAuthorityInDialTarget(t *testing.T) {
233
234
235
236
237
238
239 managementServer, nodeID, _, resolver, cleanup1 := e2e.SetupManagementServer(t, e2e.ManagementServerOptions{})
240 defer cleanup1()
241
242 server := stubserver.StartTestService(t, nil)
243 defer server.Stop()
244
245 const serviceName = "my-service-client-side-xds"
246 resources := e2e.DefaultClientResources(e2e.ResourceParams{
247 DialTarget: serviceName,
248 NodeID: nodeID,
249 Host: "localhost",
250 Port: testutils.ParsePort(t, server.Address),
251 SecLevel: e2e.SecurityLevelNone,
252 })
253 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
254 defer cancel()
255 if err := managementServer.Update(ctx, resources); err != nil {
256 t.Fatal(err)
257 }
258
259
260 target := fmt.Sprintf("xds:///%s", serviceName)
261 cc, err := grpc.NewClient(target, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
262 if err != nil {
263 t.Fatalf("Dialing target %q: %v", target, err)
264 }
265 defer cc.Close()
266 t.Log("Created ClientConn to test service")
267
268 client := testgrpc.NewTestServiceClient(cc)
269 if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
270 t.Fatalf("EmptyCall() RPC: %v", err)
271 }
272 t.Log("Successfully performed an EmptyCall RPC")
273
274 target = fmt.Sprintf("xds://unknown-authority/%s", serviceName)
275 t.Logf("Dialing target %q with unknown authority which is expected to fail", target)
276 wantErr := fmt.Sprintf("authority \"unknown-authority\" specified in dial target %q is not found in the bootstrap file", target)
277 _, err = grpc.Dial(target, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
278 if err == nil || !strings.Contains(err.Error(), wantErr) {
279 t.Fatalf("grpc.Dial(%q) returned %v, want: %s", target, err, wantErr)
280 }
281 }
282
283
284
285
286
287 func (s) TestFederation_UnknownAuthorityInReceivedResponse(t *testing.T) {
288 mgmtServer, err := e2e.StartManagementServer(e2e.ManagementServerOptions{})
289 if err != nil {
290 t.Fatalf("Failed to spin up the xDS management server: %v", err)
291 }
292 defer mgmtServer.Stop()
293
294 nodeID := uuid.New().String()
295 bootstrapContents, err := bootstrap.Contents(bootstrap.Options{
296 NodeID: nodeID,
297 ServerURI: mgmtServer.Address,
298 ServerListenerResourceNameTemplate: e2e.ServerListenerResourceNameTemplate,
299 })
300 if err != nil {
301 t.Fatal(err)
302 }
303
304 resolverBuilder := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))
305 resolver, err := resolverBuilder(bootstrapContents)
306 if err != nil {
307 t.Fatalf("Creating xDS resolver for testing: %v", err)
308 }
309
310
311
312 const serviceName = "my-service-client-side-xds"
313 const unknownAuthority = "unknown-authority"
314 ldsName := serviceName
315 rdsName := fmt.Sprintf("xdstp://%s/envoy.config.route.v3.RouteConfiguration/%s", unknownAuthority, "route-"+serviceName)
316
317 resources := e2e.UpdateOptions{
318 NodeID: nodeID,
319 Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)},
320 Routes: []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(rdsName, ldsName, "cluster-"+serviceName)},
321 SkipValidation: true,
322 }
323 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
324 defer cancel()
325 if err := mgmtServer.Update(ctx, resources); err != nil {
326 t.Fatal(err)
327 }
328
329 target := fmt.Sprintf("xds:///%s", serviceName)
330 cc, err := grpc.NewClient(target, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
331 if err != nil {
332 t.Fatalf("Dialing target %q: %v", target, err)
333 }
334 defer cc.Close()
335 t.Log("Created ClientConn to test service")
336
337 client := testgrpc.NewTestServiceClient(cc)
338 _, err = client.EmptyCall(ctx, &testpb.Empty{})
339 if err == nil {
340 t.Fatal("EmptyCall RPC succeeded for target with unknown authority when expected to fail")
341 }
342 if got, want := status.Code(err), codes.Unavailable; got != want {
343 t.Fatalf("EmptyCall RPC returned status code: %v, want %v", got, want)
344 }
345 if wantErr := `failed to find authority "unknown-authority"`; !strings.Contains(err.Error(), wantErr) {
346 t.Fatalf("EmptyCall RPC returned error: %v, want %v", err, wantErr)
347 }
348 }
349
View as plain text