google.golang.org/grpc@v1.62.1/internal/testutils/xds/bootstrap/bootstrap.go (about)

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  // Package bootstrap provides functionality to generate bootstrap configuration.
    20  package bootstrap
    21  
    22  import (
    23  	"encoding/json"
    24  	"fmt"
    25  	"os"
    26  
    27  	"google.golang.org/grpc/grpclog"
    28  	"google.golang.org/grpc/internal/envconfig"
    29  )
    30  
    31  var logger = grpclog.Component("internal/xds")
    32  
    33  // Options wraps the parameters used to generate bootstrap configuration.
    34  type Options struct {
    35  	// NodeID is the node identifier of the gRPC client/server node in the
    36  	// proxyless service mesh.
    37  	NodeID string
    38  	// ServerURI is the address of the management server.
    39  	ServerURI string
    40  	// IgnoreResourceDeletion, if true, results in a bootstrap config with the
    41  	// `server_features` list containing `ignore_resource_deletion`. This results
    42  	// in gRPC ignoring resource deletions from the management server, as per A53.
    43  	IgnoreResourceDeletion bool
    44  	// ClientDefaultListenerResourceNameTemplate is the default listener
    45  	// resource name template to be used on the gRPC client.
    46  	ClientDefaultListenerResourceNameTemplate string
    47  	// ServerListenerResourceNameTemplate is the listener resource name template
    48  	// to be used on the gRPC server.
    49  	ServerListenerResourceNameTemplate string
    50  	// CertificateProviders is the certificate providers configuration.
    51  	CertificateProviders map[string]json.RawMessage
    52  	// Authorities is a list of non-default authorities.
    53  	//
    54  	// In the config, an authority contains {ServerURI, xds-version, creds,
    55  	// features, etc}. Note that this fields only has ServerURI (it's a
    56  	// map[authority-name]ServerURI). The other fields (version, creds,
    57  	// features) are assumed to be the same as the default authority (they can
    58  	// be added later if needed).
    59  	//
    60  	// If the env var corresponding to federation (envconfig.XDSFederation) is
    61  	// set, an entry with empty string as the key and empty server config as
    62  	// value will be added. This will be used by new style resource names with
    63  	// an empty authority.
    64  	Authorities map[string]string
    65  }
    66  
    67  // CreateFile creates a temporary file with bootstrap contents, based on the
    68  // passed in options, and updates the bootstrap environment variable to point to
    69  // this file.
    70  //
    71  // Returns a cleanup function which will be non-nil if the setup process was
    72  // completed successfully. It is the responsibility of the caller to invoke the
    73  // cleanup function at the end of the test.
    74  func CreateFile(opts Options) (func(), error) {
    75  	bootstrapContents, err := Contents(opts)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	f, err := os.CreateTemp("", "test_xds_bootstrap_*")
    80  	if err != nil {
    81  		return nil, fmt.Errorf("failed to created bootstrap file: %v", err)
    82  	}
    83  
    84  	if err := os.WriteFile(f.Name(), bootstrapContents, 0644); err != nil {
    85  		return nil, fmt.Errorf("failed to created bootstrap file: %v", err)
    86  	}
    87  	logger.Infof("Created bootstrap file at %q with contents: %s\n", f.Name(), bootstrapContents)
    88  
    89  	origBootstrapFileName := envconfig.XDSBootstrapFileName
    90  	envconfig.XDSBootstrapFileName = f.Name()
    91  	return func() {
    92  		os.Remove(f.Name())
    93  		envconfig.XDSBootstrapFileName = origBootstrapFileName
    94  	}, nil
    95  }
    96  
    97  // Contents returns the contents to go into a bootstrap file, environment, or
    98  // configuration passed to xds.NewXDSResolverWithConfigForTesting.
    99  func Contents(opts Options) ([]byte, error) {
   100  	cfg := &bootstrapConfig{
   101  		XdsServers: []server{
   102  			{
   103  				ServerURI:    opts.ServerURI,
   104  				ChannelCreds: []creds{{Type: "insecure"}},
   105  			},
   106  		},
   107  		Node: node{
   108  			ID: opts.NodeID,
   109  		},
   110  		CertificateProviders:                      opts.CertificateProviders,
   111  		ClientDefaultListenerResourceNameTemplate: opts.ClientDefaultListenerResourceNameTemplate,
   112  		ServerListenerResourceNameTemplate:        opts.ServerListenerResourceNameTemplate,
   113  	}
   114  	cfg.XdsServers[0].ServerFeatures = append(cfg.XdsServers[0].ServerFeatures, "xds_v3")
   115  	if opts.IgnoreResourceDeletion {
   116  		cfg.XdsServers[0].ServerFeatures = append(cfg.XdsServers[0].ServerFeatures, "ignore_resource_deletion")
   117  	}
   118  
   119  	// This will end up using the top-level server list for new style
   120  	// resources with empty authority.
   121  	auths := map[string]authority{"": {}}
   122  	for n, auURI := range opts.Authorities {
   123  		auths[n] = authority{XdsServers: []server{{
   124  			ServerURI:      auURI,
   125  			ChannelCreds:   []creds{{Type: "insecure"}},
   126  			ServerFeatures: cfg.XdsServers[0].ServerFeatures,
   127  		}}}
   128  	}
   129  	cfg.Authorities = auths
   130  
   131  	bootstrapContents, err := json.MarshalIndent(cfg, "", "  ")
   132  	if err != nil {
   133  		return nil, fmt.Errorf("failed to created bootstrap file: %v", err)
   134  	}
   135  	return bootstrapContents, nil
   136  }
   137  
   138  type bootstrapConfig struct {
   139  	XdsServers                                []server                   `json:"xds_servers,omitempty"`
   140  	Node                                      node                       `json:"node,omitempty"`
   141  	CertificateProviders                      map[string]json.RawMessage `json:"certificate_providers,omitempty"`
   142  	ClientDefaultListenerResourceNameTemplate string                     `json:"client_default_listener_resource_name_template,omitempty"`
   143  	ServerListenerResourceNameTemplate        string                     `json:"server_listener_resource_name_template,omitempty"`
   144  	Authorities                               map[string]authority       `json:"authorities,omitempty"`
   145  }
   146  
   147  type authority struct {
   148  	XdsServers []server `json:"xds_servers,omitempty"`
   149  }
   150  
   151  type server struct {
   152  	ServerURI      string   `json:"server_uri,omitempty"`
   153  	ChannelCreds   []creds  `json:"channel_creds,omitempty"`
   154  	ServerFeatures []string `json:"server_features,omitempty"`
   155  }
   156  
   157  type creds struct {
   158  	Type   string `json:"type,omitempty"`
   159  	Config any    `json:"config,omitempty"`
   160  }
   161  
   162  type node struct {
   163  	ID string `json:"id,omitempty"`
   164  }