mirror of https://github.com/grpc/grpc-go.git
xds: resubmit xds client pool changes from #7898 along with fix to set fallback bootstrap config from googledirectpath to xdsclient pool (#8050)
This commit is contained in:
parent
947e2a4be2
commit
79b6830e4b
|
@ -151,8 +151,8 @@ var (
|
|||
// other features, including the CSDS service.
|
||||
NewXDSResolverWithConfigForTesting any // func([]byte) (resolver.Builder, error)
|
||||
|
||||
// NewXDSResolverWithClientForTesting creates a new xDS resolver builder
|
||||
// using the provided xDS client instead of creating a new one using the
|
||||
// NewXDSResolverWithPoolForTesting creates a new xDS resolver builder
|
||||
// using the provided xDS pool instead of creating a new one using the
|
||||
// bootstrap configuration specified by the supported environment variables.
|
||||
// The resolver.Builder is meant to be used in conjunction with the
|
||||
// grpc.WithResolvers DialOption. The resolver.Builder does not take
|
||||
|
@ -163,7 +163,7 @@ var (
|
|||
//
|
||||
// This function should ONLY be used for testing and may not work with some
|
||||
// other features, including the CSDS service.
|
||||
NewXDSResolverWithClientForTesting any // func(xdsclient.XDSClient) (resolver.Builder, error)
|
||||
NewXDSResolverWithPoolForTesting any // func(*xdsclient.Pool) (resolver.Builder, error)
|
||||
|
||||
// RegisterRLSClusterSpecifierPluginForTesting registers the RLS Cluster
|
||||
// Specifier Plugin for testing purposes, regardless of the XDSRLS environment
|
||||
|
|
|
@ -49,13 +49,12 @@ func ManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, string, [
|
|||
bc := e2e.DefaultBootstrapContents(t, nodeID, xdsServer.Address)
|
||||
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
var r resolver.Builder
|
||||
var err error
|
||||
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
|
||||
r, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
r, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
return xdsServer, nodeID, bc, r
|
||||
|
|
|
@ -31,7 +31,6 @@ import (
|
|||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/tls/certprovider"
|
||||
|
@ -578,9 +577,6 @@ func (c *Config) UnmarshalJSON(data []byte) error {
|
|||
// specified at ${GRPC_XDS_BOOTSTRAP_CONFIG}. If both env vars are set, the
|
||||
// former is preferred.
|
||||
//
|
||||
// If none of the env vars are set, this function returns the fallback
|
||||
// configuration if it is not nil. Else, it returns an error.
|
||||
//
|
||||
// This function tries to process as much of the bootstrap file as possible (in
|
||||
// the presence of the errors) and may return a Config object with certain
|
||||
// fields left unspecified, in which case the caller should use some sane
|
||||
|
@ -597,27 +593,22 @@ func GetConfiguration() (*Config, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("xds: failed to read bootstrap config from file %q: %v", fName, err)
|
||||
}
|
||||
return newConfigFromContents(cfg)
|
||||
return NewConfigFromContents(cfg)
|
||||
}
|
||||
|
||||
if fContent != "" {
|
||||
if logger.V(2) {
|
||||
logger.Infof("Using bootstrap contents from GRPC_XDS_BOOTSTRAP_CONFIG environment variable")
|
||||
}
|
||||
return newConfigFromContents([]byte(fContent))
|
||||
return NewConfigFromContents([]byte(fContent))
|
||||
}
|
||||
|
||||
if cfg := fallbackBootstrapConfig(); cfg != nil {
|
||||
if logger.V(2) {
|
||||
logger.Infof("Using bootstrap contents from fallback config")
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("bootstrap environment variables (%q or %q) not defined, and no fallback config set", envconfig.XDSBootstrapFileNameEnv, envconfig.XDSBootstrapFileContentEnv)
|
||||
return nil, fmt.Errorf("bootstrap environment variables (%q or %q) not defined", envconfig.XDSBootstrapFileNameEnv, envconfig.XDSBootstrapFileContentEnv)
|
||||
}
|
||||
|
||||
func newConfigFromContents(data []byte) (*Config, error) {
|
||||
// NewConfigFromContents creates a new bootstrap configuration from the provided
|
||||
// contents.
|
||||
func NewConfigFromContents(data []byte) (*Config, error) {
|
||||
// Normalize the input configuration.
|
||||
buf := bytes.Buffer{}
|
||||
err := json.Indent(&buf, data, "", "")
|
||||
|
@ -700,14 +691,6 @@ func NewContentsForTesting(opts ConfigOptionsForTesting) ([]byte, error) {
|
|||
return contents, nil
|
||||
}
|
||||
|
||||
// NewConfigForTesting creates a new bootstrap configuration from the provided
|
||||
// contents, for testing purposes.
|
||||
//
|
||||
// # Testing-Only
|
||||
func NewConfigForTesting(contents []byte) (*Config, error) {
|
||||
return newConfigFromContents(contents)
|
||||
}
|
||||
|
||||
// certproviderNameAndConfig is the internal representation of
|
||||
// the`certificate_providers` field in the bootstrap configuration.
|
||||
type certproviderNameAndConfig struct {
|
||||
|
@ -810,44 +793,3 @@ func (n node) toProto() *v3corepb.Node {
|
|||
ClientFeatures: slices.Clone(n.clientFeatures),
|
||||
}
|
||||
}
|
||||
|
||||
// SetFallbackBootstrapConfig sets the fallback bootstrap configuration to be
|
||||
// used when the bootstrap environment variables are unset.
|
||||
//
|
||||
// The provided configuration must be valid JSON. Returns a non-nil error if
|
||||
// parsing the provided configuration fails.
|
||||
func SetFallbackBootstrapConfig(cfgJSON []byte) error {
|
||||
config, err := newConfigFromContents(cfgJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configMu.Lock()
|
||||
defer configMu.Unlock()
|
||||
fallbackBootstrapCfg = config
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnsetFallbackBootstrapConfigForTesting unsets the fallback bootstrap
|
||||
// configuration to be used when the bootstrap environment variables are unset.
|
||||
//
|
||||
// # Testing-Only
|
||||
func UnsetFallbackBootstrapConfigForTesting() {
|
||||
configMu.Lock()
|
||||
defer configMu.Unlock()
|
||||
fallbackBootstrapCfg = nil
|
||||
}
|
||||
|
||||
// fallbackBootstrapConfig returns the fallback bootstrap configuration
|
||||
// that will be used by the xDS client when the bootstrap environment
|
||||
// variables are unset.
|
||||
func fallbackBootstrapConfig() *Config {
|
||||
configMu.Lock()
|
||||
defer configMu.Unlock()
|
||||
return fallbackBootstrapCfg
|
||||
}
|
||||
|
||||
var (
|
||||
configMu sync.Mutex
|
||||
fallbackBootstrapCfg *Config
|
||||
)
|
||||
|
|
|
@ -131,12 +131,12 @@ func (s) TestClientResourceVersionAfterStreamRestart(t *testing.T) {
|
|||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address)
|
||||
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
var xdsResolver resolver.Builder
|
||||
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
|
||||
xdsResolver, err = newResolver.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
server := stubserver.StartTestService(t, nil)
|
||||
|
|
|
@ -129,12 +129,12 @@ func (s) TestClientSideXDS_WithNoCertificateProvidersInBootstrap_Failure(t *test
|
|||
}
|
||||
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
var resolverBuilder resolver.Builder
|
||||
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
|
||||
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
// Spin up a test backend.
|
||||
|
|
|
@ -105,12 +105,12 @@ func (s) TestClientCustomDialerFromCredentialsBundle(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
var resolverBuilder resolver.Builder
|
||||
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
|
||||
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
// Spin up a test backend.
|
||||
|
|
|
@ -87,8 +87,10 @@ func (s) TestClientSideFederation(t *testing.T) {
|
|||
t.Fatalf("Failed to create bootstrap file: %v", err)
|
||||
}
|
||||
|
||||
resolverBuilder := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(bootstrapContents)
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
resolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
@ -181,8 +183,10 @@ func (s) TestClientSideFederationWithOnlyXDSTPStyleLDS(t *testing.T) {
|
|||
t.Fatalf("Failed to create bootstrap file: %v", err)
|
||||
}
|
||||
|
||||
resolverBuilder := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(bootstrapContents)
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
resolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
|
|
@ -289,8 +289,10 @@ func generateBootstrapContents(t *testing.T, serverURI string, ignoreResourceDel
|
|||
// as parameter.
|
||||
func xdsResolverBuilder(t *testing.T, bs []byte) resolver.Builder {
|
||||
t.Helper()
|
||||
resolverBuilder := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))
|
||||
xdsR, err := resolverBuilder(bs)
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
xdsR, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bs)
|
||||
if err != nil {
|
||||
t.Fatalf("Creating xDS resolver for testing failed for config %q: %v", string(bs), err)
|
||||
}
|
||||
|
|
|
@ -329,13 +329,12 @@ func (s) TestUnmarshalCluster_WithUpdateValidatorFunc(t *testing.T) {
|
|||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address)
|
||||
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
var xdsResolver resolver.Builder
|
||||
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
|
||||
var err error
|
||||
xdsResolver, err = newResolver.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
server := stubserver.StartTestService(t, nil)
|
||||
|
|
|
@ -325,13 +325,12 @@ func (s) TestServerSideXDS_SecurityConfigChange(t *testing.T) {
|
|||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address)
|
||||
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
var xdsResolver resolver.Builder
|
||||
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
|
||||
var err error
|
||||
xdsResolver, err = newResolver.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
|
||||
|
|
|
@ -35,6 +35,7 @@ import (
|
|||
"google.golang.org/grpc/internal/pretty"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/csds"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
|
@ -220,22 +221,28 @@ func (s) TestCSDS(t *testing.T) {
|
|||
// Create a bootstrap contents pointing to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
// We use the default xDS client pool here because the CSDS service reports
|
||||
// on the state of the default xDS client which is implicitly managed
|
||||
// within the xdsclient.DefaultPool.
|
||||
xdsclient.DefaultPool.SetFallbackBootstrapConfig(config)
|
||||
defer func() { xdsclient.DefaultPool.UnsetBootstrapConfigForTesting() }()
|
||||
// Create two xDS clients, with different names. These should end up
|
||||
// creating two different xDS clients.
|
||||
const xdsClient1Name = "xds-csds-client-1"
|
||||
xdsClient1, xdsClose1, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient1Name,
|
||||
Contents: bootstrapContents,
|
||||
xdsClient1, xdsClose1, err := xdsclient.DefaultPool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient1Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
defer xdsClose1()
|
||||
const xdsClient2Name = "xds-csds-client-2"
|
||||
xdsClient2, xdsClose2, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient2Name,
|
||||
Contents: bootstrapContents,
|
||||
xdsClient2, xdsClose2, err := xdsclient.DefaultPool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient2Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -417,22 +424,28 @@ func (s) TestCSDS_NACK(t *testing.T) {
|
|||
// Create a bootstrap contents pointing to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
// We use the default xDS client pool here because the CSDS service reports
|
||||
// on the state of the default xDS client which is implicitly managed
|
||||
// within the xdsclient.DefaultPool.
|
||||
xdsclient.DefaultPool.SetFallbackBootstrapConfig(config)
|
||||
defer func() { xdsclient.DefaultPool.UnsetBootstrapConfigForTesting() }()
|
||||
// Create two xDS clients, with different names. These should end up
|
||||
// creating two different xDS clients.
|
||||
const xdsClient1Name = "xds-csds-client-1"
|
||||
xdsClient1, xdsClose1, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient1Name,
|
||||
Contents: bootstrapContents,
|
||||
xdsClient1, xdsClose1, err := xdsclient.DefaultPool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient1Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
defer xdsClose1()
|
||||
const xdsClient2Name = "xds-csds-client-2"
|
||||
xdsClient2, xdsClose2, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient2Name,
|
||||
Contents: bootstrapContents,
|
||||
xdsClient2, xdsClose2, err := xdsclient.DefaultPool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: xdsClient2Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -39,6 +39,7 @@ import (
|
|||
internalgrpclog "google.golang.org/grpc/internal/grpclog"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
|
||||
_ "google.golang.org/grpc/xds" // To register xds resolvers and balancers.
|
||||
)
|
||||
|
@ -62,8 +63,9 @@ var (
|
|||
universeDomainMu sync.Mutex
|
||||
universeDomain = ""
|
||||
// For overriding in unittests.
|
||||
onGCE = googlecloud.OnGCE
|
||||
randInt = rand.Int
|
||||
onGCE = googlecloud.OnGCE
|
||||
randInt = rand.Int
|
||||
xdsClientPool = xdsclient.DefaultPool
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -155,9 +157,11 @@ func (c2pResolverBuilder) Build(t resolver.Target, cc resolver.ClientConn, opts
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal bootstrap configuration: %v", err)
|
||||
}
|
||||
if err := bootstrap.SetFallbackBootstrapConfig(cfgJSON); err != nil {
|
||||
return nil, fmt.Errorf("failed to set fallback bootstrap configuration: %v", err)
|
||||
config, err := bootstrap.NewConfigFromContents(cfgJSON)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse bootstrap contents: %s, %v", string(cfgJSON), err)
|
||||
}
|
||||
xdsClientPool.SetFallbackBootstrapConfig(config)
|
||||
|
||||
t = resolver.Target{
|
||||
URL: url.URL{
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"google.golang.org/grpc/internal/grpctest"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
)
|
||||
|
||||
type s struct {
|
||||
|
@ -114,6 +115,11 @@ func (s) TestBuildWithBootstrapEnvSet(t *testing.T) {
|
|||
*envP = "does not matter"
|
||||
defer func() { *envP = oldEnv }()
|
||||
|
||||
// Override xDS client pool.
|
||||
oldXdsClientPool := xdsClientPool
|
||||
xdsClientPool = xdsclient.NewPool(nil)
|
||||
defer func() { xdsClientPool = oldXdsClientPool }()
|
||||
|
||||
// Build the google-c2p resolver.
|
||||
r, err := builder.Build(resolver.Target{}, nil, resolver.BuildOptions{})
|
||||
if err != nil {
|
||||
|
@ -157,7 +163,7 @@ func bootstrapConfig(t *testing.T, opts bootstrap.ConfigOptionsForTesting) *boot
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap contents: %v", err)
|
||||
}
|
||||
cfg, err := bootstrap.NewConfigForTesting(contents)
|
||||
cfg, err := bootstrap.NewConfigFromContents(contents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap config: %v", err)
|
||||
}
|
||||
|
@ -286,6 +292,14 @@ func (s) TestBuildXDS(t *testing.T) {
|
|||
defer func() { envconfig.C2PResolverTestOnlyTrafficDirectorURI = oldURI }()
|
||||
}
|
||||
|
||||
// Override xDS client pool.
|
||||
oldXdsClientPool := xdsClientPool
|
||||
xdsClientPool = xdsclient.NewPool(nil)
|
||||
defer func() { xdsClientPool = oldXdsClientPool }()
|
||||
|
||||
getIPv6Capable = func(time.Duration) bool { return tt.ipv6Capable }
|
||||
defer func() { getIPv6Capable = oldGetIPv6Capability }()
|
||||
|
||||
// Build the google-c2p resolver.
|
||||
r, err := builder.Build(resolver.Target{}, nil, resolver.BuildOptions{})
|
||||
if err != nil {
|
||||
|
@ -298,8 +312,8 @@ func (s) TestBuildXDS(t *testing.T) {
|
|||
t.Fatalf("Build() returned %#v, want xds resolver", r)
|
||||
}
|
||||
|
||||
gotConfig, err := bootstrap.GetConfiguration()
|
||||
if err != nil {
|
||||
gotConfig := xdsClientPool.BootstrapConfigForTesting()
|
||||
if gotConfig == nil {
|
||||
t.Fatalf("Failed to get bootstrap config: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(tt.wantBootstrapConfig, gotConfig); diff != "" {
|
||||
|
@ -375,6 +389,11 @@ func (s) TestSetUniverseDomainNonDefault(t *testing.T) {
|
|||
t.Fatalf("googlec2p.SetUniverseDomain(%s) failed: %v", testUniverseDomain, err)
|
||||
}
|
||||
|
||||
// Override xDS client pool.
|
||||
oldXdsClientPool := xdsClientPool
|
||||
xdsClientPool = xdsclient.NewPool(nil)
|
||||
defer func() { xdsClientPool = oldXdsClientPool }()
|
||||
|
||||
// Build the google-c2p resolver.
|
||||
r, err := builder.Build(resolver.Target{}, nil, resolver.BuildOptions{})
|
||||
if err != nil {
|
||||
|
@ -387,8 +406,8 @@ func (s) TestSetUniverseDomainNonDefault(t *testing.T) {
|
|||
t.Fatalf("Build() returned %#v, want xds resolver", r)
|
||||
}
|
||||
|
||||
gotConfig, err := bootstrap.GetConfiguration()
|
||||
if err != nil {
|
||||
gotConfig := xdsClientPool.BootstrapConfigForTesting()
|
||||
if gotConfig == nil {
|
||||
t.Fatalf("Failed to get bootstrap config: %v", err)
|
||||
}
|
||||
|
||||
|
@ -442,6 +461,11 @@ func (s) TestDefaultUniverseDomain(t *testing.T) {
|
|||
randInt = func() int { return 666 }
|
||||
defer func() { randInt = origRandInd }()
|
||||
|
||||
// Override xDS client pool.
|
||||
oldXdsClientPool := xdsClientPool
|
||||
xdsClientPool = xdsclient.NewPool(nil)
|
||||
defer func() { xdsClientPool = oldXdsClientPool }()
|
||||
|
||||
// Build the google-c2p resolver.
|
||||
r, err := builder.Build(resolver.Target{}, nil, resolver.BuildOptions{})
|
||||
if err != nil {
|
||||
|
@ -454,8 +478,8 @@ func (s) TestDefaultUniverseDomain(t *testing.T) {
|
|||
t.Fatalf("Build() returned %#v, want xds resolver", r)
|
||||
}
|
||||
|
||||
gotConfig, err := bootstrap.GetConfiguration()
|
||||
if err != nil {
|
||||
gotConfig := xdsClientPool.BootstrapConfigForTesting()
|
||||
if gotConfig == nil {
|
||||
t.Fatalf("Failed to get bootstrap config: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -139,9 +139,13 @@ func registerWrappedCDSPolicyWithNewSubConnOverride(t *testing.T, ch chan *xdscr
|
|||
func setupForSecurityTests(t *testing.T, bootstrapContents []byte, clientCreds, serverCreds credentials.TransportCredentials) (*grpc.ClientConn, string) {
|
||||
t.Helper()
|
||||
|
||||
xdsClient, xdsClose, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsClient, xdsClose, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -241,9 +241,13 @@ func setupWithManagementServerAndListener(t *testing.T, lis net.Listener) (*e2e.
|
|||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
xdsC, xdsClose, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsC, xdsClose, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -364,9 +368,13 @@ func (s) TestConfigurationUpdate_EmptyCluster(t *testing.T) {
|
|||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
xdsClient, xdsClose, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsClient, xdsClose, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -36,6 +36,7 @@ import (
|
|||
"google.golang.org/grpc/internal/stubserver"
|
||||
"google.golang.org/grpc/internal/testutils/pickfirst"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/peer"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/resolver/manual"
|
||||
|
@ -1180,9 +1181,13 @@ func (s) TestAggregateCluster_Fallback_EDS_ResourceNotFound(t *testing.T) {
|
|||
|
||||
// Create an xDS client talking to the above management server, configured
|
||||
// with a short watch expiry timeout.
|
||||
xdsClient, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsClient, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
"google.golang.org/grpc/internal/stubserver"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/resolver/manual"
|
||||
"google.golang.org/grpc/serviceconfig"
|
||||
|
@ -74,9 +75,13 @@ func setupAndDial(t *testing.T, bootstrapContents []byte) (*grpc.ClientConn, fun
|
|||
t.Helper()
|
||||
|
||||
// Create an xDS client for use by the cluster_resolver LB policy.
|
||||
xdsC, xdsClose, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsC, xdsClose, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -40,6 +40,7 @@ import (
|
|||
"google.golang.org/grpc/internal/testutils"
|
||||
rrutil "google.golang.org/grpc/internal/testutils/roundrobin"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/peer"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/resolver/manual"
|
||||
|
@ -155,9 +156,13 @@ func (s) TestEDS_OneLocality(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client for use by the cluster_resolver LB policy.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -290,9 +295,13 @@ func (s) TestEDS_MultipleLocalities(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client for use by the cluster_resolver LB policy.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -454,9 +463,13 @@ func (s) TestEDS_EndpointsHealth(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client for use by the cluster_resolver LB policy.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -527,9 +540,13 @@ func (s) TestEDS_EmptyUpdate(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client for use by the cluster_resolver LB policy.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -926,9 +943,13 @@ func (s) TestEDS_BadUpdateWithoutPreviousGoodUpdate(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client for use by the cluster_resolver LB policy.
|
||||
xdsClient, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsClient, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -998,9 +1019,13 @@ func (s) TestEDS_BadUpdateWithPreviousGoodUpdate(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client for use by the cluster_resolver LB policy.
|
||||
xdsClient, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsClient, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -1070,9 +1095,13 @@ func (s) TestEDS_ResourceNotFound(t *testing.T) {
|
|||
// with a short watch expiry timeout.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
xdsClient, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsClient, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -1244,6 +1273,11 @@ func (s) TestEDS_EndpointWithMultipleAddresses(t *testing.T) {
|
|||
// Create bootstrap configuration pointing to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
|
||||
// Create xDS resources for consumption by the test. We start off with a
|
||||
// single backend in a single EDS locality.
|
||||
|
@ -1260,9 +1294,8 @@ func (s) TestEDS_EndpointWithMultipleAddresses(t *testing.T) {
|
|||
|
||||
// Create an xDS client talking to the above management server, configured
|
||||
// with a short watch expiry timeout.
|
||||
xdsClient, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
xdsClient, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an xDS client: %v", err)
|
||||
|
|
|
@ -265,13 +265,12 @@ func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, stri
|
|||
bc := e2e.DefaultBootstrapContents(t, nodeID, xdsServer.Address)
|
||||
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
var r resolver.Builder
|
||||
var err error
|
||||
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
|
||||
r, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
r, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
return xdsServer, nodeID, r
|
||||
|
|
|
@ -36,11 +36,13 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/internal"
|
||||
"google.golang.org/grpc/internal/grpctest"
|
||||
"google.golang.org/grpc/internal/stubserver"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
@ -76,17 +78,18 @@ func Test(t *testing.T) {
|
|||
// Returns the following:
|
||||
// - the management server: tests use this to configure resources
|
||||
// - nodeID expected by the management server: this is set in the Node proto
|
||||
// sent by the xdsClient for queries.
|
||||
// sent by the xdsClient for queries
|
||||
// - the port the server is listening on
|
||||
// - cleanup function to be invoked by the tests when done
|
||||
func clientSetup(t *testing.T) (*e2e.ManagementServer, string, uint32) {
|
||||
// - contents of the bootstrap configuration pointing to xDS management
|
||||
// server
|
||||
func clientSetup(t *testing.T) (*e2e.ManagementServer, string, uint32, []byte) {
|
||||
// Spin up a xDS management server on a local port.
|
||||
nodeID := uuid.New().String()
|
||||
managementServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
|
||||
|
||||
// Create a bootstrap file in a temporary directory.
|
||||
// Create a bootstrap config pointing to the above management server with
|
||||
// the nodeID.
|
||||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bootstrapContents)
|
||||
|
||||
// Create a local listener.
|
||||
lis, err := testutils.LocalTCPListener()
|
||||
|
@ -114,7 +117,7 @@ func clientSetup(t *testing.T) (*e2e.ManagementServer, string, uint32) {
|
|||
|
||||
stubserver.StartTestService(t, stub)
|
||||
t.Cleanup(stub.S.Stop)
|
||||
return managementServer, nodeID, uint32(lis.Addr().(*net.TCPAddr).Port)
|
||||
return managementServer, nodeID, uint32(lis.Addr().(*net.TCPAddr).Port), bootstrapContents
|
||||
}
|
||||
|
||||
func (s) TestFaultInjection_Unary(t *testing.T) {
|
||||
|
@ -456,7 +459,15 @@ func (s) TestFaultInjection_Unary(t *testing.T) {
|
|||
}},
|
||||
}}
|
||||
|
||||
fs, nodeID, port := clientSetup(t)
|
||||
fs, nodeID, port, bc := clientSetup(t)
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
for tcNum, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
@ -506,7 +517,7 @@ func (s) TestFaultInjection_Unary(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a ClientConn and run the test case.
|
||||
cc, err := grpc.NewClient("xds:///"+serviceName, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
cc, err := grpc.NewClient("xds:///"+serviceName, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(xdsResolver))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial local test server: %v", err)
|
||||
}
|
||||
|
@ -538,7 +549,15 @@ func (s) TestFaultInjection_Unary(t *testing.T) {
|
|||
}
|
||||
|
||||
func (s) TestFaultInjection_MaxActiveFaults(t *testing.T) {
|
||||
fs, nodeID, port := clientSetup(t)
|
||||
fs, nodeID, port, bc := clientSetup(t)
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
resources := e2e.DefaultClientResources(e2e.ResourceParams{
|
||||
DialTarget: "myservice",
|
||||
NodeID: nodeID,
|
||||
|
@ -548,8 +567,7 @@ func (s) TestFaultInjection_MaxActiveFaults(t *testing.T) {
|
|||
})
|
||||
hcm := new(v3httppb.HttpConnectionManager)
|
||||
lis := resources.Listeners[0].GetApiListener().GetApiListener()
|
||||
err := lis.UnmarshalTo(hcm)
|
||||
if err != nil {
|
||||
if err = lis.UnmarshalTo(hcm); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -581,7 +599,7 @@ func (s) TestFaultInjection_MaxActiveFaults(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a ClientConn
|
||||
cc, err := grpc.NewClient("xds:///myservice", grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
cc, err := grpc.NewClient("xds:///myservice", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(xdsResolver))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial local test server: %v", err)
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ func (s) TestResolverClusterSpecifierPlugin(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
|
@ -128,7 +128,7 @@ func (s) TestResolverClusterSpecifierPlugin(t *testing.T) {
|
|||
})}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Wait for an update from the resolver, and verify the service config.
|
||||
wantSC := `
|
||||
|
@ -205,7 +205,7 @@ func (s) TestXDSResolverDelayedOnCommittedCSP(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
|
@ -218,7 +218,7 @@ func (s) TestXDSResolverDelayedOnCommittedCSP(t *testing.T) {
|
|||
})}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Wait for an update from the resolver, and verify the service config.
|
||||
wantSC := `
|
||||
|
|
|
@ -78,17 +78,33 @@ var wantDefaultServiceConfig = fmt.Sprintf(`{
|
|||
}]
|
||||
}`, defaultTestClusterName, defaultTestClusterName)
|
||||
|
||||
// buildResolverForTarget builds an xDS resolver for the given target. It
|
||||
// returns the following:
|
||||
// buildResolverForTarget builds an xDS resolver for the given target. If
|
||||
// the bootstrap contents are provided, it build the xDS resolver using them
|
||||
// otherwise, it uses the default xDS resolver.
|
||||
//
|
||||
// It returns the following:
|
||||
// - a channel to read updates from the resolver
|
||||
// - a channel to read errors from the resolver
|
||||
// - the newly created xDS resolver
|
||||
func buildResolverForTarget(t *testing.T, target resolver.Target) (chan resolver.State, chan error, resolver.Resolver) {
|
||||
func buildResolverForTarget(t *testing.T, target resolver.Target, bootstrapContents []byte) (chan resolver.State, chan error, resolver.Resolver) {
|
||||
t.Helper()
|
||||
|
||||
builder := resolver.Get(xdsresolver.Scheme)
|
||||
if builder == nil {
|
||||
t.Fatalf("Scheme %q is not registered", xdsresolver.Scheme)
|
||||
var builder resolver.Builder
|
||||
if bootstrapContents != nil {
|
||||
// Create an xDS resolver with the provided bootstrap configuration.
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
var err error
|
||||
builder, err = internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
} else {
|
||||
builder = resolver.Get(xdsresolver.Scheme)
|
||||
if builder == nil {
|
||||
t.Fatalf("Scheme %q is not registered", xdsresolver.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
stateCh := make(chan resolver.State, 1)
|
||||
|
@ -186,7 +202,9 @@ func verifyErrorFromResolver(ctx context.Context, t *testing.T, errCh chan error
|
|||
// - A reference to the xDS management server
|
||||
// - A channel to read requested Listener resource names
|
||||
// - A channel to read requested RouteConfiguration resource names
|
||||
func setupManagementServerForTest(ctx context.Context, t *testing.T, nodeID string) (*e2e.ManagementServer, chan []string, chan []string) {
|
||||
// - Contents of the bootstrap configuration pointing to xDS management
|
||||
// server
|
||||
func setupManagementServerForTest(ctx context.Context, t *testing.T, nodeID string) (*e2e.ManagementServer, chan []string, chan []string, []byte) {
|
||||
t.Helper()
|
||||
|
||||
listenerResourceNamesCh := make(chan []string, 1)
|
||||
|
@ -224,8 +242,7 @@ func setupManagementServerForTest(ctx context.Context, t *testing.T, nodeID stri
|
|||
|
||||
// Create a bootstrap configuration specifying the above management server.
|
||||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bootstrapContents)
|
||||
return mgmtServer, listenerResourceNamesCh, routeConfigResourceNamesCh
|
||||
return mgmtServer, listenerResourceNamesCh, routeConfigResourceNamesCh, bootstrapContents
|
||||
}
|
||||
|
||||
// Spins up an xDS management server and configures it with a default listener
|
||||
|
|
|
@ -46,14 +46,14 @@ func (s) TestServiceWatch_ListenerPointsToNewRouteConfiguration(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, lisCh, routeCfgCh := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, lisCh, routeCfgCh, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Verify initial update from the resolver.
|
||||
waitForResourceNames(ctx, t, lisCh, []string{defaultTestServiceName})
|
||||
|
@ -103,14 +103,14 @@ func (s) TestServiceWatch_ListenerPointsToInlineRouteConfiguration(t *testing.T)
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, lisCh, routeCfgCh := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, lisCh, routeCfgCh, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Verify initial update from the resolver.
|
||||
waitForResourceNames(ctx, t, lisCh, []string{defaultTestServiceName})
|
||||
|
|
|
@ -45,25 +45,29 @@ import (
|
|||
const Scheme = "xds"
|
||||
|
||||
// newBuilderWithConfigForTesting creates a new xds resolver builder using a
|
||||
// specific xds bootstrap config, so tests can use multiple xds clients in
|
||||
// different ClientConns at the same time.
|
||||
// specific xds bootstrap config, so tests can use multiple xDS clients in
|
||||
// different ClientConns at the same time. The builder creates a new pool with
|
||||
// the provided config and a new xDS client in that pool.
|
||||
func newBuilderWithConfigForTesting(config []byte) (resolver.Builder, error) {
|
||||
return &xdsResolverBuilder{
|
||||
newXDSClient: func(name string) (xdsclient.XDSClient, func(), error) {
|
||||
return xdsclient.NewForTesting(xdsclient.OptionsForTesting{Name: name, Contents: config})
|
||||
config, err := bootstrap.NewConfigFromContents(config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
return pool.NewClientForTesting(xdsclient.OptionsForTesting{Name: name})
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// newBuilderWithClientForTesting creates a new xds resolver builder using the
|
||||
// specific xDS client, so that tests have complete control over the exact
|
||||
// specific xDS client being used.
|
||||
func newBuilderWithClientForTesting(client xdsclient.XDSClient) (resolver.Builder, error) {
|
||||
// newBuilderWithPoolForTesting creates a new xds resolver builder using the
|
||||
// specific xds client pool, so that tests have complete control over the exact
|
||||
// specific xds client pool being used.
|
||||
func newBuilderWithPoolForTesting(pool *xdsclient.Pool) (resolver.Builder, error) {
|
||||
return &xdsResolverBuilder{
|
||||
newXDSClient: func(string) (xdsclient.XDSClient, func(), error) {
|
||||
// Returning an empty close func here means that the responsibility
|
||||
// of closing the client lies with the caller.
|
||||
return client, func() {}, nil
|
||||
newXDSClient: func(name string) (xdsclient.XDSClient, func(), error) {
|
||||
return pool.NewClientForTesting(xdsclient.OptionsForTesting{Name: name})
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@ -71,10 +75,10 @@ func newBuilderWithClientForTesting(client xdsclient.XDSClient) (resolver.Builde
|
|||
func init() {
|
||||
resolver.Register(&xdsResolverBuilder{})
|
||||
internal.NewXDSResolverWithConfigForTesting = newBuilderWithConfigForTesting
|
||||
internal.NewXDSResolverWithClientForTesting = newBuilderWithClientForTesting
|
||||
internal.NewXDSResolverWithPoolForTesting = newBuilderWithPoolForTesting
|
||||
|
||||
rinternal.NewWRR = wrr.NewRandom
|
||||
rinternal.NewXDSClient = xdsclient.New
|
||||
rinternal.NewXDSClient = xdsclient.DefaultPool.NewClient
|
||||
}
|
||||
|
||||
type xdsResolverBuilder struct {
|
||||
|
@ -83,7 +87,7 @@ type xdsResolverBuilder struct {
|
|||
|
||||
// Build helps implement the resolver.Builder interface.
|
||||
//
|
||||
// The xds bootstrap process is performed (and a new xds client is built) every
|
||||
// The xds bootstrap process is performed (and a new xDS client is built) every
|
||||
// time an xds resolver is built.
|
||||
func (b *xdsResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (_ resolver.Resolver, retErr error) {
|
||||
r := &xdsResolver{
|
||||
|
|
|
@ -44,7 +44,6 @@ import (
|
|||
"google.golang.org/grpc/xds/internal/balancer/clustermanager"
|
||||
"google.golang.org/grpc/xds/internal/balancer/ringhash"
|
||||
"google.golang.org/grpc/xds/internal/httpfilter"
|
||||
xdsresolver "google.golang.org/grpc/xds/internal/resolver"
|
||||
rinternal "google.golang.org/grpc/xds/internal/resolver/internal"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version"
|
||||
|
@ -67,18 +66,24 @@ import (
|
|||
)
|
||||
|
||||
// Tests the case where xDS client creation is expected to fail because the
|
||||
// bootstrap configuration is not specified. The test verifies that xDS resolver
|
||||
// build fails as well.
|
||||
// bootstrap configuration for the xDS client pool is not specified. The test
|
||||
// verifies that xDS resolver build fails as well.
|
||||
func (s) TestResolverBuilder_ClientCreationFails_NoBootstrap(t *testing.T) {
|
||||
// Build an xDS resolver without specifying bootstrap env vars.
|
||||
builder := resolver.Get(xdsresolver.Scheme)
|
||||
if builder == nil {
|
||||
t.Fatalf("Scheme %q is not registered", xdsresolver.Scheme)
|
||||
// Build an xDS resolver specifying nil for bootstrap configuration for the
|
||||
// xDS client pool.
|
||||
pool := xdsclient.NewPool(nil)
|
||||
var xdsResolver resolver.Builder
|
||||
if newResolver := internal.NewXDSResolverWithPoolForTesting; newResolver != nil {
|
||||
var err error
|
||||
xdsResolver, err = newResolver.(func(*xdsclient.Pool) (resolver.Builder, error))(pool)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
target := resolver.Target{URL: *testutils.MustParseURL("xds:///target")}
|
||||
if _, err := builder.Build(target, nil, resolver.BuildOptions{}); err == nil {
|
||||
t.Fatalf("xds Resolver Build(%v) succeeded when expected to fail, because there is not bootstrap configuration for the xDS client", target)
|
||||
if _, err := xdsResolver.Build(target, nil, resolver.BuildOptions{}); err == nil {
|
||||
t.Fatalf("xds Resolver Build(%v) succeeded when expected to fail, because there is no bootstrap configuration for the xDS client pool", pool)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,17 +92,19 @@ func (s) TestResolverBuilder_ClientCreationFails_NoBootstrap(t *testing.T) {
|
|||
// fails with the expected error string.
|
||||
func (s) TestResolverBuilder_AuthorityNotDefinedInBootstrap(t *testing.T) {
|
||||
contents := e2e.DefaultBootstrapContents(t, "node-id", "dummy-management-server")
|
||||
testutils.CreateBootstrapFileForTesting(t, contents)
|
||||
|
||||
builder := resolver.Get(xdsresolver.Scheme)
|
||||
if builder == nil {
|
||||
t.Fatalf("Scheme %q is not registered", xdsresolver.Scheme)
|
||||
// Create an xDS resolver with the above bootstrap configuration.
|
||||
if internal.NewXDSResolverWithConfigForTesting == nil {
|
||||
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
|
||||
}
|
||||
xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(contents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
||||
target := resolver.Target{URL: *testutils.MustParseURL("xds://non-existing-authority/target")}
|
||||
const wantErr = `authority "non-existing-authority" specified in dial target "xds://non-existing-authority/target" is not found in the bootstrap file`
|
||||
|
||||
r, err := builder.Build(target, &testutils.ResolverClientConn{Logger: t}, resolver.BuildOptions{})
|
||||
r, err := xdsResolver.Build(target, &testutils.ResolverClientConn{Logger: t}, resolver.BuildOptions{})
|
||||
if r != nil {
|
||||
r.Close()
|
||||
}
|
||||
|
@ -157,7 +164,7 @@ func (s) TestResolverResourceName(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, lisCh, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, lisCh, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Create a bootstrap configuration with test options.
|
||||
opts := bootstrap.ConfigOptionsForTesting{
|
||||
|
@ -183,9 +190,8 @@ func (s) TestResolverResourceName(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, contents)
|
||||
|
||||
buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL(tt.dialTarget)})
|
||||
buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL(tt.dialTarget)}, contents)
|
||||
waitForResourceNames(ctx, t, lisCh, tt.wantResourceNames)
|
||||
})
|
||||
}
|
||||
|
@ -222,7 +228,6 @@ func (s) TestResolverWatchCallbackAfterClose(t *testing.T) {
|
|||
// Create a bootstrap configuration specifying the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
contents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, contents)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
|
@ -232,7 +237,7 @@ func (s) TestResolverWatchCallbackAfterClose(t *testing.T) {
|
|||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
// Wait for a discovery request for a route configuration resource.
|
||||
stateCh, _, r := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, r := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, contents)
|
||||
waitForResourceNames(ctx, t, routeConfigResourceNamesCh, []string{defaultTestRouteConfigName})
|
||||
|
||||
// Close the resolver and unblock the management server.
|
||||
|
@ -254,9 +259,16 @@ func (s) TestResolverCloseClosesXDSClient(t *testing.T) {
|
|||
closeCh := make(chan struct{})
|
||||
rinternal.NewXDSClient = func(string) (xdsclient.XDSClient, func(), error) {
|
||||
bc := e2e.DefaultBootstrapContents(t, uuid.New().String(), "dummy-management-server-address")
|
||||
c, cancel, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create an xDS client pool: %v", err)
|
||||
}
|
||||
c, cancel, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestTimeout,
|
||||
})
|
||||
return c, sync.OnceFunc(func() {
|
||||
|
@ -266,7 +278,7 @@ func (s) TestResolverCloseClosesXDSClient(t *testing.T) {
|
|||
}
|
||||
defer func() { rinternal.NewXDSClient = origNewClient }()
|
||||
|
||||
_, _, r := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///my-service-client-side-xds")})
|
||||
_, _, r := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///my-service-client-side-xds")}, nil)
|
||||
r.Close()
|
||||
|
||||
select {
|
||||
|
@ -287,7 +299,7 @@ func (s) TestResolverBadServiceUpdate(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure a listener resource that is expected to be NACKed because it
|
||||
// does not contain the `RouteSpecifier` field in the HTTPConnectionManager.
|
||||
|
@ -308,7 +320,7 @@ func (s) TestResolverBadServiceUpdate(t *testing.T) {
|
|||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, []*v3listenerpb.Listener{lis}, nil)
|
||||
|
||||
// Build the resolver and expect an error update from it.
|
||||
stateCh, errCh, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, errCh, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
wantErr := "no RouteSpecifier"
|
||||
verifyErrorFromResolver(ctx, t, errCh, wantErr)
|
||||
|
||||
|
@ -391,7 +403,7 @@ func (s) TestResolverGoodServiceUpdate(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure the management server with a good listener resource and a
|
||||
// route configuration resource, as specified by the test case.
|
||||
|
@ -399,7 +411,7 @@ func (s) TestResolverGoodServiceUpdate(t *testing.T) {
|
|||
routes := []*v3routepb.RouteConfiguration{tt.routeConfig}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Read the update pushed by the resolver to the ClientConn.
|
||||
cs := verifyUpdateFromResolver(ctx, t, stateCh, tt.wantServiceConfig)
|
||||
|
@ -432,7 +444,7 @@ func (s) TestResolverRequestHash(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure the management server with a good listener resource and a
|
||||
// route configuration resource that specifies a hash policy.
|
||||
|
@ -467,7 +479,7 @@ func (s) TestResolverRequestHash(t *testing.T) {
|
|||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
// Build the resolver and read the config selector out of it.
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
cs := verifyUpdateFromResolver(ctx, t, stateCh, "")
|
||||
|
||||
// Selecting a config when there was a hash policy specified in the route
|
||||
|
@ -495,14 +507,14 @@ func (s) TestResolverRemovedWithRPCs(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Read the update pushed by the resolver to the ClientConn.
|
||||
cs := verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig)
|
||||
|
@ -597,14 +609,14 @@ func (s) TestResolverRemovedResource(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Read the update pushed by the resolver to the ClientConn.
|
||||
cs := verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig)
|
||||
|
@ -661,9 +673,9 @@ func (s) TestResolverMaxStreamDuration(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Configure the management server with a listener resource that specifies a
|
||||
// max stream duration as part of its HTTP connection manager. Also
|
||||
|
@ -794,14 +806,14 @@ func (s) TestResolverDelayedOnCommitted(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
routes := []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(defaultTestRouteConfigName, defaultTestServiceName, defaultTestClusterName)}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, routes)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Read the update pushed by the resolver to the ClientConn.
|
||||
cs := verifyUpdateFromResolver(ctx, t, stateCh, wantDefaultServiceConfig)
|
||||
|
@ -904,14 +916,14 @@ func (s) TestResolverMultipleLDSUpdates(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Configure the management server with a listener resource, but no route
|
||||
// configuration resource.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
configureResourcesOnManagementServer(ctx, t, mgmtServer, nodeID, listeners, nil)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Ensure there is no update from the resolver.
|
||||
verifyNoUpdateFromResolver(ctx, t, stateCh)
|
||||
|
@ -962,9 +974,9 @@ func (s) TestResolverWRR(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Configure resources on the management server.
|
||||
listeners := []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)}
|
||||
|
@ -1161,10 +1173,10 @@ func (s) TestConfigSelector_FailureCases(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Build an xDS resolver.
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Update the management server with a listener resource that
|
||||
// contains inline route configuration.
|
||||
|
@ -1400,10 +1412,10 @@ func (s) TestXDSResolverHTTPFilters(t *testing.T) {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
nodeID := uuid.New().String()
|
||||
mgmtServer, _, _ := setupManagementServerForTest(ctx, t, nodeID)
|
||||
mgmtServer, _, _, bc := setupManagementServerForTest(ctx, t, nodeID)
|
||||
|
||||
// Build an xDS resolver.
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)})
|
||||
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, bc)
|
||||
|
||||
// Update the management server with a listener resource that
|
||||
// contains an inline route configuration.
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/internal/grpctest"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version"
|
||||
|
||||
|
@ -111,9 +112,13 @@ func xdsSetupForTests(t *testing.T) (*e2e.ManagementServer, string, chan []strin
|
|||
nodeID := uuid.New().String()
|
||||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
xdsC, cancel, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
xdsC, cancel, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -86,7 +86,7 @@ func xdsChannelForTest(t *testing.T, serverURI, nodeID string, watchExpiryTimeou
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap contents: %v", err)
|
||||
}
|
||||
bootstrapCfg, err := bootstrap.NewConfigForTesting(contents)
|
||||
bootstrapCfg, err := bootstrap.NewConfigFromContents(contents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package xdsclient
|
||||
|
||||
import (
|
||||
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/load"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
|
@ -50,3 +51,9 @@ type XDSClient interface {
|
|||
|
||||
BootstrapConfig() *bootstrap.Config
|
||||
}
|
||||
|
||||
// DumpResources returns the status and contents of all xDS resources. It uses
|
||||
// xDS clients from the default pool.
|
||||
func DumpResources() *v3statuspb.ClientStatusResponse {
|
||||
return DefaultPool.DumpResources()
|
||||
}
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2022 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package xdsclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/internal"
|
||||
"google.golang.org/grpc/internal/backoff"
|
||||
"google.golang.org/grpc/internal/grpcsync"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
xdsclientinternal "google.golang.org/grpc/xds/internal/xdsclient/internal"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/transport/ads"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/transport/grpctransport"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
)
|
||||
|
||||
// NameForServer represents the value to be passed as name when creating an xDS
|
||||
// client from xDS-enabled gRPC servers. This is a well-known dedicated key
|
||||
// value, and is defined in gRFC A71.
|
||||
const NameForServer = "#server"
|
||||
|
||||
// New returns an xDS client configured with bootstrap configuration specified
|
||||
// by the ordered list:
|
||||
// - file name containing the configuration specified by GRPC_XDS_BOOTSTRAP
|
||||
// - actual configuration specified by GRPC_XDS_BOOTSTRAP_CONFIG
|
||||
// - fallback configuration set using bootstrap.SetFallbackBootstrapConfig
|
||||
//
|
||||
// gRPC client implementations are expected to pass the channel's target URI for
|
||||
// the name field, while server implementations are expected to pass a dedicated
|
||||
// well-known value "#server", as specified in gRFC A71. The returned client is
|
||||
// a reference counted implementation shared among callers using the same name.
|
||||
//
|
||||
// The second return value represents a close function which releases the
|
||||
// caller's reference on the returned client. The caller is expected to invoke
|
||||
// it once they are done using the client. The underlying client will be closed
|
||||
// only when all references are released, and it is safe for the caller to
|
||||
// invoke this close function multiple times.
|
||||
func New(name string) (XDSClient, func(), error) {
|
||||
config, err := bootstrap.GetConfiguration()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("xds: failed to get xDS bootstrap config: %v", err)
|
||||
}
|
||||
return newRefCounted(name, config, defaultWatchExpiryTimeout, backoff.DefaultExponential.Backoff)
|
||||
}
|
||||
|
||||
// newClientImpl returns a new xdsClient with the given config.
|
||||
func newClientImpl(config *bootstrap.Config, watchExpiryTimeout time.Duration, streamBackoff func(int) time.Duration) (*clientImpl, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
c := &clientImpl{
|
||||
done: grpcsync.NewEvent(),
|
||||
authorities: make(map[string]*authority),
|
||||
config: config,
|
||||
watchExpiryTimeout: watchExpiryTimeout,
|
||||
backoff: streamBackoff,
|
||||
serializer: grpcsync.NewCallbackSerializer(ctx),
|
||||
serializerClose: cancel,
|
||||
transportBuilder: &grpctransport.Builder{},
|
||||
resourceTypes: newResourceTypeRegistry(),
|
||||
xdsActiveChannels: make(map[string]*channelState),
|
||||
}
|
||||
|
||||
for name, cfg := range config.Authorities() {
|
||||
// If server configs are specified in the authorities map, use that.
|
||||
// Else, use the top-level server configs.
|
||||
serverCfg := config.XDSServers()
|
||||
if len(cfg.XDSServers) >= 1 {
|
||||
serverCfg = cfg.XDSServers
|
||||
}
|
||||
c.authorities[name] = newAuthority(authorityBuildOptions{
|
||||
serverConfigs: serverCfg,
|
||||
name: name,
|
||||
serializer: c.serializer,
|
||||
getChannelForADS: c.getChannelForADS,
|
||||
logPrefix: clientPrefix(c),
|
||||
})
|
||||
}
|
||||
c.topLevelAuthority = newAuthority(authorityBuildOptions{
|
||||
serverConfigs: config.XDSServers(),
|
||||
name: "",
|
||||
serializer: c.serializer,
|
||||
getChannelForADS: c.getChannelForADS,
|
||||
logPrefix: clientPrefix(c),
|
||||
})
|
||||
c.logger = prefixLogger(c)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// OptionsForTesting contains options to configure xDS client creation for
|
||||
// testing purposes only.
|
||||
type OptionsForTesting struct {
|
||||
// Name is a unique name for this xDS client.
|
||||
Name string
|
||||
|
||||
// Contents contain a JSON representation of the bootstrap configuration to
|
||||
// be used when creating the xDS client.
|
||||
Contents []byte
|
||||
|
||||
// WatchExpiryTimeout is the timeout for xDS resource watch expiry. If
|
||||
// unspecified, uses the default value used in non-test code.
|
||||
WatchExpiryTimeout time.Duration
|
||||
|
||||
// StreamBackoffAfterFailure is the backoff function used to determine the
|
||||
// backoff duration after stream failures.
|
||||
// If unspecified, uses the default value used in non-test code.
|
||||
StreamBackoffAfterFailure func(int) time.Duration
|
||||
}
|
||||
|
||||
// NewForTesting returns an xDS client configured with the provided options.
|
||||
//
|
||||
// The second return value represents a close function which the caller is
|
||||
// expected to invoke once they are done using the client. It is safe for the
|
||||
// caller to invoke this close function multiple times.
|
||||
//
|
||||
// # Testing Only
|
||||
//
|
||||
// This function should ONLY be used for testing purposes.
|
||||
func NewForTesting(opts OptionsForTesting) (XDSClient, func(), error) {
|
||||
if opts.Name == "" {
|
||||
return nil, nil, fmt.Errorf("opts.Name field must be non-empty")
|
||||
}
|
||||
if opts.WatchExpiryTimeout == 0 {
|
||||
opts.WatchExpiryTimeout = defaultWatchExpiryTimeout
|
||||
}
|
||||
if opts.StreamBackoffAfterFailure == nil {
|
||||
opts.StreamBackoffAfterFailure = defaultStreamBackoffFunc
|
||||
}
|
||||
|
||||
config, err := bootstrap.NewConfigForTesting(opts.Contents)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return newRefCounted(opts.Name, config, opts.WatchExpiryTimeout, opts.StreamBackoffAfterFailure)
|
||||
}
|
||||
|
||||
// GetForTesting returns an xDS client created earlier using the given name.
|
||||
//
|
||||
// The second return value represents a close function which the caller is
|
||||
// expected to invoke once they are done using the client. It is safe for the
|
||||
// caller to invoke this close function multiple times.
|
||||
//
|
||||
// # Testing Only
|
||||
//
|
||||
// This function should ONLY be used for testing purposes.
|
||||
func GetForTesting(name string) (XDSClient, func(), error) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
|
||||
c, ok := clients[name]
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("xDS client with name %q not found", name)
|
||||
}
|
||||
c.incrRef()
|
||||
return c, sync.OnceFunc(func() { clientRefCountedClose(name) }), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
internal.TriggerXDSResourceNotFoundForTesting = triggerXDSResourceNotFoundForTesting
|
||||
xdsclientinternal.ResourceWatchStateForTesting = resourceWatchStateForTesting
|
||||
}
|
||||
|
||||
func triggerXDSResourceNotFoundForTesting(client XDSClient, typ xdsresource.Type, name string) error {
|
||||
crc, ok := client.(*clientRefCounted)
|
||||
if !ok {
|
||||
return fmt.Errorf("xDS client is of type %T, want %T", client, &clientRefCounted{})
|
||||
}
|
||||
return crc.clientImpl.triggerResourceNotFoundForTesting(typ, name)
|
||||
}
|
||||
|
||||
func resourceWatchStateForTesting(client XDSClient, typ xdsresource.Type, name string) (ads.ResourceWatchState, error) {
|
||||
crc, ok := client.(*clientRefCounted)
|
||||
if !ok {
|
||||
return ads.ResourceWatchState{}, fmt.Errorf("xDS client is of type %T, want %T", client, &clientRefCounted{})
|
||||
}
|
||||
return crc.clientImpl.resourceWatchStateForTesting(typ, name)
|
||||
}
|
||||
|
||||
var (
|
||||
clients = map[string]*clientRefCounted{}
|
||||
clientsMu sync.Mutex
|
||||
)
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2020 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package xdsclient
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/internal/backoff"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
)
|
||||
|
||||
const defaultWatchExpiryTimeout = 15 * time.Second
|
||||
|
||||
var (
|
||||
// The following functions are no-ops in the actual code, but can be
|
||||
// overridden in tests to give them visibility into certain events.
|
||||
xdsClientImplCreateHook = func(string) {}
|
||||
xdsClientImplCloseHook = func(string) {}
|
||||
|
||||
defaultStreamBackoffFunc = backoff.DefaultExponential.Backoff
|
||||
)
|
||||
|
||||
func clientRefCountedClose(name string) {
|
||||
clientsMu.Lock()
|
||||
client, ok := clients[name]
|
||||
if !ok {
|
||||
logger.Errorf("Attempt to close a non-existent xDS client with name %s", name)
|
||||
clientsMu.Unlock()
|
||||
return
|
||||
}
|
||||
if client.decrRef() != 0 {
|
||||
clientsMu.Unlock()
|
||||
return
|
||||
}
|
||||
delete(clients, name)
|
||||
clientsMu.Unlock()
|
||||
|
||||
// This attempts to close the transport to the management server and could
|
||||
// theoretically call back into the xdsclient package again and deadlock.
|
||||
// Hence, this needs to be called without holding the lock.
|
||||
client.clientImpl.close()
|
||||
xdsClientImplCloseHook(name)
|
||||
|
||||
}
|
||||
|
||||
// newRefCounted creates a new reference counted xDS client implementation for
|
||||
// name, if one does not exist already. If an xDS client for the given name
|
||||
// exists, it gets a reference to it and returns it.
|
||||
func newRefCounted(name string, config *bootstrap.Config, watchExpiryTimeout time.Duration, streamBackoff func(int) time.Duration) (XDSClient, func(), error) {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
|
||||
if c := clients[name]; c != nil {
|
||||
c.incrRef()
|
||||
return c, sync.OnceFunc(func() { clientRefCountedClose(name) }), nil
|
||||
}
|
||||
|
||||
// Create the new client implementation.
|
||||
c, err := newClientImpl(config, watchExpiryTimeout, streamBackoff)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
c.logger.Infof("Created client with name %q and bootstrap configuration:\n %s", name, config)
|
||||
client := &clientRefCounted{clientImpl: c, refCount: 1}
|
||||
clients[name] = client
|
||||
xdsClientImplCreateHook(name)
|
||||
|
||||
logger.Infof("xDS node ID: %s", config.Node().GetId())
|
||||
return client, sync.OnceFunc(func() { clientRefCountedClose(name) }), nil
|
||||
}
|
||||
|
||||
// clientRefCounted is ref-counted, and to be shared by the xds resolver and
|
||||
// balancer implementations, across multiple ClientConns and Servers.
|
||||
type clientRefCounted struct {
|
||||
*clientImpl
|
||||
|
||||
refCount int32 // accessed atomically
|
||||
}
|
||||
|
||||
func (c *clientRefCounted) incrRef() int32 {
|
||||
return atomic.AddInt32(&c.refCount, 1)
|
||||
}
|
||||
|
||||
func (c *clientRefCounted) decrRef() int32 {
|
||||
return atomic.AddInt32(&c.refCount, -1)
|
||||
}
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
)
|
||||
|
||||
// Tests that multiple calls to New() with the same name returns the same
|
||||
|
@ -36,7 +37,11 @@ func (s) TestClientNew_Single(t *testing.T) {
|
|||
// directory, and set the bootstrap env vars to point to it.
|
||||
nodeID := uuid.New().String()
|
||||
contents := e2e.DefaultBootstrapContents(t, nodeID, "non-existent-server-address")
|
||||
testutils.CreateBootstrapFileForTesting(t, contents)
|
||||
config, err := bootstrap.NewConfigFromContents(contents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", contents, err)
|
||||
}
|
||||
pool := NewPool(config)
|
||||
|
||||
// Override the client creation hook to get notified.
|
||||
origClientImplCreateHook := xdsClientImplCreateHook
|
||||
|
@ -55,7 +60,7 @@ func (s) TestClientNew_Single(t *testing.T) {
|
|||
defer func() { xdsClientImplCloseHook = origClientImplCloseHook }()
|
||||
|
||||
// The first call to New() should create a new client.
|
||||
_, closeFunc, err := New(t.Name())
|
||||
_, closeFunc, err := pool.NewClient(t.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
|
@ -71,7 +76,7 @@ func (s) TestClientNew_Single(t *testing.T) {
|
|||
closeFuncs := make([]func(), count)
|
||||
for i := 0; i < count; i++ {
|
||||
func() {
|
||||
_, closeFuncs[i], err = New(t.Name())
|
||||
_, closeFuncs[i], err = pool.NewClient(t.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("%d-th call to New() failed with error: %v", i, err)
|
||||
}
|
||||
|
@ -109,7 +114,7 @@ func (s) TestClientNew_Single(t *testing.T) {
|
|||
|
||||
// Calling New() again, after the previous Client was actually closed,
|
||||
// should create a new one.
|
||||
_, closeFunc, err = New(t.Name())
|
||||
_, closeFunc, err = pool.NewClient(t.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
|
@ -127,7 +132,11 @@ func (s) TestClientNew_Multiple(t *testing.T) {
|
|||
// directory, and set the bootstrap env vars to point to it.
|
||||
nodeID := uuid.New().String()
|
||||
contents := e2e.DefaultBootstrapContents(t, nodeID, "non-existent-server-address")
|
||||
testutils.CreateBootstrapFileForTesting(t, contents)
|
||||
config, err := bootstrap.NewConfigFromContents(contents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", contents, err)
|
||||
}
|
||||
pool := NewPool(config)
|
||||
|
||||
// Override the client creation hook to get notified.
|
||||
origClientImplCreateHook := xdsClientImplCreateHook
|
||||
|
@ -147,7 +156,7 @@ func (s) TestClientNew_Multiple(t *testing.T) {
|
|||
|
||||
// Create two xDS clients.
|
||||
client1Name := t.Name() + "-1"
|
||||
_, closeFunc1, err := New(client1Name)
|
||||
_, closeFunc1, err := pool.NewClient(client1Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
|
@ -162,7 +171,7 @@ func (s) TestClientNew_Multiple(t *testing.T) {
|
|||
}
|
||||
|
||||
client2Name := t.Name() + "-2"
|
||||
_, closeFunc2, err := New(client2Name)
|
||||
_, closeFunc2, err := pool.NewClient(client2Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
|
@ -184,7 +193,7 @@ func (s) TestClientNew_Multiple(t *testing.T) {
|
|||
defer wg.Done()
|
||||
for i := 0; i < count; i++ {
|
||||
var err error
|
||||
_, closeFuncs1[i], err = New(client1Name)
|
||||
_, closeFuncs1[i], err = pool.NewClient(client1Name)
|
||||
if err != nil {
|
||||
t.Errorf("%d-th call to New() failed with error: %v", i, err)
|
||||
}
|
||||
|
@ -194,7 +203,7 @@ func (s) TestClientNew_Multiple(t *testing.T) {
|
|||
defer wg.Done()
|
||||
for i := 0; i < count; i++ {
|
||||
var err error
|
||||
_, closeFuncs2[i], err = New(client2Name)
|
||||
_, closeFuncs2[i], err = pool.NewClient(client2Name)
|
||||
if err != nil {
|
||||
t.Errorf("%d-th call to New() failed with error: %v", i, err)
|
||||
}
|
||||
|
|
|
@ -19,26 +19,50 @@
|
|||
package xdsclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
|
||||
"google.golang.org/grpc/internal"
|
||||
"google.golang.org/grpc/internal/backoff"
|
||||
"google.golang.org/grpc/internal/grpclog"
|
||||
"google.golang.org/grpc/internal/grpcsync"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
xdsclientinternal "google.golang.org/grpc/xds/internal/xdsclient/internal"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/transport"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/transport/ads"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/transport/grpctransport"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
)
|
||||
|
||||
var _ XDSClient = &clientImpl{}
|
||||
const (
|
||||
// NameForServer represents the value to be passed as name when creating an xDS
|
||||
// client from xDS-enabled gRPC servers. This is a well-known dedicated key
|
||||
// value, and is defined in gRFC A71.
|
||||
NameForServer = "#server"
|
||||
|
||||
// ErrClientClosed is returned when the xDS client is closed.
|
||||
var ErrClientClosed = errors.New("xds: the xDS client is closed")
|
||||
defaultWatchExpiryTimeout = 15 * time.Second
|
||||
)
|
||||
|
||||
// clientImpl is the real implementation of the xds client. The exported Client
|
||||
var (
|
||||
_ XDSClient = &clientImpl{}
|
||||
|
||||
// ErrClientClosed is returned when the xDS client is closed.
|
||||
ErrClientClosed = errors.New("xds: the xDS client is closed")
|
||||
|
||||
// The following functions are no-ops in the actual code, but can be
|
||||
// overridden in tests to give them visibility into certain events.
|
||||
xdsClientImplCreateHook = func(string) {}
|
||||
xdsClientImplCloseHook = func(string) {}
|
||||
|
||||
defaultExponentialBackoff = backoff.DefaultExponential.Backoff
|
||||
)
|
||||
|
||||
// clientImpl is the real implementation of the xDS client. The exported Client
|
||||
// is a wrapper of this struct with a ref count.
|
||||
type clientImpl struct {
|
||||
// The following fields are initialized at creation time and are read-only
|
||||
|
@ -67,70 +91,65 @@ type clientImpl struct {
|
|||
xdsActiveChannels map[string]*channelState // Map from server config to in-use xdsChannels.
|
||||
}
|
||||
|
||||
// channelState represents the state of an xDS channel. It tracks the number of
|
||||
// LRS references, the authorities interested in the channel, and the server
|
||||
// configuration used for the channel.
|
||||
//
|
||||
// It receives callbacks for events on the underlying ADS stream and invokes
|
||||
// corresponding callbacks on interested authoririties.
|
||||
type channelState struct {
|
||||
parent *clientImpl
|
||||
serverConfig *bootstrap.ServerConfig
|
||||
func init() {
|
||||
internal.TriggerXDSResourceNotFoundForTesting = triggerXDSResourceNotFoundForTesting
|
||||
xdsclientinternal.ResourceWatchStateForTesting = resourceWatchStateForTesting
|
||||
|
||||
// Access to the following fields should be protected by the parent's
|
||||
// channelsMu.
|
||||
channel *xdsChannel
|
||||
lrsRefs int
|
||||
interestedAuthorities map[*authority]bool
|
||||
}
|
||||
|
||||
func (cs *channelState) adsStreamFailure(err error) {
|
||||
if cs.parent.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
||||
cs.parent.channelsMu.Lock()
|
||||
defer cs.parent.channelsMu.Unlock()
|
||||
for authority := range cs.interestedAuthorities {
|
||||
authority.adsStreamFailure(cs.serverConfig, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *channelState) adsResourceUpdate(typ xdsresource.Type, updates map[string]ads.DataAndErrTuple, md xdsresource.UpdateMetadata, onDone func()) {
|
||||
if cs.parent.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
||||
cs.parent.channelsMu.Lock()
|
||||
defer cs.parent.channelsMu.Unlock()
|
||||
|
||||
if len(cs.interestedAuthorities) == 0 {
|
||||
onDone()
|
||||
return
|
||||
}
|
||||
|
||||
authorityCnt := new(atomic.Int64)
|
||||
authorityCnt.Add(int64(len(cs.interestedAuthorities)))
|
||||
done := func() {
|
||||
if authorityCnt.Add(-1) == 0 {
|
||||
onDone()
|
||||
// DefaultPool is initialized with bootstrap configuration from one of the
|
||||
// supported environment variables. If the environment variables are not
|
||||
// set, then fallback bootstrap configuration should be set before
|
||||
// attempting to create an xDS client, else xDS client creation will fail.
|
||||
config, err := bootstrap.GetConfiguration()
|
||||
if err != nil {
|
||||
if logger.V(2) {
|
||||
logger.Infof("Failed to read xDS bootstrap config from env vars: %v", err)
|
||||
}
|
||||
}
|
||||
for authority := range cs.interestedAuthorities {
|
||||
authority.adsResourceUpdate(cs.serverConfig, typ, updates, md, done)
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *channelState) adsResourceDoesNotExist(typ xdsresource.Type, resourceName string) {
|
||||
if cs.parent.done.HasFired() {
|
||||
DefaultPool = &Pool{clients: make(map[string]*clientRefCounted)}
|
||||
return
|
||||
}
|
||||
DefaultPool = &Pool{clients: make(map[string]*clientRefCounted), config: config}
|
||||
}
|
||||
|
||||
cs.parent.channelsMu.Lock()
|
||||
defer cs.parent.channelsMu.Unlock()
|
||||
for authority := range cs.interestedAuthorities {
|
||||
authority.adsResourceDoesNotExist(typ, resourceName)
|
||||
// newClientImpl returns a new xdsClient with the given config.
|
||||
func newClientImpl(config *bootstrap.Config, watchExpiryTimeout time.Duration, streamBackoff func(int) time.Duration) (*clientImpl, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
c := &clientImpl{
|
||||
done: grpcsync.NewEvent(),
|
||||
authorities: make(map[string]*authority),
|
||||
config: config,
|
||||
watchExpiryTimeout: watchExpiryTimeout,
|
||||
backoff: streamBackoff,
|
||||
serializer: grpcsync.NewCallbackSerializer(ctx),
|
||||
serializerClose: cancel,
|
||||
transportBuilder: &grpctransport.Builder{},
|
||||
resourceTypes: newResourceTypeRegistry(),
|
||||
xdsActiveChannels: make(map[string]*channelState),
|
||||
}
|
||||
|
||||
for name, cfg := range config.Authorities() {
|
||||
// If server configs are specified in the authorities map, use that.
|
||||
// Else, use the top-level server configs.
|
||||
serverCfg := config.XDSServers()
|
||||
if len(cfg.XDSServers) >= 1 {
|
||||
serverCfg = cfg.XDSServers
|
||||
}
|
||||
c.authorities[name] = newAuthority(authorityBuildOptions{
|
||||
serverConfigs: serverCfg,
|
||||
name: name,
|
||||
serializer: c.serializer,
|
||||
getChannelForADS: c.getChannelForADS,
|
||||
logPrefix: clientPrefix(c),
|
||||
})
|
||||
}
|
||||
c.topLevelAuthority = newAuthority(authorityBuildOptions{
|
||||
serverConfigs: config.XDSServers(),
|
||||
name: "",
|
||||
serializer: c.serializer,
|
||||
getChannelForADS: c.getChannelForADS,
|
||||
logPrefix: clientPrefix(c),
|
||||
})
|
||||
c.logger = prefixLogger(c)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// BootstrapConfig returns the configuration read from the bootstrap file.
|
||||
|
@ -285,7 +304,7 @@ func (c *clientImpl) getOrCreateChannel(serverConfig *bootstrap.ServerConfig, in
|
|||
// map of xdsChannels.
|
||||
tr, err := c.transportBuilder.Build(transport.BuildOptions{ServerConfig: serverConfig})
|
||||
if err != nil {
|
||||
return nil, func() {}, fmt.Errorf("failed to create transport for server config %s: %v", serverConfig, err)
|
||||
return nil, func() {}, fmt.Errorf("xds: failed to create transport for server config %s: %v", serverConfig, err)
|
||||
}
|
||||
state := &channelState{
|
||||
parent: c,
|
||||
|
@ -303,7 +322,7 @@ func (c *clientImpl) getOrCreateChannel(serverConfig *bootstrap.ServerConfig, in
|
|||
logPrefix: clientPrefix(c),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, func() {}, fmt.Errorf("failed to create xdsChannel for server config %s: %v", serverConfig, err)
|
||||
return nil, func() {}, fmt.Errorf("xds: failed to create xdsChannel for server config %s: %v", serverConfig, err)
|
||||
}
|
||||
state.channel = channel
|
||||
c.xdsActiveChannels[serverConfig.String()] = state
|
||||
|
@ -350,3 +369,114 @@ func (c *clientImpl) releaseChannel(serverConfig *bootstrap.ServerConfig, state
|
|||
channelToClose.close()
|
||||
})
|
||||
}
|
||||
|
||||
// dumpResources returns the status and contents of all xDS resources.
|
||||
func (c *clientImpl) dumpResources() *v3statuspb.ClientConfig {
|
||||
retCfg := c.topLevelAuthority.dumpResources()
|
||||
for _, a := range c.authorities {
|
||||
retCfg = append(retCfg, a.dumpResources()...)
|
||||
}
|
||||
|
||||
return &v3statuspb.ClientConfig{
|
||||
Node: c.config.Node(),
|
||||
GenericXdsConfigs: retCfg,
|
||||
}
|
||||
}
|
||||
|
||||
// channelState represents the state of an xDS channel. It tracks the number of
|
||||
// LRS references, the authorities interested in the channel, and the server
|
||||
// configuration used for the channel.
|
||||
//
|
||||
// It receives callbacks for events on the underlying ADS stream and invokes
|
||||
// corresponding callbacks on interested authorities.
|
||||
type channelState struct {
|
||||
parent *clientImpl
|
||||
serverConfig *bootstrap.ServerConfig
|
||||
|
||||
// Access to the following fields should be protected by the parent's
|
||||
// channelsMu.
|
||||
channel *xdsChannel
|
||||
lrsRefs int
|
||||
interestedAuthorities map[*authority]bool
|
||||
}
|
||||
|
||||
func (cs *channelState) adsStreamFailure(err error) {
|
||||
if cs.parent.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
||||
cs.parent.channelsMu.Lock()
|
||||
defer cs.parent.channelsMu.Unlock()
|
||||
for authority := range cs.interestedAuthorities {
|
||||
authority.adsStreamFailure(cs.serverConfig, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *channelState) adsResourceUpdate(typ xdsresource.Type, updates map[string]ads.DataAndErrTuple, md xdsresource.UpdateMetadata, onDone func()) {
|
||||
if cs.parent.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
||||
cs.parent.channelsMu.Lock()
|
||||
defer cs.parent.channelsMu.Unlock()
|
||||
|
||||
if len(cs.interestedAuthorities) == 0 {
|
||||
onDone()
|
||||
return
|
||||
}
|
||||
|
||||
authorityCnt := new(atomic.Int64)
|
||||
authorityCnt.Add(int64(len(cs.interestedAuthorities)))
|
||||
done := func() {
|
||||
if authorityCnt.Add(-1) == 0 {
|
||||
onDone()
|
||||
}
|
||||
}
|
||||
for authority := range cs.interestedAuthorities {
|
||||
authority.adsResourceUpdate(cs.serverConfig, typ, updates, md, done)
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *channelState) adsResourceDoesNotExist(typ xdsresource.Type, resourceName string) {
|
||||
if cs.parent.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
||||
cs.parent.channelsMu.Lock()
|
||||
defer cs.parent.channelsMu.Unlock()
|
||||
for authority := range cs.interestedAuthorities {
|
||||
authority.adsResourceDoesNotExist(typ, resourceName)
|
||||
}
|
||||
}
|
||||
|
||||
// clientRefCounted is ref-counted, and to be shared by the xds resolver and
|
||||
// balancer implementations, across multiple ClientConns and Servers.
|
||||
type clientRefCounted struct {
|
||||
*clientImpl
|
||||
|
||||
refCount int32 // accessed atomically
|
||||
}
|
||||
|
||||
func (c *clientRefCounted) incrRef() int32 {
|
||||
return atomic.AddInt32(&c.refCount, 1)
|
||||
}
|
||||
|
||||
func (c *clientRefCounted) decrRef() int32 {
|
||||
return atomic.AddInt32(&c.refCount, -1)
|
||||
}
|
||||
|
||||
func triggerXDSResourceNotFoundForTesting(client XDSClient, typ xdsresource.Type, name string) error {
|
||||
crc, ok := client.(*clientRefCounted)
|
||||
if !ok {
|
||||
return fmt.Errorf("xds: xDS client is of type %T, want %T", client, &clientRefCounted{})
|
||||
}
|
||||
return crc.clientImpl.triggerResourceNotFoundForTesting(typ, name)
|
||||
}
|
||||
|
||||
func resourceWatchStateForTesting(client XDSClient, typ xdsresource.Type, name string) (ads.ResourceWatchState, error) {
|
||||
crc, ok := client.(*clientRefCounted)
|
||||
if !ok {
|
||||
return ads.ResourceWatchState{}, fmt.Errorf("xds: xDS client is of type %T, want %T", client, &clientRefCounted{})
|
||||
}
|
||||
return crc.clientImpl.resourceWatchStateForTesting(typ, name)
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2021 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package xdsclient
|
||||
|
||||
import (
|
||||
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
|
||||
)
|
||||
|
||||
// dumpResources returns the status and contents of all xDS resources.
|
||||
func (c *clientImpl) dumpResources() *v3statuspb.ClientConfig {
|
||||
retCfg := c.topLevelAuthority.dumpResources()
|
||||
for _, a := range c.authorities {
|
||||
retCfg = append(retCfg, a.dumpResources()...)
|
||||
}
|
||||
|
||||
return &v3statuspb.ClientConfig{
|
||||
Node: c.config.Node(),
|
||||
GenericXdsConfigs: retCfg,
|
||||
}
|
||||
}
|
||||
|
||||
// DumpResources returns the status and contents of all xDS resources.
|
||||
func DumpResources() *v3statuspb.ClientStatusResponse {
|
||||
clientsMu.Lock()
|
||||
defer clientsMu.Unlock()
|
||||
|
||||
resp := &v3statuspb.ClientStatusResponse{}
|
||||
for key, client := range clients {
|
||||
cfg := client.dumpResources()
|
||||
cfg.ClientScope = key
|
||||
resp.Config = append(resp.Config, cfg)
|
||||
}
|
||||
return resp
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package xdsclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
|
||||
"google.golang.org/grpc/internal/backoff"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultPool is the default pool for xDS clients. It is created at init
|
||||
// time by reading bootstrap configuration from env vars.
|
||||
DefaultPool *Pool
|
||||
)
|
||||
|
||||
// Pool represents a pool of xDS clients that share the same bootstrap
|
||||
// configuration.
|
||||
type Pool struct {
|
||||
// Note that mu should ideally only have to guard clients. But here, we need
|
||||
// it to guard config as well since SetFallbackBootstrapConfig writes to
|
||||
// config.
|
||||
mu sync.Mutex
|
||||
clients map[string]*clientRefCounted
|
||||
config *bootstrap.Config
|
||||
}
|
||||
|
||||
// OptionsForTesting contains options to configure xDS client creation for
|
||||
// testing purposes only.
|
||||
type OptionsForTesting struct {
|
||||
// Name is a unique name for this xDS client.
|
||||
Name string
|
||||
|
||||
// WatchExpiryTimeout is the timeout for xDS resource watch expiry. If
|
||||
// unspecified, uses the default value used in non-test code.
|
||||
WatchExpiryTimeout time.Duration
|
||||
|
||||
// StreamBackoffAfterFailure is the backoff function used to determine the
|
||||
// backoff duration after stream failures.
|
||||
// If unspecified, uses the default value used in non-test code.
|
||||
StreamBackoffAfterFailure func(int) time.Duration
|
||||
}
|
||||
|
||||
// NewPool creates a new xDS client pool with the given bootstrap config.
|
||||
//
|
||||
// If a nil bootstrap config is passed and SetFallbackBootstrapConfig is not
|
||||
// called before a call to NewClient, the latter will fail. i.e. if there is an
|
||||
// attempt to create an xDS client from the pool without specifying bootstrap
|
||||
// configuration (either at pool creation time or by setting the fallback
|
||||
// bootstrap configuration), xDS client creation will fail.
|
||||
func NewPool(config *bootstrap.Config) *Pool {
|
||||
return &Pool{
|
||||
clients: make(map[string]*clientRefCounted),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClient returns an xDS client with the given name from the pool. If the
|
||||
// client doesn't already exist, it creates a new xDS client and adds it to the
|
||||
// pool.
|
||||
//
|
||||
// The second return value represents a close function which the caller is
|
||||
// expected to invoke once they are done using the client. It is safe for the
|
||||
// caller to invoke this close function multiple times.
|
||||
func (p *Pool) NewClient(name string) (XDSClient, func(), error) {
|
||||
return p.newRefCounted(name, defaultWatchExpiryTimeout, backoff.DefaultExponential.Backoff)
|
||||
}
|
||||
|
||||
// NewClientForTesting returns an xDS client configured with the provided
|
||||
// options from the pool. If the client doesn't already exist, it creates a new
|
||||
// xDS client and adds it to the pool.
|
||||
//
|
||||
// The second return value represents a close function which the caller is
|
||||
// expected to invoke once they are done using the client. It is safe for the
|
||||
// caller to invoke this close function multiple times.
|
||||
//
|
||||
// # Testing Only
|
||||
//
|
||||
// This function should ONLY be used for testing purposes.
|
||||
func (p *Pool) NewClientForTesting(opts OptionsForTesting) (XDSClient, func(), error) {
|
||||
if opts.Name == "" {
|
||||
return nil, nil, fmt.Errorf("xds: opts.Name field must be non-empty")
|
||||
}
|
||||
if opts.WatchExpiryTimeout == 0 {
|
||||
opts.WatchExpiryTimeout = defaultWatchExpiryTimeout
|
||||
}
|
||||
if opts.StreamBackoffAfterFailure == nil {
|
||||
opts.StreamBackoffAfterFailure = defaultExponentialBackoff
|
||||
}
|
||||
return p.newRefCounted(opts.Name, opts.WatchExpiryTimeout, opts.StreamBackoffAfterFailure)
|
||||
}
|
||||
|
||||
// GetClientForTesting returns an xDS client created earlier using the given
|
||||
// name from the pool. If the client with the given name doesn't already exist,
|
||||
// it returns an error.
|
||||
//
|
||||
// The second return value represents a close function which the caller is
|
||||
// expected to invoke once they are done using the client. It is safe for the
|
||||
// caller to invoke this close function multiple times.
|
||||
//
|
||||
// # Testing Only
|
||||
//
|
||||
// This function should ONLY be used for testing purposes.
|
||||
func (p *Pool) GetClientForTesting(name string) (XDSClient, func(), error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
c, ok := p.clients[name]
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("xds:: xDS client with name %q not found", name)
|
||||
}
|
||||
c.incrRef()
|
||||
return c, sync.OnceFunc(func() { p.clientRefCountedClose(name) }), nil
|
||||
}
|
||||
|
||||
// SetFallbackBootstrapConfig is used to specify a bootstrap configuration
|
||||
// that will be used as a fallback when the bootstrap environment variables
|
||||
// are not defined.
|
||||
func (p *Pool) SetFallbackBootstrapConfig(config *bootstrap.Config) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if p.config != nil {
|
||||
logger.Error("Attempt to set a bootstrap configuration even though one is already set via environment variables.")
|
||||
return
|
||||
}
|
||||
p.config = config
|
||||
}
|
||||
|
||||
// DumpResources returns the status and contents of all xDS resources.
|
||||
func (p *Pool) DumpResources() *v3statuspb.ClientStatusResponse {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
resp := &v3statuspb.ClientStatusResponse{}
|
||||
for key, client := range p.clients {
|
||||
cfg := client.dumpResources()
|
||||
cfg.ClientScope = key
|
||||
resp.Config = append(resp.Config, cfg)
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// BootstrapConfigForTesting returns the bootstrap configuration used by the
|
||||
// pool. The caller should not mutate the returned config.
|
||||
//
|
||||
// To be used only for testing purposes.
|
||||
func (p *Pool) BootstrapConfigForTesting() *bootstrap.Config {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
return p.config
|
||||
}
|
||||
|
||||
// UnsetBootstrapConfigForTesting unsets the bootstrap configuration used by
|
||||
// the pool.
|
||||
//
|
||||
// To be used only for testing purposes.
|
||||
func (p *Pool) UnsetBootstrapConfigForTesting() {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.config = nil
|
||||
}
|
||||
|
||||
func (p *Pool) clientRefCountedClose(name string) {
|
||||
p.mu.Lock()
|
||||
client, ok := p.clients[name]
|
||||
if !ok {
|
||||
logger.Errorf("Attempt to close a non-existent xDS client with name %s", name)
|
||||
p.mu.Unlock()
|
||||
return
|
||||
}
|
||||
if client.decrRef() != 0 {
|
||||
p.mu.Unlock()
|
||||
return
|
||||
}
|
||||
delete(p.clients, name)
|
||||
p.mu.Unlock()
|
||||
|
||||
// This attempts to close the transport to the management server and could
|
||||
// theoretically call back into the xdsclient package again and deadlock.
|
||||
// Hence, this needs to be called without holding the lock.
|
||||
client.clientImpl.close()
|
||||
xdsClientImplCloseHook(name)
|
||||
}
|
||||
|
||||
// newRefCounted creates a new reference counted xDS client implementation for
|
||||
// name, if one does not exist already. If an xDS client for the given name
|
||||
// exists, it gets a reference to it and returns it.
|
||||
func (p *Pool) newRefCounted(name string, watchExpiryTimeout time.Duration, streamBackoff func(int) time.Duration) (XDSClient, func(), error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if p.config == nil {
|
||||
return nil, nil, fmt.Errorf("xds: bootstrap configuration not set in the pool")
|
||||
}
|
||||
|
||||
if c := p.clients[name]; c != nil {
|
||||
c.incrRef()
|
||||
return c, sync.OnceFunc(func() { p.clientRefCountedClose(name) }), nil
|
||||
}
|
||||
|
||||
c, err := newClientImpl(p.config, watchExpiryTimeout, streamBackoff)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if logger.V(2) {
|
||||
c.logger.Infof("Created client with name %q and bootstrap configuration:\n %s", name, p.config)
|
||||
}
|
||||
client := &clientRefCounted{clientImpl: c, refCount: 1}
|
||||
p.clients[name] = client
|
||||
xdsClientImplCreateHook(name)
|
||||
|
||||
logger.Infof("xDS node ID: %s", p.config.Node().GetId())
|
||||
return client, sync.OnceFunc(func() { p.clientRefCountedClose(name) }), nil
|
||||
}
|
|
@ -31,6 +31,7 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
@ -85,7 +86,6 @@ func (s) TestADS_ACK_NACK_Simple(t *testing.T) {
|
|||
|
||||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client := createXDSClient(t, bc)
|
||||
|
||||
// Register a watch for a listener resource.
|
||||
|
@ -272,7 +272,6 @@ func (s) TestADS_NACK_InvalidFirstResponse(t *testing.T) {
|
|||
|
||||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client := createXDSClient(t, bc)
|
||||
|
||||
// Register a watch for a listener resource.
|
||||
|
@ -380,10 +379,13 @@ func (s) TestADS_ACK_NACK_ResourceIsNotRequestedAnymore(t *testing.T) {
|
|||
|
||||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version"
|
||||
|
@ -46,10 +47,14 @@ import (
|
|||
func createXDSClientWithBackoff(t *testing.T, bootstrapContents []byte, streamBackoff func(int) time.Duration) xdsclient.XDSClient {
|
||||
t.Helper()
|
||||
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
StreamBackoffAfterFailure: streamBackoff,
|
||||
Contents: bootstrapContents,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -110,7 +115,6 @@ func (s) TestADS_BackoffAfterStreamFailure(t *testing.T) {
|
|||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client := createXDSClientWithBackoff(t, bc, streamBackoff)
|
||||
|
||||
// Register a watch for a listener resource.
|
||||
|
@ -221,7 +225,6 @@ func (s) TestADS_RetriesAfterBrokenStream(t *testing.T) {
|
|||
|
||||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client := createXDSClientWithBackoff(t, bc, streamBackoff)
|
||||
|
||||
// Register a watch for a listener resource.
|
||||
|
@ -383,7 +386,6 @@ func (s) TestADS_ResourceRequestedBeforeStreamCreation(t *testing.T) {
|
|||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client := createXDSClientWithBackoff(t, bc, streamBackoff)
|
||||
|
||||
// Register a watch for a listener resource.
|
||||
|
|
|
@ -28,8 +28,8 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
xdsclientinternal "google.golang.org/grpc/xds/internal/xdsclient/internal"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
|
@ -150,9 +150,13 @@ func overrideADSStreamCreation(t *testing.T) chan *wrappedADSStream {
|
|||
func createXDSClient(t *testing.T, bootstrapContents []byte) xdsclient.XDSClient {
|
||||
t.Helper()
|
||||
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -186,7 +190,6 @@ func (s) TestADSFlowControl_ResourceUpdates_SingleResource(t *testing.T) {
|
|||
// Create bootstrap configuration pointing to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client := createXDSClient(t, bc)
|
||||
|
@ -335,7 +338,6 @@ func (s) TestADSFlowControl_ResourceUpdates_MultipleResources(t *testing.T) {
|
|||
// Create bootstrap configuration pointing to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client := createXDSClient(t, bc)
|
||||
|
@ -452,7 +454,6 @@ func (s) TestADSFlowControl_ResourceErrors(t *testing.T) {
|
|||
// Create bootstrap configuration pointing to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client := createXDSClient(t, bc)
|
||||
|
@ -533,7 +534,6 @@ func (s) TestADSFlowControl_ResourceDoesNotExist(t *testing.T) {
|
|||
// Create bootstrap configuration pointing to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client := createXDSClient(t, bc)
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version"
|
||||
|
@ -112,9 +113,13 @@ func (s) TestADS_ResourcesAreRequestedAfterStreamRestart(t *testing.T) {
|
|||
bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
// Create an xDS client with the above bootstrap configuration.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
xdsinternal "google.golang.org/grpc/xds/internal"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient/internal"
|
||||
|
@ -55,7 +56,6 @@ func (s) TestADS_WatchState_StreamBreaks(t *testing.T) {
|
|||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client := createXDSClient(t, bc)
|
||||
|
||||
// Create a watch for the first listener resource and verify that the timer
|
||||
|
@ -146,10 +146,13 @@ func (s) TestADS_WatchState_TimerFires(t *testing.T) {
|
|||
// short resource expiry timeout.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -100,9 +100,13 @@ func setupForAuthorityTests(ctx context.Context, t *testing.T) (*testutils.Liste
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -207,12 +207,15 @@ func (s) TestCDSWatch(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -357,12 +360,15 @@ func (s) TestCDSWatch_TwoWatchesForSameResourceName(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -460,12 +466,15 @@ func (s) TestCDSWatch_ThreeWatchesForDifferentResourceNames(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -557,12 +566,15 @@ func (s) TestCDSWatch_ResourceCaching(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -631,11 +643,14 @@ func (s) TestCDSWatch_ExpiryTimerFiresBeforeResponse(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -671,11 +686,14 @@ func (s) TestCDSWatch_ValidResponseCancelsExpiryTimerBehavior(t *testing.T) {
|
|||
// Create an xDS client talking to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -753,12 +771,15 @@ func (s) TestCDSWatch_ResourceRemoved(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -865,12 +886,15 @@ func (s) TestCDSWatch_NACKError(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -934,12 +958,15 @@ func (s) TestCDSWatch_PartialValid(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -1026,12 +1053,15 @@ func (s) TestCDSWatch_PartialResponse(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -62,7 +62,7 @@ func makeGenericXdsConfig(typeURL, name, version string, status v3adminpb.Client
|
|||
}
|
||||
}
|
||||
|
||||
func checkResourceDump(ctx context.Context, want *v3statuspb.ClientStatusResponse) error {
|
||||
func checkResourceDump(ctx context.Context, want *v3statuspb.ClientStatusResponse, pool *xdsclient.Pool) error {
|
||||
var cmpOpts = cmp.Options{
|
||||
protocmp.Transform(),
|
||||
protocmp.IgnoreFields((*v3statuspb.ClientConfig_GenericXdsConfig)(nil), "last_updated"),
|
||||
|
@ -71,7 +71,7 @@ func checkResourceDump(ctx context.Context, want *v3statuspb.ClientStatusRespons
|
|||
|
||||
var lastErr error
|
||||
for ; ctx.Err() == nil; <-time.After(defaultTestShortTimeout) {
|
||||
got := xdsclient.DumpResources()
|
||||
got := pool.DumpResources()
|
||||
// Sort the client configs based on the `client_scope` field.
|
||||
slices.SortFunc(got.GetConfig(), func(a, b *v3statuspb.ClientConfig) int {
|
||||
return strings.Compare(a.ClientScope, b.ClientScope)
|
||||
|
@ -136,22 +136,23 @@ func (s) TestDumpResources_ManyToOne(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
// Create two xDS clients with the above bootstrap contents.
|
||||
client1Name := t.Name() + "-1"
|
||||
client1, close1, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client1Name,
|
||||
Contents: bc,
|
||||
client1, close1, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client1Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
defer close1()
|
||||
client2Name := t.Name() + "-2"
|
||||
client2, close2, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client2Name,
|
||||
Contents: bc,
|
||||
client2, close2, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client2Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -179,7 +180,7 @@ func (s) TestDumpResources_ManyToOne(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -222,7 +223,7 @@ func (s) TestDumpResources_ManyToOne(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -262,7 +263,7 @@ func (s) TestDumpResources_ManyToOne(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -322,7 +323,7 @@ func (s) TestDumpResources_ManyToOne(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +397,7 @@ func (s) TestDumpResources_ManyToMany(t *testing.T) {
|
|||
Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)),
|
||||
Authorities: map[string]json.RawMessage{
|
||||
authority: []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{
|
||||
"xds_servers": [{
|
||||
"server_uri": %q,
|
||||
"channel_creds": [{"type": "insecure"}]
|
||||
}]}`, mgmtServer2.Address)),
|
||||
|
@ -405,22 +406,24 @@ func (s) TestDumpResources_ManyToMany(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
|
||||
// Create two xDS clients with the above bootstrap contents.
|
||||
client1Name := t.Name() + "-1"
|
||||
client1, close1, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client1Name,
|
||||
Contents: bc,
|
||||
client1, close1, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client1Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
defer close1()
|
||||
client2Name := t.Name() + "-2"
|
||||
client2, close2, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client2Name,
|
||||
Contents: bc,
|
||||
client2, close2, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: client2Name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -449,7 +452,7 @@ func (s) TestDumpResources_ManyToMany(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -492,7 +495,7 @@ func (s) TestDumpResources_ManyToMany(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -529,7 +532,7 @@ func (s) TestDumpResources_ManyToMany(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -566,7 +569,7 @@ func (s) TestDumpResources_ManyToMany(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
if err := checkResourceDump(ctx, wantResp); err != nil {
|
||||
if err := checkResourceDump(ctx, wantResp, pool); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,12 +237,15 @@ func (s) TestEDSWatch(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -427,12 +430,15 @@ func (s) TestEDSWatch_TwoWatchesForSameResourceName(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -531,12 +537,15 @@ func (s) TestEDSWatch_ThreeWatchesForDifferentResourceNames(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -633,12 +642,15 @@ func (s) TestEDSWatch_ResourceCaching(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -718,11 +730,14 @@ func (s) TestEDSWatch_ExpiryTimerFiresBeforeResponse(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -758,12 +773,15 @@ func (s) TestEDSWatch_ValidResponseCancelsExpiryTimerBehavior(t *testing.T) {
|
|||
// Create an xDS client talking to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client talking to the above management server.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -827,12 +845,15 @@ func (s) TestEDSWatch_NACKError(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -896,12 +917,15 @@ func (s) TestEDSWatch_PartialValid(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -155,18 +155,18 @@ func (s) TestFallback_OnStartup(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client with the above bootstrap configuration.
|
||||
xdsC, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
})
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
defer close()
|
||||
|
||||
// Get the xDS resolver to use the above xDS client.
|
||||
resolverBuilder := internal.NewXDSResolverWithClientForTesting.(func(xdsclient.XDSClient) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(xdsC)
|
||||
resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(pool)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
@ -350,18 +350,18 @@ func (s) TestFallback_MidUpdate(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client with the above bootstrap configuration.
|
||||
xdsC, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
})
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
defer close()
|
||||
|
||||
// Get the xDS resolver to use the above xDS client.
|
||||
resolverBuilder := internal.NewXDSResolverWithClientForTesting.(func(xdsclient.XDSClient) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(xdsC)
|
||||
resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(pool)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
@ -535,18 +535,18 @@ func (s) TestFallback_MidStartup(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create an xDS client with the above bootstrap configuration.
|
||||
xdsC, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
})
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
}
|
||||
defer close()
|
||||
|
||||
// Get the xDS resolver to use the above xDS client.
|
||||
resolverBuilder := internal.NewXDSResolverWithClientForTesting.(func(xdsclient.XDSClient) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(xdsC)
|
||||
resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error))
|
||||
resolver, err := resolverBuilder(pool)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
|
||||
}
|
||||
|
|
|
@ -69,9 +69,13 @@ func setupForFederationWatchersTest(t *testing.T) (*e2e.ManagementServer, string
|
|||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bootstrapContents,
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -263,12 +263,15 @@ func (s) TestLDSWatch(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -413,12 +416,15 @@ func (s) TestLDSWatch_TwoWatchesForSameResourceName(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -517,12 +523,15 @@ func (s) TestLDSWatch_ThreeWatchesForDifferentResourceNames(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -609,12 +618,15 @@ func (s) TestLDSWatch_ResourceCaching(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -683,12 +695,15 @@ func (s) TestLDSWatch_ExpiryTimerFiresBeforeResponse(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client talking to the above management server.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -723,12 +738,15 @@ func (s) TestLDSWatch_ValidResponseCancelsExpiryTimerBehavior(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client talking to the above management server.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -807,12 +825,15 @@ func (s) TestLDSWatch_ResourceRemoved(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -924,9 +945,13 @@ func (s) TestLDSWatch_NewWatcherForRemovedResource(t *testing.T) {
|
|||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -998,12 +1023,15 @@ func (s) TestLDSWatch_NACKError(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -1055,9 +1083,13 @@ func (s) TestLDSWatch_ResourceCaching_NACKError(t *testing.T) {
|
|||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -1151,12 +1183,15 @@ func (s) TestLDSWatch_PartialValid(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -1240,12 +1275,15 @@ func (s) TestLDSWatch_PartialResponse(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -119,16 +119,16 @@ func (s) TestReportLoad_ConnectionCreation(t *testing.T) {
|
|||
nodeID := uuid.New().String()
|
||||
bc, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{
|
||||
Servers: []byte(fmt.Sprintf(`[{
|
||||
"server_uri": %q,
|
||||
"channel_creds": [{"type": "insecure"}]
|
||||
}]`, mgmtServer1.Address)),
|
||||
"server_uri": %q,
|
||||
"channel_creds": [{"type": "insecure"}]
|
||||
}]`, mgmtServer1.Address)),
|
||||
Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)),
|
||||
Authorities: map[string]json.RawMessage{
|
||||
"test-authority": []byte(fmt.Sprintf(`{
|
||||
"xds_servers": [{
|
||||
"server_uri": %q,
|
||||
"channel_creds": [{"type": "insecure"}]
|
||||
}]}`, mgmtServer2.Address)),
|
||||
"xds_servers": [{
|
||||
"server_uri": %q,
|
||||
"channel_creds": [{"type": "insecure"}]
|
||||
}]}`, mgmtServer2.Address)),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -266,7 +266,6 @@ func (s) TestReportLoad_StreamCreation(t *testing.T) {
|
|||
// Create an xDS client with bootstrap pointing to the above server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
client := createXDSClient(t, bc)
|
||||
|
||||
// Call the load reporting API, and ensure that an LRS stream is created.
|
||||
|
|
|
@ -123,12 +123,15 @@ func (s) TestWatchCallAnotherWatch(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -236,9 +239,13 @@ func (s) TestNodeProtoSentOnlyInFirstRequest(t *testing.T) {
|
|||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -239,12 +239,15 @@ func (s) TestRDSWatch(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -429,12 +432,15 @@ func (s) TestRDSWatch_TwoWatchesForSameResourceName(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -533,12 +539,15 @@ func (s) TestRDSWatch_ThreeWatchesForDifferentResourceNames(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -635,12 +644,15 @@ func (s) TestRDSWatch_ResourceCaching(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -719,12 +731,15 @@ func (s) TestRDSWatch_ExpiryTimerFiresBeforeResponse(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client talking to the above management server.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -759,12 +774,15 @@ func (s) TestRDSWatch_ValidResponseCancelsExpiryTimerBehavior(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client talking to the above management server.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -828,12 +846,15 @@ func (s) TestRDSWatch_NACKError(t *testing.T) {
|
|||
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
@ -897,12 +918,15 @@ func (s) TestRDSWatch_PartialValid(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create bootstrap configuration: %v", err)
|
||||
}
|
||||
testutils.CreateBootstrapFileForTesting(t, bc)
|
||||
|
||||
// Create an xDS client with the above bootstrap contents.
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create xDS client: %v", err)
|
||||
|
|
|
@ -283,9 +283,13 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
|
|||
// Create an xDS client talking to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -349,7 +353,7 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
|
|||
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
|
||||
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
|
||||
}
|
||||
if err := compareUpdateMetadata(ctx, xdsclient.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
if err := compareUpdateMetadata(ctx, pool.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
@ -559,9 +563,13 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
|
|||
// Create an xDS client talking to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -624,7 +632,7 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
|
|||
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
|
||||
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
|
||||
}
|
||||
if err := compareUpdateMetadata(ctx, xdsclient.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
if err := compareUpdateMetadata(ctx, pool.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
@ -796,9 +804,13 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
|
|||
// Create an xDS client talking to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -875,7 +887,7 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
|
|||
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
|
||||
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
|
||||
}
|
||||
if err := compareUpdateMetadata(ctx, xdsclient.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
if err := compareUpdateMetadata(ctx, pool.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
@ -1145,9 +1157,13 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
|
|||
// Create an xDS client talking to the above management server.
|
||||
nodeID := uuid.New().String()
|
||||
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
|
||||
client, close, err := xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
config, err := bootstrap.NewConfigFromContents(bc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
client, close, err := pool.NewClientForTesting(xdsclient.OptionsForTesting{
|
||||
Name: t.Name(),
|
||||
Contents: bc,
|
||||
WatchExpiryTimeout: defaultTestWatchExpiryTimeout,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -1210,7 +1226,7 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
|
|||
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
|
||||
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
|
||||
}
|
||||
if err := compareUpdateMetadata(ctx, xdsclient.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
if err := compareUpdateMetadata(ctx, pool.DumpResources, test.wantGenericXDSConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -51,7 +51,7 @@ func (e *xdsClientError) Error() string {
|
|||
return e.desc
|
||||
}
|
||||
|
||||
// NewErrorf creates an xds client error. The callbacks are called with this
|
||||
// NewErrorf creates an xDS client error. The callbacks are called with this
|
||||
// error, to pass additional information about the error.
|
||||
func NewErrorf(t ErrorType, format string, args ...any) error {
|
||||
return &xdsClientError{t: t, desc: fmt.Sprintf(format, args...)}
|
||||
|
|
|
@ -42,10 +42,8 @@ import (
|
|||
const serverPrefix = "[xds-server %p] "
|
||||
|
||||
var (
|
||||
// These new functions will be overridden in unit tests.
|
||||
newXDSClient = func(name string) (xdsclient.XDSClient, func(), error) {
|
||||
return xdsclient.New(name)
|
||||
}
|
||||
// These will be overridden in unit tests.
|
||||
xdsClientPool = xdsclient.DefaultPool
|
||||
newGRPCServer = func(opts ...grpc.ServerOption) grpcServer {
|
||||
return grpc.NewServer(opts...)
|
||||
}
|
||||
|
@ -92,17 +90,11 @@ func NewGRPCServer(opts ...grpc.ServerOption) (*GRPCServer, error) {
|
|||
// Initializing the xDS client upfront (instead of at serving time)
|
||||
// simplifies the code by eliminating the need for a mutex to protect the
|
||||
// xdsC and xdsClientClose fields.
|
||||
newXDSClient := newXDSClient
|
||||
if s.opts.bootstrapContentsForTesting != nil {
|
||||
// Bootstrap file contents may be specified as a server option for tests.
|
||||
newXDSClient = func(name string) (xdsclient.XDSClient, func(), error) {
|
||||
return xdsclient.NewForTesting(xdsclient.OptionsForTesting{
|
||||
Name: name,
|
||||
Contents: s.opts.bootstrapContentsForTesting,
|
||||
})
|
||||
}
|
||||
pool := xdsClientPool
|
||||
if s.opts.clientPoolForTesting != nil {
|
||||
pool = s.opts.clientPoolForTesting
|
||||
}
|
||||
xdsClient, xdsClientClose, err := newXDSClient(xdsclient.NameForServer)
|
||||
xdsClient, xdsClientClose, err := pool.NewClient(xdsclient.NameForServer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("xDS client creation failed: %v", err)
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ import (
|
|||
"google.golang.org/grpc/internal/stubserver"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/testutils/xds/e2e"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/peer"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/grpc/xds"
|
||||
xdsinternal "google.golang.org/grpc/xds/internal"
|
||||
|
@ -142,7 +144,12 @@ func (s) TestServingModeChanges(t *testing.T) {
|
|||
}
|
||||
},
|
||||
}
|
||||
sopts := []grpc.ServerOption{grpc.Creds(insecure.NewCredentials()), modeChangeOpt, xds.BootstrapContentsForTesting(bootstrapContents)}
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
sopts := []grpc.ServerOption{grpc.Creds(insecure.NewCredentials()), modeChangeOpt, xds.ClientPoolForTesting(pool)}
|
||||
if stub.S, err = xds.NewGRPCServer(sopts...); err != nil {
|
||||
t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err)
|
||||
}
|
||||
|
@ -174,7 +181,7 @@ func (s) TestServingModeChanges(t *testing.T) {
|
|||
|
||||
// A unary RPC should work once it transitions into serving. (need this same
|
||||
// assertion from LDS resource not found triggering it).
|
||||
waitForSuccessfulRPC(ctx, t, cc)
|
||||
waitForSuccessfulRPC(ctx, t, cc, grpc.WaitForReady(true))
|
||||
|
||||
// Start a stream before switching the server to not serving. Due to the
|
||||
// stream being created before the graceful stop of the underlying
|
||||
|
@ -188,7 +195,7 @@ func (s) TestServingModeChanges(t *testing.T) {
|
|||
|
||||
// Lookup the xDS client in use based on the dedicated well-known key, as
|
||||
// defined in A71, used by the xDS enabled gRPC server.
|
||||
xdsC, close, err := xdsclient.GetForTesting(xdsclient.NameForServer)
|
||||
xdsC, close, err := pool.GetClientForTesting(xdsclient.NameForServer)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to find xDS client for configuration: %v", string(bootstrapContents))
|
||||
}
|
||||
|
@ -217,6 +224,140 @@ func (s) TestServingModeChanges(t *testing.T) {
|
|||
waitForFailedRPCWithStatus(ctx, t, cc, errAcceptAndClose)
|
||||
}
|
||||
|
||||
// TestMultipleServers_DifferentBootstrapConfigurations verifies that multiple
|
||||
// xDS-enabled gRPC servers can be created with different bootstrap
|
||||
// configurations, and that they correctly request different LDS resources from
|
||||
// the management server based on their respective listening ports. It also
|
||||
// ensures that gRPC clients can connect to the intended server and that RPCs
|
||||
// function correctly. The test uses the grpc.Peer() call option to validate
|
||||
// that the client is connected to the correct server.
|
||||
func (s) TestMultipleServers_DifferentBootstrapConfigurations(t *testing.T) {
|
||||
// Setup an xDS management server.
|
||||
mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
|
||||
|
||||
// Create two bootstrap configurations pointing to the above management server.
|
||||
nodeID1 := uuid.New().String()
|
||||
bootstrapContents1 := e2e.DefaultBootstrapContents(t, nodeID1, mgmtServer.Address)
|
||||
nodeID2 := uuid.New().String()
|
||||
bootstrapContents2 := e2e.DefaultBootstrapContents(t, nodeID2, mgmtServer.Address)
|
||||
|
||||
// Create two xDS-enabled gRPC servers using the above bootstrap configs.
|
||||
lis1, err := testutils.LocalTCPListener()
|
||||
if err != nil {
|
||||
t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
|
||||
}
|
||||
lis2, err := testutils.LocalTCPListener()
|
||||
if err != nil {
|
||||
t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
|
||||
}
|
||||
|
||||
serving1 := grpcsync.NewEvent()
|
||||
modeChangeOpt1 := xds.ServingModeCallback(func(addr net.Addr, args xds.ServingModeChangeArgs) {
|
||||
t.Logf("Serving mode for listener %q changed to %q, err: %v", addr.String(), args.Mode, args.Err)
|
||||
if args.Mode == connectivity.ServingModeServing {
|
||||
serving1.Fire()
|
||||
}
|
||||
})
|
||||
serving2 := grpcsync.NewEvent()
|
||||
modeChangeOpt2 := xds.ServingModeCallback(func(addr net.Addr, args xds.ServingModeChangeArgs) {
|
||||
t.Logf("Serving mode for listener %q changed to %q, err: %v", addr.String(), args.Mode, args.Err)
|
||||
if args.Mode == connectivity.ServingModeServing {
|
||||
serving2.Fire()
|
||||
}
|
||||
})
|
||||
|
||||
stub1 := &stubserver.StubServer{
|
||||
Listener: lis1,
|
||||
EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
|
||||
return &testpb.Empty{}, nil
|
||||
},
|
||||
}
|
||||
if stub1.S, err = xds.NewGRPCServer(xds.BootstrapContentsForTesting(bootstrapContents1), modeChangeOpt1); err != nil {
|
||||
t.Fatalf("Failed to create first xDS enabled gRPC server: %v", err)
|
||||
}
|
||||
stubserver.StartTestService(t, stub1)
|
||||
defer stub1.S.Stop()
|
||||
|
||||
stub2 := &stubserver.StubServer{
|
||||
Listener: lis2,
|
||||
EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
|
||||
return &testpb.Empty{}, nil
|
||||
},
|
||||
}
|
||||
if stub2.S, err = xds.NewGRPCServer(xds.BootstrapContentsForTesting(bootstrapContents2), modeChangeOpt2); err != nil {
|
||||
t.Fatalf("Failed to create second xDS enabled gRPC server: %v", err)
|
||||
}
|
||||
stubserver.StartTestService(t, stub2)
|
||||
defer stub2.S.Stop()
|
||||
|
||||
// Update the management server with the listener resources pointing to the
|
||||
// corresponding gRPC servers.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
|
||||
host1, port1, err := hostPortFromListener(lis1)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve host and port of server: %v", err)
|
||||
}
|
||||
host2, port2, err := hostPortFromListener(lis2)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve host and port of server: %v", err)
|
||||
}
|
||||
|
||||
resources1 := e2e.UpdateOptions{
|
||||
NodeID: nodeID1,
|
||||
Listeners: []*v3listenerpb.Listener{e2e.DefaultServerListener(host1, port1, e2e.SecurityLevelNone, "routeName")},
|
||||
}
|
||||
if err := mgmtServer.Update(ctx, resources1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resources2 := e2e.UpdateOptions{
|
||||
NodeID: nodeID2,
|
||||
Listeners: []*v3listenerpb.Listener{e2e.DefaultServerListener(host2, port2, e2e.SecurityLevelNone, "routeName")},
|
||||
}
|
||||
if err := mgmtServer.Update(ctx, resources2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Fatal("Timeout waiting for the server 1 to go Serving")
|
||||
case <-serving1.Done():
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Fatal("Timeout waiting for the server 2 to go Serving")
|
||||
case <-serving2.Done():
|
||||
}
|
||||
|
||||
// Create two gRPC clients, one for each server.
|
||||
cc1, err := grpc.NewClient(lis1.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create client for test server 1: %s, %v", lis1.Addr().String(), err)
|
||||
}
|
||||
defer cc1.Close()
|
||||
|
||||
cc2, err := grpc.NewClient(lis2.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create client for test server 2: %s, %v", lis2.Addr().String(), err)
|
||||
}
|
||||
defer cc2.Close()
|
||||
|
||||
// Both unary RPCs should work once the servers transitions into serving.
|
||||
var peer1 peer.Peer
|
||||
waitForSuccessfulRPC(ctx, t, cc1, grpc.Peer(&peer1))
|
||||
if peer1.Addr.String() != lis1.Addr().String() {
|
||||
t.Errorf("Connected to wrong peer: %s, want %s", peer1.Addr, lis1.Addr())
|
||||
}
|
||||
|
||||
var peer2 peer.Peer
|
||||
waitForSuccessfulRPC(ctx, t, cc2, grpc.Peer(&peer2))
|
||||
if peer2.Addr.String() != lis2.Addr().String() {
|
||||
t.Errorf("Connected to wrong peer: %s, want %s", peer2.Addr, lis2.Addr())
|
||||
}
|
||||
}
|
||||
|
||||
// TestResourceNotFoundRDS tests the case where an LDS points to an RDS which
|
||||
// returns resource not found. Before getting the resource not found, the xDS
|
||||
// Server has not received all configuration needed, so it should Accept and
|
||||
|
@ -280,7 +421,12 @@ func (s) TestResourceNotFoundRDS(t *testing.T) {
|
|||
}
|
||||
},
|
||||
}
|
||||
sopts := []grpc.ServerOption{grpc.Creds(insecure.NewCredentials()), modeChangeOpt, xds.BootstrapContentsForTesting(bootstrapContents)}
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bootstrapContents), err)
|
||||
}
|
||||
pool := xdsclient.NewPool(config)
|
||||
sopts := []grpc.ServerOption{grpc.Creds(insecure.NewCredentials()), modeChangeOpt, xds.ClientPoolForTesting(pool)}
|
||||
if stub.S, err = xds.NewGRPCServer(sopts...); err != nil {
|
||||
t.Fatalf("Failed to create an xDS enabled gRPC server: %v", err)
|
||||
}
|
||||
|
@ -297,7 +443,7 @@ func (s) TestResourceNotFoundRDS(t *testing.T) {
|
|||
|
||||
// Lookup the xDS client in use based on the dedicated well-known key, as
|
||||
// defined in A71, used by the xDS enabled gRPC server.
|
||||
xdsC, close, err := xdsclient.GetForTesting(xdsclient.NameForServer)
|
||||
xdsC, close, err := pool.GetClientForTesting(xdsclient.NameForServer)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to find xDS client for configuration: %v", string(bootstrapContents))
|
||||
}
|
||||
|
@ -325,11 +471,11 @@ loop:
|
|||
waitForFailedRPCWithStatus(ctx, t, cc, status.New(codes.Unavailable, "error from xDS configuration for matched route configuration"))
|
||||
}
|
||||
|
||||
func waitForSuccessfulRPC(ctx context.Context, t *testing.T, cc *grpc.ClientConn) {
|
||||
func waitForSuccessfulRPC(ctx context.Context, t *testing.T, cc *grpc.ClientConn, opts ...grpc.CallOption) {
|
||||
t.Helper()
|
||||
|
||||
c := testgrpc.NewTestServiceClient(cc)
|
||||
if _, err := c.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
|
||||
if _, err := c.EmptyCall(ctx, &testpb.Empty{}, opts...); err != nil {
|
||||
t.Fatalf("rpc EmptyCall() failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,13 @@ import (
|
|||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
"google.golang.org/grpc/internal/xds/bootstrap"
|
||||
"google.golang.org/grpc/xds/internal/xdsclient"
|
||||
)
|
||||
|
||||
type serverOptions struct {
|
||||
modeCallback ServingModeCallbackFunc
|
||||
bootstrapContentsForTesting []byte
|
||||
modeCallback ServingModeCallbackFunc
|
||||
clientPoolForTesting *xdsclient.Pool
|
||||
}
|
||||
|
||||
type serverOption struct {
|
||||
|
@ -71,6 +73,28 @@ type ServingModeChangeArgs struct {
|
|||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func BootstrapContentsForTesting(contents []byte) grpc.ServerOption {
|
||||
return &serverOption{apply: func(o *serverOptions) { o.bootstrapContentsForTesting = contents }}
|
||||
func BootstrapContentsForTesting(bootstrapContents []byte) grpc.ServerOption {
|
||||
config, err := bootstrap.NewConfigFromContents(bootstrapContents)
|
||||
if err != nil {
|
||||
logger.Warningf("Failed to parse bootstrap contents %s for server options: %v", string(bootstrapContents), err)
|
||||
return &serverOption{apply: func(o *serverOptions) { o.clientPoolForTesting = nil }}
|
||||
}
|
||||
return ClientPoolForTesting(xdsclient.NewPool(config))
|
||||
}
|
||||
|
||||
// ClientPoolForTesting returns a grpc.ServerOption with the pool for xds
|
||||
// clients. It allows users to set a pool for xDS clients sharing the bootstrap
|
||||
// contents for this server.
|
||||
//
|
||||
// # Testing Only
|
||||
//
|
||||
// This function should ONLY be used for testing and may not work with some
|
||||
// other features, including the CSDS service.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func ClientPoolForTesting(pool *xdsclient.Pool) grpc.ServerOption {
|
||||
return &serverOption{apply: func(o *serverOptions) { o.clientPoolForTesting = pool }}
|
||||
}
|
||||
|
|
|
@ -177,14 +177,14 @@ func (s) TestNewServer_Failure(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
desc: "bootstrap env var not set",
|
||||
serverOpts: []grpc.ServerOption{grpc.Creds(xdsCreds)},
|
||||
wantErr: "failed to get xDS bootstrap config",
|
||||
serverOpts: []grpc.ServerOption{grpc.Creds(xdsCreds), BootstrapContentsForTesting(nil)},
|
||||
wantErr: "bootstrap configuration not set in the pool",
|
||||
},
|
||||
{
|
||||
desc: "empty bootstrap config",
|
||||
serverOpts: []grpc.ServerOption{
|
||||
grpc.Creds(xdsCreds),
|
||||
BootstrapContentsForTesting([]byte(`{}`)),
|
||||
BootstrapContentsForTesting(nil),
|
||||
},
|
||||
wantErr: "xDS client creation failed",
|
||||
},
|
||||
|
@ -474,11 +474,9 @@ func (s) TestServeSuccess(t *testing.T) {
|
|||
// TestNewServer_ClientCreationFailure tests the case where the xDS client
|
||||
// creation fails and verifies that the call to NewGRPCServer() fails.
|
||||
func (s) TestNewServer_ClientCreationFailure(t *testing.T) {
|
||||
origNewXDSClient := newXDSClient
|
||||
newXDSClient = func(string) (xdsclient.XDSClient, func(), error) {
|
||||
return nil, nil, errors.New("xdsClient creation failed")
|
||||
}
|
||||
defer func() { newXDSClient = origNewXDSClient }()
|
||||
origXDSClientPool := xdsClientPool
|
||||
xdsClientPool = xdsclient.NewPool(nil)
|
||||
defer func() { xdsClientPool = origXDSClientPool }()
|
||||
|
||||
if _, err := NewGRPCServer(); err == nil {
|
||||
t.Fatal("NewGRPCServer() succeeded when expected to fail")
|
||||
|
|
Loading…
Reference in New Issue