Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xds: minor cleanup in xdsclient bootstrap code #5195

Merged
merged 1 commit into from Feb 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions internal/envconfig/xds.go
Expand Up @@ -26,13 +26,13 @@ import (
const (
// XDSBootstrapFileNameEnv is the env variable to set bootstrap file name.
// Do not use this and read from env directly. Its value is read and kept in
// variable BootstrapFileName.
// variable XDSBootstrapFileName.
//
// When both bootstrap FileName and FileContent are set, FileName is used.
XDSBootstrapFileNameEnv = "GRPC_XDS_BOOTSTRAP"
// XDSBootstrapFileContentEnv is the env variable to set bootstrapp file
// XDSBootstrapFileContentEnv is the env variable to set bootstrap file
// content. Do not use this and read from env directly. Its value is read
// and kept in variable BootstrapFileName.
// and kept in variable XDSBootstrapFileContent.
//
// When both bootstrap FileName and FileContent are set, FileName is used.
XDSBootstrapFileContentEnv = "GRPC_XDS_BOOTSTRAP_CONFIG"
Expand Down
10 changes: 5 additions & 5 deletions xds/internal/resolver/xds_resolver.go
Expand Up @@ -37,13 +37,13 @@ import (

const xdsScheme = "xds"

// NewBuilder 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.
func NewBuilder(config []byte) (resolver.Builder, error) {
// NewBuilderForTesting 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.
func NewBuilderForTesting(config []byte) (resolver.Builder, error) {
return &xdsResolverBuilder{
newXDSClient: func() (xdsclient.XDSClient, error) {
return xdsclient.NewClientWithBootstrapContents(config)
return xdsclient.NewWithBootstrapContentsForTesting(config)
},
}, nil
}
Expand Down
38 changes: 23 additions & 15 deletions xds/internal/xdsclient/bootstrap/bootstrap.go
Expand Up @@ -65,19 +65,20 @@ var gRPCVersion = fmt.Sprintf("%s %s", gRPCUserAgentName, grpc.Version)
// For overriding in unit tests.
var bootstrapFileReadFunc = ioutil.ReadFile

// insecureCredsBuilder encapsulates a insecure credential that is built using a
// JSON config.
// insecureCredsBuilder implements the `Credentials` interface defined in
// package `xds/bootstrap` and encapsulates an insecure credential.
type insecureCredsBuilder struct{}

func (i *insecureCredsBuilder) Build(json.RawMessage) (credentials.Bundle, error) {
return insecure.NewBundle(), nil
}

func (i *insecureCredsBuilder) Name() string {
return "insecure"
}

// googleDefaultCredsBuilder encapsulates a Google Default credential that is built using a
// JSON config.
// googleDefaultCredsBuilder implements the `Credentials` interface defined in
// package `xds/boostrap` and encapsulates a Google Default credential.
type googleDefaultCredsBuilder struct{}

func (d *googleDefaultCredsBuilder) Build(json.RawMessage) (credentials.Bundle, error) {
Expand Down Expand Up @@ -328,11 +329,13 @@ func bootstrapConfigFromEnvVariable() ([]byte, error) {
}

// NewConfig returns a new instance of Config initialized by reading the
// bootstrap file found at ${GRPC_XDS_BOOTSTRAP}.
// bootstrap file found at ${GRPC_XDS_BOOTSTRAP} or bootstrap contents specified
// at ${GRPC_XDS_BOOTSTRAP_CONFIG}. If both env vars are set, the former is
// preferred.
//
// Currently, we support exactly one type of credential, which is
// "google_default", where we use the host's default certs for transport
// credentials and a Google oauth token for call credentials.
// We support a credential registration mechanism and only credentials
// registered through that mechanism will be accepted here. See package
// `xds/bootstrap` for details.
//
// 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
Expand All @@ -346,13 +349,18 @@ func NewConfig() (*Config, error) {
return nil, fmt.Errorf("xds: Failed to read bootstrap config: %v", err)
}
logger.Debugf("Bootstrap content: %s", data)
return NewConfigFromContents(data)
return newConfigFromContents(data)
}

// NewConfigFromContentsForTesting returns a new Config using the specified
// bootstrap file contents instead of reading the environment variable.
//
// This is only suitable for testing purposes.
func NewConfigFromContentsForTesting(data []byte) (*Config, error) {
return newConfigFromContents(data)
}

// NewConfigFromContents returns a new Config using the specified bootstrap
// file contents instead of reading the environment variable. This is only
// suitable for testing purposes.
func NewConfigFromContents(data []byte) (*Config, error) {
func newConfigFromContents(data []byte) (*Config, error) {
config := &Config{}

var jsonData map[string]json.RawMessage
Expand Down Expand Up @@ -483,7 +491,7 @@ func NewConfigFromContents(data []byte) (*Config, error) {
// file are populated here.
// 3. For each server config (both top level and in each authority), we set its
// node field to the v3.Node, or a v2.Node with the same content, depending on
// the server's transprot API version.
// the server's transport API version.
func (c *Config) updateNodeProto(node *v3corepb.Node) error {
v3 := node
if v3 == nil {
Expand All @@ -493,11 +501,11 @@ func (c *Config) updateNodeProto(node *v3corepb.Node) error {
v3.UserAgentVersionType = &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}
v3.ClientFeatures = append(v3.ClientFeatures, clientFeatureNoOverprovisioning)

v2 := &v2corepb.Node{}
v3bytes, err := proto.Marshal(v3)
if err != nil {
return fmt.Errorf("xds: proto.Marshal(%v): %v", v3, err)
}
v2 := &v2corepb.Node{}
if err := proto.Unmarshal(v3bytes, v2); err != nil {
return fmt.Errorf("xds: proto.Unmarshal(%v): %v", v3bytes, err)
}
Expand Down
17 changes: 9 additions & 8 deletions xds/internal/xdsclient/singleton.go
Expand Up @@ -160,10 +160,10 @@ func (c *clientRefCounted) Close() {
}
}

// NewWithConfigForTesting is exported for testing only.
// NewWithConfigForTesting returns an xdsClient for the specified bootstrap
// config, separate from the global singleton.
//
// Note that this function doesn't set the singleton, so that the testing states
// don't leak.
// This should be used for testing purposes only.
func NewWithConfigForTesting(config *bootstrap.Config, watchExpiryTimeout time.Duration) (XDSClient, error) {
cl, err := newWithConfig(config, watchExpiryTimeout, defaultIdleAuthorityDeleteTimeout)
if err != nil {
Expand All @@ -172,10 +172,11 @@ func NewWithConfigForTesting(config *bootstrap.Config, watchExpiryTimeout time.D
return &clientRefCounted{clientImpl: cl, refCount: 1}, nil
}

// NewClientWithBootstrapContents returns an xds client for this config,
// separate from the global singleton. This should be used for testing
// purposes only.
func NewClientWithBootstrapContents(contents []byte) (XDSClient, error) {
// NewWithBootstrapContentsForTesting returns an xdsClient for this config,
// separate from the global singleton.
//
// This should be used for testing purposes only.
func NewWithBootstrapContentsForTesting(contents []byte) (XDSClient, error) {
// Normalize the contents
buf := bytes.Buffer{}
err := json.Indent(&buf, contents, "", "")
Expand All @@ -198,7 +199,7 @@ func NewClientWithBootstrapContents(contents []byte) (XDSClient, error) {
c.mu.Unlock()
}

bcfg, err := bootstrap.NewConfigFromContents(contents)
bcfg, err := bootstrap.NewConfigFromContentsForTesting(contents)
if err != nil {
return nil, fmt.Errorf("xds: error with bootstrap config: %v", err)
}
Expand Down
6 changes: 4 additions & 2 deletions xds/server.go
Expand Up @@ -161,11 +161,13 @@ func (s *GRPCServer) initXDSClient() error {
}

newXDSClient := newXDSClient
if s.opts.bootstrapContents != nil {
if s.opts.bootstrapContentsForTesting != nil {
// Bootstrap file contents may be specified as a server option for tests.
newXDSClient = func() (xdsclient.XDSClient, error) {
return xdsclient.NewClientWithBootstrapContents(s.opts.bootstrapContents)
return xdsclient.NewWithBootstrapContentsForTesting(s.opts.bootstrapContentsForTesting)
}
}

client, err := newXDSClient()
if err != nil {
return fmt.Errorf("xds: failed to create xds-client: %v", err)
Expand Down
6 changes: 3 additions & 3 deletions xds/server_options.go
Expand Up @@ -26,8 +26,8 @@ import (
)

type serverOptions struct {
modeCallback ServingModeCallbackFunc
bootstrapContents []byte
modeCallback ServingModeCallbackFunc
bootstrapContentsForTesting []byte
}

type serverOption struct {
Expand Down Expand Up @@ -72,5 +72,5 @@ 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.bootstrapContents = contents }}
return &serverOption{apply: func(o *serverOptions) { o.bootstrapContentsForTesting = contents }}
}
2 changes: 1 addition & 1 deletion xds/xds.go
Expand Up @@ -90,5 +90,5 @@ func init() {
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
// later release.
func NewXDSResolverWithConfigForTesting(bootstrapConfig []byte) (resolver.Builder, error) {
return xdsresolver.NewBuilder(bootstrapConfig)
return xdsresolver.NewBuilderForTesting(bootstrapConfig)
}