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 }