blob: 7dcefcfa0f647e7c0ea0ff92fbbe55f07b8732ab [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001/*
2 *
3 * Copyright 2017 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
19package grpc
20
21import (
22 "fmt"
23 "strings"
Andrea Campanella3614a922021-02-25 12:40:42 +010024 "sync"
25 "time"
khenaidooac637102019-01-14 15:44:34 -050026
Andrea Campanella3614a922021-02-25 12:40:42 +010027 "google.golang.org/grpc/balancer"
28 "google.golang.org/grpc/credentials"
khenaidooac637102019-01-14 15:44:34 -050029 "google.golang.org/grpc/grpclog"
30 "google.golang.org/grpc/internal/channelz"
Andrea Campanella3614a922021-02-25 12:40:42 +010031 "google.golang.org/grpc/internal/grpcsync"
khenaidooac637102019-01-14 15:44:34 -050032 "google.golang.org/grpc/resolver"
Andrea Campanella3614a922021-02-25 12:40:42 +010033 "google.golang.org/grpc/serviceconfig"
khenaidooac637102019-01-14 15:44:34 -050034)
35
36// ccResolverWrapper is a wrapper on top of cc for resolvers.
37// It implements resolver.ClientConnection interface.
38type ccResolverWrapper struct {
Andrea Campanella3614a922021-02-25 12:40:42 +010039 cc *ClientConn
40 resolverMu sync.Mutex
41 resolver resolver.Resolver
42 done *grpcsync.Event
43 curState resolver.State
44
45 pollingMu sync.Mutex
46 polling chan struct{}
khenaidooac637102019-01-14 15:44:34 -050047}
48
49// split2 returns the values from strings.SplitN(s, sep, 2).
Stephane Barbarie260a5632019-02-26 16:12:49 -050050// If sep is not found, it returns ("", "", false) instead.
khenaidooac637102019-01-14 15:44:34 -050051func split2(s, sep string) (string, string, bool) {
52 spl := strings.SplitN(s, sep, 2)
53 if len(spl) < 2 {
54 return "", "", false
55 }
56 return spl[0], spl[1], true
57}
58
59// parseTarget splits target into a struct containing scheme, authority and
60// endpoint.
61//
62// If target is not a valid scheme://authority/endpoint, it returns {Endpoint:
63// target}.
64func parseTarget(target string) (ret resolver.Target) {
65 var ok bool
66 ret.Scheme, ret.Endpoint, ok = split2(target, "://")
67 if !ok {
68 return resolver.Target{Endpoint: target}
69 }
70 ret.Authority, ret.Endpoint, ok = split2(ret.Endpoint, "/")
71 if !ok {
72 return resolver.Target{Endpoint: target}
73 }
74 return ret
75}
76
Andrea Campanella3614a922021-02-25 12:40:42 +010077// newCCResolverWrapper uses the resolver.Builder stored in the ClientConn to
78// build a Resolver and returns a ccResolverWrapper object which wraps the
79// newly built resolver.
khenaidooac637102019-01-14 15:44:34 -050080func newCCResolverWrapper(cc *ClientConn) (*ccResolverWrapper, error) {
81 rb := cc.dopts.resolverBuilder
82 if rb == nil {
83 return nil, fmt.Errorf("could not get resolver for scheme: %q", cc.parsedTarget.Scheme)
84 }
85
86 ccr := &ccResolverWrapper{
Andrea Campanella3614a922021-02-25 12:40:42 +010087 cc: cc,
88 done: grpcsync.NewEvent(),
89 }
90
91 var credsClone credentials.TransportCredentials
92 if creds := cc.dopts.copts.TransportCredentials; creds != nil {
93 credsClone = creds.Clone()
94 }
95 rbo := resolver.BuildOption{
96 DisableServiceConfig: cc.dopts.disableServiceConfig,
97 DialCreds: credsClone,
98 CredsBundle: cc.dopts.copts.CredsBundle,
99 Dialer: cc.dopts.copts.Dialer,
khenaidooac637102019-01-14 15:44:34 -0500100 }
101
102 var err error
Andrea Campanella3614a922021-02-25 12:40:42 +0100103 // We need to hold the lock here while we assign to the ccr.resolver field
104 // to guard against a data race caused by the following code path,
105 // rb.Build-->ccr.ReportError-->ccr.poll-->ccr.resolveNow, would end up
106 // accessing ccr.resolver which is being assigned here.
107 ccr.resolverMu.Lock()
108 ccr.resolver, err = rb.Build(cc.parsedTarget, ccr, rbo)
khenaidooac637102019-01-14 15:44:34 -0500109 if err != nil {
110 return nil, err
111 }
Andrea Campanella3614a922021-02-25 12:40:42 +0100112 ccr.resolverMu.Unlock()
khenaidooac637102019-01-14 15:44:34 -0500113 return ccr, nil
114}
115
116func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOption) {
Andrea Campanella3614a922021-02-25 12:40:42 +0100117 ccr.resolverMu.Lock()
118 if !ccr.done.HasFired() {
119 ccr.resolver.ResolveNow(o)
120 }
121 ccr.resolverMu.Unlock()
khenaidooac637102019-01-14 15:44:34 -0500122}
123
124func (ccr *ccResolverWrapper) close() {
Andrea Campanella3614a922021-02-25 12:40:42 +0100125 ccr.resolverMu.Lock()
khenaidooac637102019-01-14 15:44:34 -0500126 ccr.resolver.Close()
Andrea Campanella3614a922021-02-25 12:40:42 +0100127 ccr.done.Fire()
128 ccr.resolverMu.Unlock()
khenaidooac637102019-01-14 15:44:34 -0500129}
130
Andrea Campanella3614a922021-02-25 12:40:42 +0100131// poll begins or ends asynchronous polling of the resolver based on whether
132// err is ErrBadResolverState.
133func (ccr *ccResolverWrapper) poll(err error) {
134 ccr.pollingMu.Lock()
135 defer ccr.pollingMu.Unlock()
136 if err != balancer.ErrBadResolverState {
137 // stop polling
138 if ccr.polling != nil {
139 close(ccr.polling)
140 ccr.polling = nil
141 }
142 return
143 }
144 if ccr.polling != nil {
145 // already polling
146 return
147 }
148 p := make(chan struct{})
149 ccr.polling = p
150 go func() {
151 for i := 0; ; i++ {
152 ccr.resolveNow(resolver.ResolveNowOption{})
153 t := time.NewTimer(ccr.cc.dopts.resolveNowBackoff(i))
154 select {
155 case <-p:
156 t.Stop()
157 return
158 case <-ccr.done.Done():
159 // Resolver has been closed.
160 t.Stop()
161 return
162 case <-t.C:
163 select {
164 case <-p:
165 return
166 default:
167 }
168 // Timer expired; re-resolve.
169 }
170 }
171 }()
Scott Baker8461e152019-10-01 14:44:30 -0700172}
173
174func (ccr *ccResolverWrapper) UpdateState(s resolver.State) {
Andrea Campanella3614a922021-02-25 12:40:42 +0100175 if ccr.done.HasFired() {
khenaidooac637102019-01-14 15:44:34 -0500176 return
Scott Baker8461e152019-10-01 14:44:30 -0700177 }
178 grpclog.Infof("ccResolverWrapper: sending update to cc: %v", s)
179 if channelz.IsOn() {
180 ccr.addChannelzTraceEvent(s)
181 }
Scott Baker8461e152019-10-01 14:44:30 -0700182 ccr.curState = s
Andrea Campanella3614a922021-02-25 12:40:42 +0100183 ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil))
184}
185
186func (ccr *ccResolverWrapper) ReportError(err error) {
187 if ccr.done.HasFired() {
188 return
189 }
190 grpclog.Warningf("ccResolverWrapper: reporting error to cc: %v", err)
191 if channelz.IsOn() {
192 channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{
193 Desc: fmt.Sprintf("Resolver reported error: %v", err),
194 Severity: channelz.CtWarning,
195 })
196 }
197 ccr.poll(ccr.cc.updateResolverState(resolver.State{}, err))
Scott Baker8461e152019-10-01 14:44:30 -0700198}
199
200// NewAddress is called by the resolver implementation to send addresses to gRPC.
201func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) {
Andrea Campanella3614a922021-02-25 12:40:42 +0100202 if ccr.done.HasFired() {
Scott Baker8461e152019-10-01 14:44:30 -0700203 return
khenaidooac637102019-01-14 15:44:34 -0500204 }
205 grpclog.Infof("ccResolverWrapper: sending new addresses to cc: %v", addrs)
206 if channelz.IsOn() {
Scott Baker8461e152019-10-01 14:44:30 -0700207 ccr.addChannelzTraceEvent(resolver.State{Addresses: addrs, ServiceConfig: ccr.curState.ServiceConfig})
khenaidooac637102019-01-14 15:44:34 -0500208 }
Scott Baker8461e152019-10-01 14:44:30 -0700209 ccr.curState.Addresses = addrs
Andrea Campanella3614a922021-02-25 12:40:42 +0100210 ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil))
khenaidooac637102019-01-14 15:44:34 -0500211}
212
Scott Baker8461e152019-10-01 14:44:30 -0700213// NewServiceConfig is called by the resolver implementation to send service
khenaidooac637102019-01-14 15:44:34 -0500214// configs to gRPC.
215func (ccr *ccResolverWrapper) NewServiceConfig(sc string) {
Andrea Campanella3614a922021-02-25 12:40:42 +0100216 if ccr.done.HasFired() {
khenaidooac637102019-01-14 15:44:34 -0500217 return
khenaidooac637102019-01-14 15:44:34 -0500218 }
219 grpclog.Infof("ccResolverWrapper: got new service config: %v", sc)
Andrea Campanella3614a922021-02-25 12:40:42 +0100220 scpr := parseServiceConfig(sc)
221 if scpr.Err != nil {
222 grpclog.Warningf("ccResolverWrapper: error parsing service config: %v", scpr.Err)
223 if channelz.IsOn() {
224 channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{
225 Desc: fmt.Sprintf("Error parsing service config: %v", scpr.Err),
226 Severity: channelz.CtWarning,
227 })
228 }
229 ccr.poll(balancer.ErrBadResolverState)
Scott Baker8461e152019-10-01 14:44:30 -0700230 return
231 }
232 if channelz.IsOn() {
Andrea Campanella3614a922021-02-25 12:40:42 +0100233 ccr.addChannelzTraceEvent(resolver.State{Addresses: ccr.curState.Addresses, ServiceConfig: scpr})
Scott Baker8461e152019-10-01 14:44:30 -0700234 }
Andrea Campanella3614a922021-02-25 12:40:42 +0100235 ccr.curState.ServiceConfig = scpr
236 ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil))
237}
238
239func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.ParseResult {
240 return parseServiceConfig(scJSON)
khenaidooac637102019-01-14 15:44:34 -0500241}
242
Scott Baker8461e152019-10-01 14:44:30 -0700243func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) {
244 var updates []string
Andrea Campanella3614a922021-02-25 12:40:42 +0100245 var oldSC, newSC *ServiceConfig
246 var oldOK, newOK bool
247 if ccr.curState.ServiceConfig != nil {
248 oldSC, oldOK = ccr.curState.ServiceConfig.Config.(*ServiceConfig)
249 }
250 if s.ServiceConfig != nil {
251 newSC, newOK = s.ServiceConfig.Config.(*ServiceConfig)
252 }
Scott Baker8461e152019-10-01 14:44:30 -0700253 if oldOK != newOK || (oldOK && newOK && oldSC.rawJSONString != newSC.rawJSONString) {
254 updates = append(updates, "service config updated")
khenaidooac637102019-01-14 15:44:34 -0500255 }
Scott Baker8461e152019-10-01 14:44:30 -0700256 if len(ccr.curState.Addresses) > 0 && len(s.Addresses) == 0 {
257 updates = append(updates, "resolver returned an empty address list")
258 } else if len(ccr.curState.Addresses) == 0 && len(s.Addresses) > 0 {
259 updates = append(updates, "resolver returned new addresses")
260 }
261 channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{
262 Desc: fmt.Sprintf("Resolver state updated: %+v (%v)", s, strings.Join(updates, "; ")),
263 Severity: channelz.CtINFO,
264 })
khenaidooac637102019-01-14 15:44:34 -0500265}