gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/xdsclient/controller/controller.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  // Package controller contains implementation to connect to the control plane.
    19  // Including starting the ClientConn, starting the xDS stream, and
    20  // sending/receiving messages.
    21  //
    22  // All the messages are parsed by the resource package (e.g.
    23  // UnmarshalListener()) and sent to the Pubsub watchers.
    24  package controller
    25  
    26  import (
    27  	"context"
    28  	"errors"
    29  	"fmt"
    30  	"sync"
    31  	"time"
    32  
    33  	grpc "gitee.com/ks-custle/core-gm/grpc"
    34  	"gitee.com/ks-custle/core-gm/grpc/internal/backoff"
    35  	"gitee.com/ks-custle/core-gm/grpc/internal/buffer"
    36  	"gitee.com/ks-custle/core-gm/grpc/internal/grpclog"
    37  	"gitee.com/ks-custle/core-gm/grpc/keepalive"
    38  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/bootstrap"
    39  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/controller/version"
    40  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/pubsub"
    41  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource"
    42  )
    43  
    44  // Controller manages the connection and stream to the control plane.
    45  //
    46  // It keeps track of what resources are being watched, and send new requests
    47  // when new watches are added.
    48  //
    49  // It takes a pubsub (as an interface) as input. When a response is received,
    50  // it's parsed, and the updates are sent to the pubsub.
    51  type Controller struct {
    52  	config          *bootstrap.ServerConfig
    53  	updateHandler   pubsub.UpdateHandler
    54  	updateValidator xdsresource.UpdateValidatorFunc
    55  	logger          *grpclog.PrefixLogger
    56  
    57  	cc               *grpc.ClientConn // Connection to the management server.
    58  	vClient          version.VersionedClient
    59  	stopRunGoroutine context.CancelFunc
    60  
    61  	backoff  func(int) time.Duration
    62  	streamCh chan grpc.ClientStream
    63  	sendCh   *buffer.Unbounded
    64  
    65  	mu sync.Mutex
    66  	// Message specific watch infos, protected by the above mutex. These are
    67  	// written to, after successfully reading from the update channel, and are
    68  	// read from when recovering from a broken stream to resend the xDS
    69  	// messages. When the user of this client object cancels a watch call,
    70  	// these are set to nil. All accesses to the map protected and any value
    71  	// inside the map should be protected with the above mutex.
    72  	watchMap map[xdsresource.ResourceType]map[string]bool
    73  	// versionMap contains the version that was acked (the version in the ack
    74  	// request that was sent on wire). The key is rType, the value is the
    75  	// version string, becaues the versions for different resource types should
    76  	// be independent.
    77  	versionMap map[xdsresource.ResourceType]string
    78  	// nonceMap contains the nonce from the most recent received response.
    79  	nonceMap map[xdsresource.ResourceType]string
    80  
    81  	// Changes to map lrsClients and the lrsClient inside the map need to be
    82  	// protected by lrsMu.
    83  	//
    84  	// TODO: after LRS refactoring, each controller should only manage the LRS
    85  	// stream to its server. LRS streams to other servers should be managed by
    86  	// other controllers.
    87  	lrsMu      sync.Mutex
    88  	lrsClients map[string]*lrsClient
    89  }
    90  
    91  // New creates a new controller.
    92  func New(config *bootstrap.ServerConfig, updateHandler pubsub.UpdateHandler, validator xdsresource.UpdateValidatorFunc, logger *grpclog.PrefixLogger) (_ *Controller, retErr error) {
    93  	switch {
    94  	case config == nil:
    95  		return nil, errors.New("xds: no xds_server provided")
    96  	case config.ServerURI == "":
    97  		return nil, errors.New("xds: no xds_server name provided in options")
    98  	case config.Creds == nil:
    99  		return nil, errors.New("xds: no credentials provided in options")
   100  	case config.NodeProto == nil:
   101  		return nil, errors.New("xds: no node_proto provided in options")
   102  	}
   103  
   104  	dopts := []grpc.DialOption{
   105  		config.Creds,
   106  		grpc.WithKeepaliveParams(keepalive.ClientParameters{
   107  			Time:    5 * time.Minute,
   108  			Timeout: 20 * time.Second,
   109  		}),
   110  	}
   111  
   112  	ret := &Controller{
   113  		config:          config,
   114  		updateValidator: validator,
   115  		updateHandler:   updateHandler,
   116  
   117  		backoff:    backoff.DefaultExponential.Backoff, // TODO: should this be configurable?
   118  		streamCh:   make(chan grpc.ClientStream, 1),
   119  		sendCh:     buffer.NewUnbounded(),
   120  		watchMap:   make(map[xdsresource.ResourceType]map[string]bool),
   121  		versionMap: make(map[xdsresource.ResourceType]string),
   122  		nonceMap:   make(map[xdsresource.ResourceType]string),
   123  
   124  		lrsClients: make(map[string]*lrsClient),
   125  	}
   126  
   127  	defer func() {
   128  		if retErr != nil {
   129  			ret.Close()
   130  		}
   131  	}()
   132  
   133  	cc, err := grpc.Dial(config.ServerURI, dopts...)
   134  	if err != nil {
   135  		// An error from a non-blocking dial indicates something serious.
   136  		return nil, fmt.Errorf("xds: failed to dial control plane {%s}: %v", config.ServerURI, err)
   137  	}
   138  	ret.cc = cc
   139  
   140  	builder := version.GetAPIClientBuilder(config.TransportAPI)
   141  	if builder == nil {
   142  		return nil, fmt.Errorf("no client builder for xDS API version: %v", config.TransportAPI)
   143  	}
   144  	apiClient, err := builder(version.BuildOptions{NodeProto: config.NodeProto, Logger: logger})
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	ret.vClient = apiClient
   149  
   150  	ctx, cancel := context.WithCancel(context.Background())
   151  	ret.stopRunGoroutine = cancel
   152  	go ret.run(ctx)
   153  
   154  	return ret, nil
   155  }
   156  
   157  // Close closes the controller.
   158  func (t *Controller) Close() {
   159  	// Note that Close needs to check for nils even if some of them are always
   160  	// set in the constructor. This is because the constructor defers Close() in
   161  	// error cases, and the fields might not be set when the error happens.
   162  	if t.stopRunGoroutine != nil {
   163  		t.stopRunGoroutine()
   164  	}
   165  	if t.cc != nil {
   166  		t.cc.Close()
   167  	}
   168  }