|
19 | 19 | package rls
|
20 | 20 |
|
21 | 21 | import (
|
22 |
| - "sync" |
23 |
| - |
24 |
| - "google.golang.org/grpc" |
25 | 22 | "google.golang.org/grpc/balancer"
|
26 | 23 | "google.golang.org/grpc/grpclog"
|
27 |
| - "google.golang.org/grpc/internal/grpcsync" |
28 | 24 | )
|
29 | 25 |
|
30 | 26 | var (
|
31 | 27 | _ balancer.Balancer = (*rlsBalancer)(nil)
|
32 | 28 |
|
33 |
| - // For overriding in tests. |
34 |
| - newRLSClientFunc = newRLSClient |
35 |
| - logger = grpclog.Component("rls") |
| 29 | + logger = grpclog.Component("rls") |
36 | 30 | )
|
37 | 31 |
|
38 | 32 | // rlsBalancer implements the RLS LB policy.
|
39 |
| -type rlsBalancer struct { |
40 |
| - done *grpcsync.Event |
41 |
| - cc balancer.ClientConn |
42 |
| - opts balancer.BuildOptions |
43 |
| - |
44 |
| - // Mutex protects all the state maintained by the LB policy. |
45 |
| - // TODO(easwars): Once we add the cache, we will also have another lock for |
46 |
| - // the cache alone. |
47 |
| - mu sync.Mutex |
48 |
| - lbCfg *lbConfig // Most recently received service config. |
49 |
| - rlsCC *grpc.ClientConn // ClientConn to the RLS server. |
50 |
| - rlsC *rlsClient // RLS client wrapper. |
51 |
| - |
52 |
| - ccUpdateCh chan *balancer.ClientConnState |
53 |
| -} |
54 |
| - |
55 |
| -// run is a long running goroutine which handles all the updates that the |
56 |
| -// balancer wishes to handle. The appropriate updateHandler will push the update |
57 |
| -// on to a channel that this goroutine will select on, thereby the handling of |
58 |
| -// the update will happen asynchronously. |
59 |
| -func (lb *rlsBalancer) run() { |
60 |
| - for { |
61 |
| - // TODO(easwars): Handle other updates like subConn state changes, RLS |
62 |
| - // responses from the server etc. |
63 |
| - select { |
64 |
| - case u := <-lb.ccUpdateCh: |
65 |
| - lb.handleClientConnUpdate(u) |
66 |
| - case <-lb.done.Done(): |
67 |
| - return |
68 |
| - } |
69 |
| - } |
70 |
| -} |
71 |
| - |
72 |
| -// handleClientConnUpdate handles updates to the service config. |
73 |
| -// If the RLS server name or the RLS RPC timeout changes, it updates the control |
74 |
| -// channel accordingly. |
75 |
| -// TODO(easwars): Handle updates to other fields in the service config. |
76 |
| -func (lb *rlsBalancer) handleClientConnUpdate(ccs *balancer.ClientConnState) { |
77 |
| - logger.Infof("rls: service config: %+v", ccs.BalancerConfig) |
78 |
| - lb.mu.Lock() |
79 |
| - defer lb.mu.Unlock() |
80 |
| - |
81 |
| - if lb.done.HasFired() { |
82 |
| - logger.Warning("rls: received service config after balancer close") |
83 |
| - return |
84 |
| - } |
85 |
| - |
86 |
| - newCfg := ccs.BalancerConfig.(*lbConfig) |
87 |
| - if lb.lbCfg.Equal(newCfg) { |
88 |
| - logger.Info("rls: new service config matches existing config") |
89 |
| - return |
90 |
| - } |
91 |
| - |
92 |
| - lb.updateControlChannel(newCfg) |
93 |
| - lb.lbCfg = newCfg |
94 |
| -} |
| 33 | +type rlsBalancer struct{} |
95 | 34 |
|
96 |
| -// UpdateClientConnState pushes the received ClientConnState update on the |
97 |
| -// update channel which will be processed asynchronously by the run goroutine. |
98 |
| -// Implements balancer.Balancer interface. |
99 | 35 | func (lb *rlsBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error {
|
100 |
| - select { |
101 |
| - case lb.ccUpdateCh <- &ccs: |
102 |
| - case <-lb.done.Done(): |
103 |
| - } |
| 36 | + logger.Fatal("rls: UpdateClientConnState is not yet unimplemented") |
104 | 37 | return nil
|
105 | 38 | }
|
106 | 39 |
|
107 |
| -// ResolverErr implements balancer.Balancer interface. |
108 | 40 | func (lb *rlsBalancer) ResolverError(error) {
|
109 |
| - // ResolverError is called by gRPC when the name resolver reports an error. |
110 |
| - // TODO(easwars): How do we handle this? |
111 | 41 | logger.Fatal("rls: ResolverError is not yet unimplemented")
|
112 | 42 | }
|
113 | 43 |
|
114 |
| -// UpdateSubConnState implements balancer.Balancer interface. |
115 | 44 | func (lb *rlsBalancer) UpdateSubConnState(_ balancer.SubConn, _ balancer.SubConnState) {
|
116 | 45 | logger.Fatal("rls: UpdateSubConnState is not yet implemented")
|
117 | 46 | }
|
118 | 47 |
|
119 |
| -// Cleans up the resources allocated by the LB policy including the clientConn |
120 |
| -// to the RLS server. |
121 |
| -// Implements balancer.Balancer. |
122 | 48 | func (lb *rlsBalancer) Close() {
|
123 |
| - lb.mu.Lock() |
124 |
| - defer lb.mu.Unlock() |
125 |
| - |
126 |
| - lb.done.Fire() |
127 |
| - if lb.rlsCC != nil { |
128 |
| - lb.rlsCC.Close() |
129 |
| - } |
| 49 | + logger.Fatal("rls: Close is not yet implemented") |
130 | 50 | }
|
131 | 51 |
|
132 | 52 | func (lb *rlsBalancer) ExitIdle() {
|
133 |
| - // TODO: are we 100% sure this should be a nop? |
134 |
| -} |
135 |
| - |
136 |
| -// updateControlChannel updates the RLS client if required. |
137 |
| -// Caller must hold lb.mu. |
138 |
| -func (lb *rlsBalancer) updateControlChannel(newCfg *lbConfig) { |
139 |
| - oldCfg := lb.lbCfg |
140 |
| - if newCfg.lookupService == oldCfg.lookupService && newCfg.lookupServiceTimeout == oldCfg.lookupServiceTimeout { |
141 |
| - return |
142 |
| - } |
143 |
| - |
144 |
| - // Use RPC timeout from new config, if different from existing one. |
145 |
| - timeout := oldCfg.lookupServiceTimeout |
146 |
| - if timeout != newCfg.lookupServiceTimeout { |
147 |
| - timeout = newCfg.lookupServiceTimeout |
148 |
| - } |
149 |
| - |
150 |
| - if newCfg.lookupService == oldCfg.lookupService { |
151 |
| - // This is the case where only the timeout has changed. We will continue |
152 |
| - // to use the existing clientConn. but will create a new rlsClient with |
153 |
| - // the new timeout. |
154 |
| - lb.rlsC = newRLSClientFunc(lb.rlsCC, lb.opts.Target.Endpoint, timeout) |
155 |
| - return |
156 |
| - } |
157 |
| - |
158 |
| - // This is the case where the RLS server name has changed. We need to create |
159 |
| - // a new clientConn and close the old one. |
160 |
| - var dopts []grpc.DialOption |
161 |
| - if dialer := lb.opts.Dialer; dialer != nil { |
162 |
| - dopts = append(dopts, grpc.WithContextDialer(dialer)) |
163 |
| - } |
164 |
| - dopts = append(dopts, dialCreds(lb.opts)) |
165 |
| - |
166 |
| - cc, err := grpc.Dial(newCfg.lookupService, dopts...) |
167 |
| - if err != nil { |
168 |
| - logger.Errorf("rls: dialRLS(%s, %v): %v", newCfg.lookupService, lb.opts, err) |
169 |
| - // An error from a non-blocking dial indicates something serious. We |
170 |
| - // should continue to use the old control channel if one exists, and |
171 |
| - // return so that the rest of the config updates can be processes. |
172 |
| - return |
173 |
| - } |
174 |
| - if lb.rlsCC != nil { |
175 |
| - lb.rlsCC.Close() |
176 |
| - } |
177 |
| - lb.rlsCC = cc |
178 |
| - lb.rlsC = newRLSClientFunc(cc, lb.opts.Target.Endpoint, timeout) |
179 |
| -} |
180 |
| - |
181 |
| -func dialCreds(opts balancer.BuildOptions) grpc.DialOption { |
182 |
| - // The control channel should use the same authority as that of the parent |
183 |
| - // channel. This ensures that the identify of the RLS server and that of the |
184 |
| - // backend is the same, so if the RLS config is injected by an attacker, it |
185 |
| - // cannot cause leakage of private information contained in headers set by |
186 |
| - // the application. |
187 |
| - server := opts.Target.Authority |
188 |
| - switch { |
189 |
| - case opts.DialCreds != nil: |
190 |
| - if err := opts.DialCreds.OverrideServerName(server); err != nil { |
191 |
| - logger.Warningf("rls: OverrideServerName(%s) = (%v), using Insecure", server, err) |
192 |
| - return grpc.WithInsecure() |
193 |
| - } |
194 |
| - return grpc.WithTransportCredentials(opts.DialCreds) |
195 |
| - case opts.CredsBundle != nil: |
196 |
| - return grpc.WithTransportCredentials(opts.CredsBundle.TransportCredentials()) |
197 |
| - default: |
198 |
| - logger.Warning("rls: no credentials available, using Insecure") |
199 |
| - return grpc.WithInsecure() |
200 |
| - } |
| 53 | + logger.Fatal("rls: ExitIdle is not yet implemented") |
201 | 54 | }
|
0 commit comments