mirror of https://github.com/grpc/grpc-go.git
xds: minor cleanup in xdsclient bootstrap code (#5195)
This commit is contained in:
parent
ebc30b8fc3
commit
ec717cad73
|
@ -26,13 +26,13 @@ import (
|
||||||
const (
|
const (
|
||||||
// XDSBootstrapFileNameEnv is the env variable to set bootstrap file name.
|
// 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
|
// 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.
|
// When both bootstrap FileName and FileContent are set, FileName is used.
|
||||||
XDSBootstrapFileNameEnv = "GRPC_XDS_BOOTSTRAP"
|
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
|
// 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.
|
// When both bootstrap FileName and FileContent are set, FileName is used.
|
||||||
XDSBootstrapFileContentEnv = "GRPC_XDS_BOOTSTRAP_CONFIG"
|
XDSBootstrapFileContentEnv = "GRPC_XDS_BOOTSTRAP_CONFIG"
|
||||||
|
|
|
@ -37,13 +37,13 @@ import (
|
||||||
|
|
||||||
const xdsScheme = "xds"
|
const xdsScheme = "xds"
|
||||||
|
|
||||||
// NewBuilder creates a new xds resolver builder using a specific xds bootstrap
|
// NewBuilderForTesting creates a new xds resolver builder using a specific xds
|
||||||
// config, so tests can use multiple xds clients in different ClientConns at
|
// bootstrap config, so tests can use multiple xds clients in different
|
||||||
// the same time.
|
// ClientConns at the same time.
|
||||||
func NewBuilder(config []byte) (resolver.Builder, error) {
|
func NewBuilderForTesting(config []byte) (resolver.Builder, error) {
|
||||||
return &xdsResolverBuilder{
|
return &xdsResolverBuilder{
|
||||||
newXDSClient: func() (xdsclient.XDSClient, error) {
|
newXDSClient: func() (xdsclient.XDSClient, error) {
|
||||||
return xdsclient.NewClientWithBootstrapContents(config)
|
return xdsclient.NewWithBootstrapContentsForTesting(config)
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,19 +65,20 @@ var gRPCVersion = fmt.Sprintf("%s %s", gRPCUserAgentName, grpc.Version)
|
||||||
// For overriding in unit tests.
|
// For overriding in unit tests.
|
||||||
var bootstrapFileReadFunc = ioutil.ReadFile
|
var bootstrapFileReadFunc = ioutil.ReadFile
|
||||||
|
|
||||||
// insecureCredsBuilder encapsulates a insecure credential that is built using a
|
// insecureCredsBuilder implements the `Credentials` interface defined in
|
||||||
// JSON config.
|
// package `xds/bootstrap` and encapsulates an insecure credential.
|
||||||
type insecureCredsBuilder struct{}
|
type insecureCredsBuilder struct{}
|
||||||
|
|
||||||
func (i *insecureCredsBuilder) Build(json.RawMessage) (credentials.Bundle, error) {
|
func (i *insecureCredsBuilder) Build(json.RawMessage) (credentials.Bundle, error) {
|
||||||
return insecure.NewBundle(), nil
|
return insecure.NewBundle(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *insecureCredsBuilder) Name() string {
|
func (i *insecureCredsBuilder) Name() string {
|
||||||
return "insecure"
|
return "insecure"
|
||||||
}
|
}
|
||||||
|
|
||||||
// googleDefaultCredsBuilder encapsulates a Google Default credential that is built using a
|
// googleDefaultCredsBuilder implements the `Credentials` interface defined in
|
||||||
// JSON config.
|
// package `xds/boostrap` and encapsulates a Google Default credential.
|
||||||
type googleDefaultCredsBuilder struct{}
|
type googleDefaultCredsBuilder struct{}
|
||||||
|
|
||||||
func (d *googleDefaultCredsBuilder) Build(json.RawMessage) (credentials.Bundle, error) {
|
func (d *googleDefaultCredsBuilder) Build(json.RawMessage) (credentials.Bundle, error) {
|
||||||
|
@ -328,11 +329,13 @@ func bootstrapConfigFromEnvVariable() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfig returns a new instance of Config initialized by reading the
|
// 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
|
// We support a credential registration mechanism and only credentials
|
||||||
// "google_default", where we use the host's default certs for transport
|
// registered through that mechanism will be accepted here. See package
|
||||||
// credentials and a Google oauth token for call credentials.
|
// `xds/bootstrap` for details.
|
||||||
//
|
//
|
||||||
// This function tries to process as much of the bootstrap file as possible (in
|
// 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
|
// the presence of the errors) and may return a Config object with certain
|
||||||
|
@ -346,13 +349,18 @@ func NewConfig() (*Config, error) {
|
||||||
return nil, fmt.Errorf("xds: Failed to read bootstrap config: %v", err)
|
return nil, fmt.Errorf("xds: Failed to read bootstrap config: %v", err)
|
||||||
}
|
}
|
||||||
logger.Debugf("Bootstrap content: %s", data)
|
logger.Debugf("Bootstrap content: %s", data)
|
||||||
return NewConfigFromContents(data)
|
return newConfigFromContents(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfigFromContents returns a new Config using the specified bootstrap
|
// NewConfigFromContentsForTesting returns a new Config using the specified
|
||||||
// file contents instead of reading the environment variable. This is only
|
// bootstrap file contents instead of reading the environment variable.
|
||||||
// suitable for testing purposes.
|
//
|
||||||
func NewConfigFromContents(data []byte) (*Config, error) {
|
// This is only suitable for testing purposes.
|
||||||
|
func NewConfigFromContentsForTesting(data []byte) (*Config, error) {
|
||||||
|
return newConfigFromContents(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConfigFromContents(data []byte) (*Config, error) {
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
|
|
||||||
var jsonData map[string]json.RawMessage
|
var jsonData map[string]json.RawMessage
|
||||||
|
@ -483,7 +491,7 @@ func NewConfigFromContents(data []byte) (*Config, error) {
|
||||||
// file are populated here.
|
// file are populated here.
|
||||||
// 3. For each server config (both top level and in each authority), we set its
|
// 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
|
// 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 {
|
func (c *Config) updateNodeProto(node *v3corepb.Node) error {
|
||||||
v3 := node
|
v3 := node
|
||||||
if v3 == nil {
|
if v3 == nil {
|
||||||
|
@ -493,11 +501,11 @@ func (c *Config) updateNodeProto(node *v3corepb.Node) error {
|
||||||
v3.UserAgentVersionType = &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}
|
v3.UserAgentVersionType = &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}
|
||||||
v3.ClientFeatures = append(v3.ClientFeatures, clientFeatureNoOverprovisioning)
|
v3.ClientFeatures = append(v3.ClientFeatures, clientFeatureNoOverprovisioning)
|
||||||
|
|
||||||
v2 := &v2corepb.Node{}
|
|
||||||
v3bytes, err := proto.Marshal(v3)
|
v3bytes, err := proto.Marshal(v3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("xds: proto.Marshal(%v): %v", v3, err)
|
return fmt.Errorf("xds: proto.Marshal(%v): %v", v3, err)
|
||||||
}
|
}
|
||||||
|
v2 := &v2corepb.Node{}
|
||||||
if err := proto.Unmarshal(v3bytes, v2); err != nil {
|
if err := proto.Unmarshal(v3bytes, v2); err != nil {
|
||||||
return fmt.Errorf("xds: proto.Unmarshal(%v): %v", v3bytes, err)
|
return fmt.Errorf("xds: proto.Unmarshal(%v): %v", v3bytes, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
// This should be used for testing purposes only.
|
||||||
// don't leak.
|
|
||||||
func NewWithConfigForTesting(config *bootstrap.Config, watchExpiryTimeout time.Duration) (XDSClient, error) {
|
func NewWithConfigForTesting(config *bootstrap.Config, watchExpiryTimeout time.Duration) (XDSClient, error) {
|
||||||
cl, err := newWithConfig(config, watchExpiryTimeout, defaultIdleAuthorityDeleteTimeout)
|
cl, err := newWithConfig(config, watchExpiryTimeout, defaultIdleAuthorityDeleteTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -172,10 +172,11 @@ func NewWithConfigForTesting(config *bootstrap.Config, watchExpiryTimeout time.D
|
||||||
return &clientRefCounted{clientImpl: cl, refCount: 1}, nil
|
return &clientRefCounted{clientImpl: cl, refCount: 1}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientWithBootstrapContents returns an xds client for this config,
|
// NewWithBootstrapContentsForTesting returns an xdsClient for this config,
|
||||||
// separate from the global singleton. This should be used for testing
|
// separate from the global singleton.
|
||||||
// purposes only.
|
//
|
||||||
func NewClientWithBootstrapContents(contents []byte) (XDSClient, error) {
|
// This should be used for testing purposes only.
|
||||||
|
func NewWithBootstrapContentsForTesting(contents []byte) (XDSClient, error) {
|
||||||
// Normalize the contents
|
// Normalize the contents
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
err := json.Indent(&buf, contents, "", "")
|
err := json.Indent(&buf, contents, "", "")
|
||||||
|
@ -198,7 +199,7 @@ func NewClientWithBootstrapContents(contents []byte) (XDSClient, error) {
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
bcfg, err := bootstrap.NewConfigFromContents(contents)
|
bcfg, err := bootstrap.NewConfigFromContentsForTesting(contents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("xds: error with bootstrap config: %v", err)
|
return nil, fmt.Errorf("xds: error with bootstrap config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,11 +161,13 @@ func (s *GRPCServer) initXDSClient() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
newXDSClient := newXDSClient
|
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) {
|
newXDSClient = func() (xdsclient.XDSClient, error) {
|
||||||
return xdsclient.NewClientWithBootstrapContents(s.opts.bootstrapContents)
|
return xdsclient.NewWithBootstrapContentsForTesting(s.opts.bootstrapContentsForTesting)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := newXDSClient()
|
client, err := newXDSClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("xds: failed to create xds-client: %v", err)
|
return fmt.Errorf("xds: failed to create xds-client: %v", err)
|
||||||
|
|
|
@ -26,8 +26,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type serverOptions struct {
|
type serverOptions struct {
|
||||||
modeCallback ServingModeCallbackFunc
|
modeCallback ServingModeCallbackFunc
|
||||||
bootstrapContents []byte
|
bootstrapContentsForTesting []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type serverOption struct {
|
type serverOption struct {
|
||||||
|
@ -72,5 +72,5 @@ type ServingModeChangeArgs struct {
|
||||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||||
// later release.
|
// later release.
|
||||||
func BootstrapContentsForTesting(contents []byte) grpc.ServerOption {
|
func BootstrapContentsForTesting(contents []byte) grpc.ServerOption {
|
||||||
return &serverOption{apply: func(o *serverOptions) { o.bootstrapContents = contents }}
|
return &serverOption{apply: func(o *serverOptions) { o.bootstrapContentsForTesting = contents }}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,5 +90,5 @@ func init() {
|
||||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||||
// later release.
|
// later release.
|
||||||
func NewXDSResolverWithConfigForTesting(bootstrapConfig []byte) (resolver.Builder, error) {
|
func NewXDSResolverWithConfigForTesting(bootstrapConfig []byte) (resolver.Builder, error) {
|
||||||
return xdsresolver.NewBuilder(bootstrapConfig)
|
return xdsresolver.NewBuilderForTesting(bootstrapConfig)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue