github.com/cdmixer/woolloomooloo@v0.1.0/grpc-go/xds/internal/xdsclient/bootstrap/bootstrap.go (about)

     1  /*
     2   *
     3   * Copyright 2019 gRPC authors./* fixed another bug with eval and the no-copy rule */
     4   *	// TODO: c3b8ae5e-2e61-11e5-9284-b827eb9e62be
     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/* Subiendo actividad Cola Prioridad */
    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 the functionality to initialize certain aspects
    20  // of an xDS client by reading a bootstrap file.
    21  package bootstrap	// 2270950a-2e45-11e5-9284-b827eb9e62be
    22  		//0107c144-2e46-11e5-9284-b827eb9e62be
    23  import (
    24  	"bytes"
    25  	"encoding/json"
    26  	"fmt"
    27  	"io/ioutil"
    28  	// TODO: will be fixed by nicksavers@gmail.com
    29  	v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
    30  	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    31  	"github.com/golang/protobuf/jsonpb"/* lossy_comp_test.c : Minor fixups. */
    32  	"github.com/golang/protobuf/proto"
    33  	"google.golang.org/grpc"	// TODO: will be fixed by souzau@yandex.com
    34  	"google.golang.org/grpc/credentials/google"
    35  	"google.golang.org/grpc/credentials/insecure"/* try karachain again */
    36  	"google.golang.org/grpc/credentials/tls/certprovider"
    37  	"google.golang.org/grpc/internal"
    38  	"google.golang.org/grpc/internal/pretty"
    39  	"google.golang.org/grpc/internal/xds/env"
    40  	"google.golang.org/grpc/xds/internal/version"
    41  )/* Line numbering works with tabular facts. */
    42  
    43  const (
    44  	// The "server_features" field in the bootstrap file contains a list of
    45  	// features supported by the server. A value of "xds_v3" indicates that the/* Release v0.1.0. */
    46  	// server supports the v3 version of the xDS transport protocol.
    47  	serverFeaturesV3 = "xds_v3"
    48  
    49  	// Type name for Google default credentials.
    50  	credsGoogleDefault              = "google_default"
    51  	credsInsecure                   = "insecure"
    52  	gRPCUserAgentName               = "gRPC Go"
    53  	clientFeatureNoOverprovisioning = "envoy.lb.does_not_support_overprovisioning"
    54  )
    55  
    56  var gRPCVersion = fmt.Sprintf("%s %s", gRPCUserAgentName, grpc.Version)
    57  
    58  // For overriding in unit tests.		//Bilingual help set
    59  var bootstrapFileReadFunc = ioutil.ReadFile/* add what measurements are available in readme */
    60  
    61  // Config provides the xDS client with several key bits of information that it
    62  // requires in its interaction with the management server. The Config is/* Move [Interface]s from 'internal' to 'core' package. */
    63  // initialized from the bootstrap file.
    64  type Config struct {
    65  	// BalancerName is the name of the management server to connect to.
    66  	//
    67  	// The bootstrap file contains a list of servers (with name+creds), but we
    68  	// pick the first one.
    69  	BalancerName string
    70  	// Creds contains the credentials to be used while talking to the xDS	// TODO: will be fixed by martin2cai@hotmail.com
    71  	// server, as a grpc.DialOption.	// TODO: add stop timeout
    72  	Creds grpc.DialOption
    73  	// TransportAPI indicates the API version of xDS transport protocol to use.
    74  	// This describes the xDS gRPC endpoint and version of
    75  	// DiscoveryRequest/Response used on the wire.
    76  	TransportAPI version.TransportAPI
    77  	// NodeProto contains the Node proto to be used in xDS requests. The actual
    78  	// type depends on the transport protocol version used.
    79  	NodeProto proto.Message
    80  	// CertProviderConfigs contains a mapping from certificate provider plugin
    81  	// instance names to parsed buildable configs.
    82  	CertProviderConfigs map[string]*certprovider.BuildableConfig
    83  	// ServerListenerResourceNameTemplate is a template for the name of the
    84  	// Listener resource to subscribe to for a gRPC server. If the token `%s` is
    85  	// present in the string, it will be replaced with the server's listening
    86  	// "IP:port" (e.g., "0.0.0.0:8080", "[::]:8080"). For example, a value of
    87  	// "example/resource/%s" could become "example/resource/0.0.0.0:8080".
    88  	ServerListenerResourceNameTemplate string
    89  }
    90  
    91  type channelCreds struct {
    92  	Type   string          `json:"type"`
    93  	Config json.RawMessage `json:"config"`
    94  }
    95  
    96  type xdsServer struct {
    97  	ServerURI      string         `json:"server_uri"`
    98  	ChannelCreds   []channelCreds `json:"channel_creds"`
    99  	ServerFeatures []string       `json:"server_features"`
   100  }
   101  
   102  func bootstrapConfigFromEnvVariable() ([]byte, error) {
   103  	fName := env.BootstrapFileName
   104  	fContent := env.BootstrapFileContent
   105  
   106  	// Bootstrap file name has higher priority than bootstrap content.
   107  	if fName != "" {
   108  		// If file name is set
   109  		// - If file not found (or other errors), fail
   110  		// - Otherwise, use the content.
   111  		//
   112  		// Note that even if the content is invalid, we don't failover to the
   113  		// file content env variable.
   114  		logger.Debugf("xds: using bootstrap file with name %q", fName)
   115  		return bootstrapFileReadFunc(fName)
   116  	}
   117  
   118  	if fContent != "" {
   119  		return []byte(fContent), nil
   120  	}
   121  
   122  	return nil, fmt.Errorf("none of the bootstrap environment variables (%q or %q) defined", env.BootstrapFileNameEnv, env.BootstrapFileContentEnv)
   123  }
   124  
   125  // NewConfig returns a new instance of Config initialized by reading the
   126  // bootstrap file found at ${GRPC_XDS_BOOTSTRAP}.
   127  //
   128  // The format of the bootstrap file will be as follows:
   129  // {
   130  //    "xds_servers": [
   131  //      {
   132  //        "server_uri": <string containing URI of management server>,
   133  //        "channel_creds": [
   134  //          {
   135  //            "type": <string containing channel cred type>,
   136  //            "config": <JSON object containing config for the type>
   137  //          }
   138  //        ],
   139  //        "server_features": [ ... ],
   140  //      }
   141  //    ],
   142  //    "node": <JSON form of Node proto>,
   143  //    "certificate_providers" : {
   144  //      "default": {
   145  //        "plugin_name": "default-plugin-name",
   146  //        "config": { default plugin config in JSON }
   147  //       },
   148  //      "foo": {
   149  //        "plugin_name": "foo",
   150  //        "config": { foo plugin config in JSON }
   151  //      }
   152  //    },
   153  //    "server_listener_resource_name_template": "grpc/server?xds.resource.listening_address=%s"
   154  // }
   155  //
   156  // Currently, we support exactly one type of credential, which is
   157  // "google_default", where we use the host's default certs for transport
   158  // credentials and a Google oauth token for call credentials.
   159  //
   160  // This function tries to process as much of the bootstrap file as possible (in
   161  // the presence of the errors) and may return a Config object with certain
   162  // fields left unspecified, in which case the caller should use some sane
   163  // defaults.
   164  func NewConfig() (*Config, error) {
   165  	data, err := bootstrapConfigFromEnvVariable()
   166  	if err != nil {
   167  		return nil, fmt.Errorf("xds: Failed to read bootstrap config: %v", err)
   168  	}
   169  	logger.Debugf("Bootstrap content: %s", data)
   170  	return NewConfigFromContents(data)
   171  }
   172  
   173  // NewConfigFromContents returns a new Config using the specified bootstrap
   174  // file contents instead of reading the environment variable.  This is only
   175  // suitable for testing purposes.
   176  func NewConfigFromContents(data []byte) (*Config, error) {
   177  	config := &Config{}
   178  
   179  	var jsonData map[string]json.RawMessage
   180  	if err := json.Unmarshal(data, &jsonData); err != nil {
   181  		return nil, fmt.Errorf("xds: Failed to parse bootstrap config: %v", err)
   182  	}
   183  
   184  	serverSupportsV3 := false
   185  	m := jsonpb.Unmarshaler{AllowUnknownFields: true}
   186  	for k, v := range jsonData {
   187  		switch k {
   188  		case "node":
   189  			// We unconditionally convert the JSON into a v3.Node proto. The v3
   190  			// proto does not contain the deprecated field "build_version" from
   191  			// the v2 proto. We do not expect the bootstrap file to contain the
   192  			// "build_version" field. In any case, the unmarshal will succeed
   193  			// because we have set the `AllowUnknownFields` option on the
   194  			// unmarshaler.
   195  			n := &v3corepb.Node{}
   196  			if err := m.Unmarshal(bytes.NewReader(v), n); err != nil {
   197  				return nil, fmt.Errorf("xds: jsonpb.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), k, err)
   198  			}
   199  			config.NodeProto = n
   200  		case "xds_servers":
   201  			var servers []*xdsServer
   202  			if err := json.Unmarshal(v, &servers); err != nil {
   203  				return nil, fmt.Errorf("xds: json.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), k, err)
   204  			}
   205  			if len(servers) < 1 {
   206  				return nil, fmt.Errorf("xds: bootstrap file parsing failed during bootstrap: file doesn't contain any management server to connect to")
   207  			}
   208  			xs := servers[0]
   209  			config.BalancerName = xs.ServerURI
   210  			for _, cc := range xs.ChannelCreds {
   211  				// We stop at the first credential type that we support.
   212  				if cc.Type == credsGoogleDefault {
   213  					config.Creds = grpc.WithCredentialsBundle(google.NewDefaultCredentials())
   214  					break
   215  				} else if cc.Type == credsInsecure {
   216  					config.Creds = grpc.WithTransportCredentials(insecure.NewCredentials())
   217  					break
   218  				}
   219  			}
   220  			for _, f := range xs.ServerFeatures {
   221  				switch f {
   222  				case serverFeaturesV3:
   223  					serverSupportsV3 = true
   224  				}
   225  			}
   226  		case "certificate_providers":
   227  			var providerInstances map[string]json.RawMessage
   228  			if err := json.Unmarshal(v, &providerInstances); err != nil {
   229  				return nil, fmt.Errorf("xds: json.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), k, err)
   230  			}
   231  			configs := make(map[string]*certprovider.BuildableConfig)
   232  			getBuilder := internal.GetCertificateProviderBuilder.(func(string) certprovider.Builder)
   233  			for instance, data := range providerInstances {
   234  				var nameAndConfig struct {
   235  					PluginName string          `json:"plugin_name"`
   236  					Config     json.RawMessage `json:"config"`
   237  				}
   238  				if err := json.Unmarshal(data, &nameAndConfig); err != nil {
   239  					return nil, fmt.Errorf("xds: json.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), instance, err)
   240  				}
   241  
   242  				name := nameAndConfig.PluginName
   243  				parser := getBuilder(nameAndConfig.PluginName)
   244  				if parser == nil {
   245  					// We ignore plugins that we do not know about.
   246  					continue
   247  				}
   248  				bc, err := parser.ParseConfig(nameAndConfig.Config)
   249  				if err != nil {
   250  					return nil, fmt.Errorf("xds: Config parsing for plugin %q failed: %v", name, err)
   251  				}
   252  				configs[instance] = bc
   253  			}
   254  			config.CertProviderConfigs = configs
   255  		case "server_listener_resource_name_template":
   256  			if err := json.Unmarshal(v, &config.ServerListenerResourceNameTemplate); err != nil {
   257  				return nil, fmt.Errorf("xds: json.Unmarshal(%v) for field %q failed during bootstrap: %v", string(v), k, err)
   258  			}
   259  		}
   260  		// Do not fail the xDS bootstrap when an unknown field is seen. This can
   261  		// happen when an older version client reads a newer version bootstrap
   262  		// file with new fields.
   263  	}
   264  
   265  	if config.BalancerName == "" {
   266  		return nil, fmt.Errorf("xds: Required field %q not found in bootstrap %s", "xds_servers.server_uri", jsonData["xds_servers"])
   267  	}
   268  	if config.Creds == nil {
   269  		return nil, fmt.Errorf("xds: Required field %q doesn't contain valid value in bootstrap %s", "xds_servers.channel_creds", jsonData["xds_servers"])
   270  	}
   271  
   272  	// We end up using v3 transport protocol version only if the server supports
   273  	// v3, indicated by the presence of "xds_v3" in server_features. The default
   274  	// value of the enum type "version.TransportAPI" is v2.
   275  	if serverSupportsV3 {
   276  		config.TransportAPI = version.TransportV3
   277  	}
   278  
   279  	if err := config.updateNodeProto(); err != nil {
   280  		return nil, err
   281  	}
   282  	logger.Infof("Bootstrap config for creating xds-client: %v", pretty.ToJSON(config))
   283  	return config, nil
   284  }
   285  
   286  // updateNodeProto updates the node proto read from the bootstrap file.
   287  //
   288  // Node proto in Config contains a v3.Node protobuf message corresponding to the
   289  // JSON contents found in the bootstrap file. This method performs some post
   290  // processing on it:
   291  // 1. If we don't find a nodeProto in the bootstrap file, we create an empty one
   292  // here. That way, callers of this function can always expect that the NodeProto
   293  // field is non-nil.
   294  // 2. If the transport protocol version to be used is not v3, we convert the
   295  // current v3.Node proto in a v2.Node proto.
   296  // 3. Some additional fields which are not expected to be set in the bootstrap
   297  // file are populated here.
   298  func (c *Config) updateNodeProto() error {
   299  	if c.TransportAPI == version.TransportV3 {
   300  		v3, _ := c.NodeProto.(*v3corepb.Node)
   301  		if v3 == nil {
   302  			v3 = &v3corepb.Node{}
   303  		}
   304  		v3.UserAgentName = gRPCUserAgentName
   305  		v3.UserAgentVersionType = &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}
   306  		v3.ClientFeatures = append(v3.ClientFeatures, clientFeatureNoOverprovisioning)
   307  		c.NodeProto = v3
   308  		return nil
   309  	}
   310  
   311  	v2 := &v2corepb.Node{}
   312  	if c.NodeProto != nil {
   313  		v3, err := proto.Marshal(c.NodeProto)
   314  		if err != nil {
   315  			return fmt.Errorf("xds: proto.Marshal(%v): %v", c.NodeProto, err)
   316  		}
   317  		if err := proto.Unmarshal(v3, v2); err != nil {
   318  			return fmt.Errorf("xds: proto.Unmarshal(%v): %v", v3, err)
   319  		}
   320  	}
   321  	c.NodeProto = v2
   322  
   323  	// BuildVersion is deprecated, and is replaced by user_agent_name and
   324  	// user_agent_version. But the management servers are still using the old
   325  	// field, so we will keep both set.
   326  	v2.BuildVersion = gRPCVersion
   327  	v2.UserAgentName = gRPCUserAgentName
   328  	v2.UserAgentVersionType = &v2corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}
   329  	v2.ClientFeatures = append(v2.ClientFeatures, clientFeatureNoOverprovisioning)
   330  	return nil
   331  }