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  }