google.golang.org/grpc@v1.62.1/xds/internal/xdsclient/tests/authority_test.go (about) 1 /* 2 * 3 * Copyright 2022 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package xdsclient_test 20 21 import ( 22 "context" 23 "testing" 24 "time" 25 26 "github.com/google/uuid" 27 "google.golang.org/grpc/internal/testutils" 28 "google.golang.org/grpc/internal/testutils/xds/e2e" 29 xdstestutils "google.golang.org/grpc/xds/internal/testutils" 30 "google.golang.org/grpc/xds/internal/xdsclient" 31 "google.golang.org/grpc/xds/internal/xdsclient/bootstrap" 32 "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" 33 34 v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" 35 v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 36 ) 37 38 const ( 39 testAuthority1 = "test-authority1" 40 testAuthority2 = "test-authority2" 41 testAuthority3 = "test-authority3" 42 ) 43 44 var ( 45 // These two resources use `testAuthority1`, which contains an empty server 46 // config in the bootstrap file, and therefore will use the default 47 // management server. 48 authorityTestResourceName11 = xdstestutils.BuildResourceName(xdsresource.ClusterResourceTypeName, testAuthority1, cdsName+"1", nil) 49 authorityTestResourceName12 = xdstestutils.BuildResourceName(xdsresource.ClusterResourceTypeName, testAuthority1, cdsName+"2", nil) 50 // This resource uses `testAuthority2`, which contains an empty server 51 // config in the bootstrap file, and therefore will use the default 52 // management server. 53 authorityTestResourceName2 = xdstestutils.BuildResourceName(xdsresource.ClusterResourceTypeName, testAuthority2, cdsName+"3", nil) 54 // This resource uses `testAuthority3`, which contains a non-empty server 55 // config in the bootstrap file, and therefore will use the non-default 56 // management server. 57 authorityTestResourceName3 = xdstestutils.BuildResourceName(xdsresource.ClusterResourceTypeName, testAuthority3, cdsName+"3", nil) 58 ) 59 60 // setupForAuthorityTests spins up two management servers, one to act as the 61 // default and the other to act as the non-default. It also generates a 62 // bootstrap configuration with three authorities (the first two pointing to the 63 // default and the third one pointing to the non-default). 64 // 65 // Returns two listeners used by the default and non-default management servers 66 // respectively, and the xDS client and its close function. 67 func setupForAuthorityTests(ctx context.Context, t *testing.T, idleTimeout time.Duration) (*testutils.ListenerWrapper, *testutils.ListenerWrapper, xdsclient.XDSClient, func()) { 68 // Create listener wrappers which notify on to a channel whenever a new 69 // connection is accepted. We use this to track the number of transports 70 // used by the xDS client. 71 lisDefault := testutils.NewListenerWrapper(t, nil) 72 lisNonDefault := testutils.NewListenerWrapper(t, nil) 73 74 // Start a management server to act as the default authority. 75 defaultAuthorityServer, err := e2e.StartManagementServer(e2e.ManagementServerOptions{Listener: lisDefault}) 76 if err != nil { 77 t.Fatalf("Failed to spin up the xDS management server: %v", err) 78 } 79 t.Cleanup(func() { defaultAuthorityServer.Stop() }) 80 81 // Start a management server to act as the non-default authority. 82 nonDefaultAuthorityServer, err := e2e.StartManagementServer(e2e.ManagementServerOptions{Listener: lisNonDefault}) 83 if err != nil { 84 t.Fatalf("Failed to spin up the xDS management server: %v", err) 85 } 86 t.Cleanup(func() { nonDefaultAuthorityServer.Stop() }) 87 88 // Create a bootstrap configuration with two non-default authorities which 89 // have empty server configs, and therefore end up using the default server 90 // config, which points to the above management server. 91 nodeID := uuid.New().String() 92 client, close, err := xdsclient.NewWithConfigForTesting(&bootstrap.Config{ 93 XDSServer: xdstestutils.ServerConfigForAddress(t, defaultAuthorityServer.Address), 94 NodeProto: &v3corepb.Node{Id: nodeID}, 95 Authorities: map[string]*bootstrap.Authority{ 96 testAuthority1: {}, 97 testAuthority2: {}, 98 testAuthority3: {XDSServer: xdstestutils.ServerConfigForAddress(t, nonDefaultAuthorityServer.Address)}, 99 }, 100 }, defaultTestWatchExpiryTimeout, idleTimeout) 101 if err != nil { 102 t.Fatalf("failed to create xds client: %v", err) 103 } 104 105 resources := e2e.UpdateOptions{ 106 NodeID: nodeID, 107 Clusters: []*v3clusterpb.Cluster{ 108 e2e.DefaultCluster(authorityTestResourceName11, edsName, e2e.SecurityLevelNone), 109 e2e.DefaultCluster(authorityTestResourceName12, edsName, e2e.SecurityLevelNone), 110 e2e.DefaultCluster(authorityTestResourceName2, edsName, e2e.SecurityLevelNone), 111 e2e.DefaultCluster(authorityTestResourceName3, edsName, e2e.SecurityLevelNone), 112 }, 113 SkipValidation: true, 114 } 115 if err := defaultAuthorityServer.Update(ctx, resources); err != nil { 116 t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err) 117 } 118 return lisDefault, lisNonDefault, client, close 119 } 120 121 // TestAuthorityShare tests the authority sharing logic. The test verifies the 122 // following scenarios: 123 // - A watch for a resource name with an authority matching an existing watch 124 // should not result in a new transport being created. 125 // - A watch for a resource name with different authority name but same 126 // authority config as an existing watch should not result in a new transport 127 // being created. 128 func (s) TestAuthorityShare(t *testing.T) { 129 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 130 defer cancel() 131 lis, _, client, close := setupForAuthorityTests(ctx, t, time.Duration(0)) 132 defer close() 133 134 // Verify that no connection is established to the management server at this 135 // point. A transport is created only when a resource (which belongs to that 136 // authority) is requested. 137 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 138 defer sCancel() 139 if _, err := lis.NewConnCh.Receive(sCtx); err != context.DeadlineExceeded { 140 t.Fatal("Unexpected new transport created to management server") 141 } 142 143 // Request the first resource. Verify that a new transport is created. 144 watcher := noopClusterWatcher{} 145 cdsCancel1 := xdsresource.WatchCluster(client, authorityTestResourceName11, watcher) 146 defer cdsCancel1() 147 if _, err := lis.NewConnCh.Receive(ctx); err != nil { 148 t.Fatalf("Timed out when waiting for a new transport to be created to the management server: %v", err) 149 } 150 151 // Request the second resource. Verify that no new transport is created. 152 cdsCancel2 := xdsresource.WatchCluster(client, authorityTestResourceName12, watcher) 153 defer cdsCancel2() 154 sCtx, sCancel = context.WithTimeout(ctx, defaultTestShortTimeout) 155 defer sCancel() 156 if _, err := lis.NewConnCh.Receive(sCtx); err != context.DeadlineExceeded { 157 t.Fatal("Unexpected new transport created to management server") 158 } 159 160 // Request the third resource. Verify that no new transport is created. 161 cdsCancel3 := xdsresource.WatchCluster(client, authorityTestResourceName2, watcher) 162 defer cdsCancel3() 163 sCtx, sCancel = context.WithTimeout(ctx, defaultTestShortTimeout) 164 defer sCancel() 165 if _, err := lis.NewConnCh.Receive(sCtx); err != context.DeadlineExceeded { 166 t.Fatal("Unexpected new transport created to management server") 167 } 168 } 169 170 // TestAuthorityIdle test the authority idle timeout logic. The test verifies 171 // that the xDS client does not close authorities immediately after the last 172 // watch is canceled, but waits for the configured idle timeout to expire before 173 // closing them. 174 func (s) TestAuthorityIdleTimeout(t *testing.T) { 175 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 176 defer cancel() 177 lis, _, client, close := setupForAuthorityTests(ctx, t, defaultTestIdleAuthorityTimeout) 178 defer close() 179 180 // Request the first resource. Verify that a new transport is created. 181 watcher := noopClusterWatcher{} 182 cdsCancel1 := xdsresource.WatchCluster(client, authorityTestResourceName11, watcher) 183 val, err := lis.NewConnCh.Receive(ctx) 184 if err != nil { 185 t.Fatalf("Timed out when waiting for a new transport to be created to the management server: %v", err) 186 } 187 conn := val.(*testutils.ConnWrapper) 188 189 // Request the second resource. Verify that no new transport is created. 190 cdsCancel2 := xdsresource.WatchCluster(client, authorityTestResourceName12, watcher) 191 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 192 defer sCancel() 193 if _, err := lis.NewConnCh.Receive(sCtx); err != context.DeadlineExceeded { 194 t.Fatal("Unexpected new transport created to management server") 195 } 196 197 // Cancel both watches, and verify that the connection to the management 198 // server is not closed immediately. 199 cdsCancel1() 200 cdsCancel2() 201 sCtx, sCancel = context.WithTimeout(ctx, defaultTestShortTimeout) 202 defer sCancel() 203 if _, err := conn.CloseCh.Receive(sCtx); err != context.DeadlineExceeded { 204 t.Fatal("Connection to management server closed unexpectedly") 205 } 206 207 // Wait for the authority idle timeout to fire. 208 time.Sleep(2 * defaultTestIdleAuthorityTimeout) 209 sCtx, sCancel = context.WithTimeout(ctx, defaultTestShortTimeout) 210 defer sCancel() 211 if _, err := conn.CloseCh.Receive(sCtx); err != nil { 212 t.Fatal("Connection to management server not closed after idle timeout expiry") 213 } 214 } 215 216 // TestAuthorityClientClose verifies that authorities in use and in the idle 217 // cache are all closed when the client is closed. 218 func (s) TestAuthorityClientClose(t *testing.T) { 219 // Set the authority idle timeout to twice the defaultTestTimeout. This will 220 // ensure that idle authorities stay in the cache for the duration of this 221 // test, until explicitly closed. 222 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 223 defer cancel() 224 lisDefault, lisNonDefault, client, close := setupForAuthorityTests(ctx, t, time.Duration(2*defaultTestTimeout)) 225 226 // Request the first resource. Verify that a new transport is created to the 227 // default management server. 228 watcher := noopClusterWatcher{} 229 cdsCancel1 := xdsresource.WatchCluster(client, authorityTestResourceName11, watcher) 230 val, err := lisDefault.NewConnCh.Receive(ctx) 231 if err != nil { 232 t.Fatalf("Timed out when waiting for a new transport to be created to the management server: %v", err) 233 } 234 connDefault := val.(*testutils.ConnWrapper) 235 236 // Request another resource which is served by the non-default authority. 237 // Verify that a new transport is created to the non-default management 238 // server. 239 xdsresource.WatchCluster(client, authorityTestResourceName3, watcher) 240 val, err = lisNonDefault.NewConnCh.Receive(ctx) 241 if err != nil { 242 t.Fatalf("Timed out when waiting for a new transport to be created to the management server: %v", err) 243 } 244 connNonDefault := val.(*testutils.ConnWrapper) 245 246 // Cancel the first watch. This should move the default authority to the 247 // idle cache, but the connection should not be closed yet, because the idle 248 // timeout would not have fired. 249 cdsCancel1() 250 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 251 defer sCancel() 252 if _, err := connDefault.CloseCh.Receive(sCtx); err != context.DeadlineExceeded { 253 t.Fatal("Connection to management server closed unexpectedly") 254 } 255 256 // Closing the xDS client should close the connection to both management 257 // servers, even though we have an open watch to one of them. 258 close() 259 if _, err := connDefault.CloseCh.Receive(ctx); err != nil { 260 t.Fatal("Connection to management server not closed after client close") 261 } 262 if _, err := connNonDefault.CloseCh.Receive(ctx); err != nil { 263 t.Fatal("Connection to management server not closed after client close") 264 } 265 } 266 267 // TestAuthorityRevive verifies that an authority in the idle cache is revived 268 // when a new watch is started on this authority. 269 func (s) TestAuthorityRevive(t *testing.T) { 270 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 271 defer cancel() 272 lis, _, client, close := setupForAuthorityTests(ctx, t, defaultTestIdleAuthorityTimeout) 273 defer close() 274 275 // Request the first resource. Verify that a new transport is created. 276 watcher := noopClusterWatcher{} 277 cdsCancel1 := xdsresource.WatchCluster(client, authorityTestResourceName11, watcher) 278 val, err := lis.NewConnCh.Receive(ctx) 279 if err != nil { 280 t.Fatalf("Timed out when waiting for a new transport to be created to the management server: %v", err) 281 } 282 conn := val.(*testutils.ConnWrapper) 283 284 // Cancel the above watch. This should move the authority to the idle cache. 285 cdsCancel1() 286 287 // Request the second resource. Verify that no new transport is created. 288 // This should move the authority out of the idle cache. 289 cdsCancel2 := xdsresource.WatchCluster(client, authorityTestResourceName12, watcher) 290 defer cdsCancel2() 291 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 292 defer sCancel() 293 if _, err := lis.NewConnCh.Receive(sCtx); err != context.DeadlineExceeded { 294 t.Fatal("Unexpected new transport created to management server") 295 } 296 297 // Wait for double the idle timeout, and the connection to the management 298 // server should not be closed, since it was revived from the idle cache. 299 time.Sleep(2 * defaultTestIdleAuthorityTimeout) 300 sCtx, sCancel = context.WithTimeout(ctx, defaultTestShortTimeout) 301 defer sCancel() 302 if _, err := conn.CloseCh.Receive(sCtx); err != context.DeadlineExceeded { 303 t.Fatal("Connection to management server closed unexpectedly") 304 } 305 }