@@ -82,12 +82,6 @@ type peerProxyHandler struct {
82
82
finishedSync atomic.Bool
83
83
}
84
84
85
- type serviceableByResponse struct {
86
- locallyServiceable bool
87
- errorFetchingAddressFromLease bool
88
- peerEndpoints []string
89
- }
90
-
91
85
// responder implements rest.Responder for assisting a connector in writing objects or errors.
92
86
type responder struct {
93
87
w http.ResponseWriter
@@ -149,84 +143,97 @@ func (h *peerProxyHandler) WrapHandler(handler http.Handler) http.Handler {
149
143
gvr .Group = "core"
150
144
}
151
145
152
- // find servers that are capable of serving this request
153
- serviceableByResp , err := h .findServiceableByServers (gvr )
146
+ apiservers , err := h .findServiceableByServers (gvr )
154
147
if err != nil {
155
- // this means that resource is an aggregated API or a CR since it wasn't found in SV informer cache, pass as it is
156
- handler .ServeHTTP (w , r )
157
- return
158
- }
159
- // found the gvr locally, pass request to the next handler in local apiserver
160
- if serviceableByResp .locallyServiceable {
148
+ // resource wasn't found in SV informer cache which means that resource is an aggregated API
149
+ // or a CR. This situation is ok to be handled by local handler.
161
150
handler .ServeHTTP (w , r )
162
151
return
163
152
}
164
153
165
- gv := schema.GroupVersion {Group : gvr .Group , Version : gvr .Version }
166
- if serviceableByResp .errorFetchingAddressFromLease {
167
- klog .ErrorS (err , "error fetching ip and port of remote server while proxying" )
154
+ locallyServiceable , peerEndpoints , err := h .resolveServingLocation (apiservers )
155
+ if err != nil {
156
+ gv := schema.GroupVersion {Group : gvr .Group , Version : gvr .Version }
157
+ klog .ErrorS (err , "error finding serviceable-by apiservers for the requested resource" , "gvr" , gvr )
168
158
responsewriters .ErrorNegotiated (apierrors .NewServiceUnavailable ("Error getting ip and port info of the remote server while proxying" ), h .serializer , gv , w , r )
169
159
return
170
160
}
171
161
172
- // no apiservers were found that could serve the request, pass request to
173
- // next handler, that should eventually serve 404
174
-
162
+ // pass request to the next handler if found the gvr locally.
175
163
// TODO: maintain locally serviceable GVRs somewhere so that we dont have to
176
164
// consult the storageversion-informed map for those
177
- if len (serviceableByResp .peerEndpoints ) == 0 {
165
+ if locallyServiceable {
166
+ handler .ServeHTTP (w , r )
167
+ return
168
+ }
169
+
170
+ if len (peerEndpoints ) == 0 {
178
171
klog .Errorf ("gvr %v is not served by anything in this cluster" , gvr )
179
172
handler .ServeHTTP (w , r )
180
173
return
181
174
}
182
175
183
176
// otherwise, randomly select an apiserver and proxy request to it
184
- rand := rand .Intn (len (serviceableByResp . peerEndpoints ))
185
- destServerHostPort := serviceableByResp . peerEndpoints [rand ]
177
+ rand := rand .Intn (len (peerEndpoints ))
178
+ destServerHostPort := peerEndpoints [rand ]
186
179
h .proxyRequestToDestinationAPIServer (r , w , destServerHostPort )
187
-
188
180
})
189
181
}
190
182
191
- func (h * peerProxyHandler ) findServiceableByServers (gvr schema.GroupVersionResource ) (serviceableByResponse , error ) {
192
-
183
+ func (h * peerProxyHandler ) findServiceableByServers (gvr schema.GroupVersionResource ) (* sync.Map , error ) {
193
184
apiserversi , ok := h .svMap .Load (gvr )
194
-
195
- // no value found for the requested gvr in svMap
196
185
if ! ok || apiserversi == nil {
197
- return serviceableByResponse {} , fmt .Errorf ("no StorageVersions found for the GVR: %v" , gvr )
186
+ return nil , fmt .Errorf ("no storageVersions found for the GVR: %v" , gvr )
198
187
}
199
- apiservers := apiserversi .(* sync.Map )
200
- response := serviceableByResponse {}
188
+
189
+ apiservers , _ := apiserversi .(* sync.Map )
190
+ return apiservers , nil
191
+ }
192
+
193
+ func (h * peerProxyHandler ) resolveServingLocation (apiservers * sync.Map ) (bool , []string , error ) {
201
194
var peerServerEndpoints []string
195
+ var locallyServiceable bool
196
+ var respErr error
197
+
202
198
apiservers .Range (func (key , value interface {}) bool {
203
199
apiserverKey := key .(string )
204
200
if apiserverKey == h .serverId {
205
- response . locallyServiceable = true
201
+ locallyServiceable = true
206
202
// stop iteration
207
203
return false
208
204
}
209
205
210
- hostPort , err := h .reconciler . GetEndpoint (apiserverKey )
206
+ hostPort , err := h .hostportInfo (apiserverKey )
211
207
if err != nil {
212
- response .errorFetchingAddressFromLease = true
213
- klog .ErrorS (err , "failed to get peer ip from storage lease for server" , "serverID" , apiserverKey )
208
+ respErr = err
214
209
// continue with iteration
215
210
return true
216
211
}
217
- // check ip format
218
- _ , _ , err = net .SplitHostPort (hostPort )
219
- if err != nil {
220
- response .errorFetchingAddressFromLease = true
221
- klog .ErrorS (err , "invalid address found for server" , "serverID" , apiserverKey )
222
- return true
223
- }
212
+
224
213
peerServerEndpoints = append (peerServerEndpoints , hostPort )
225
214
return true
226
215
})
227
216
228
- response .peerEndpoints = peerServerEndpoints
229
- return response , nil
217
+ // reset err if there was atleast one valid peer server found.
218
+ if len (peerServerEndpoints ) > 0 {
219
+ respErr = nil
220
+ }
221
+
222
+ return locallyServiceable , peerServerEndpoints , respErr
223
+ }
224
+
225
+ func (h * peerProxyHandler ) hostportInfo (apiserverKey string ) (string , error ) {
226
+ hostport , err := h .reconciler .GetEndpoint (apiserverKey )
227
+ if err != nil {
228
+ return "" , err
229
+ }
230
+ // check ip format
231
+ _ , _ , err = net .SplitHostPort (hostport )
232
+ if err != nil {
233
+ return "" , err
234
+ }
235
+
236
+ return hostport , nil
230
237
}
231
238
232
239
func (h * peerProxyHandler ) proxyRequestToDestinationAPIServer (req * http.Request , rw http.ResponseWriter , host string ) {
@@ -248,13 +255,11 @@ func (h *peerProxyHandler) proxyRequestToDestinationAPIServer(req *http.Request,
248
255
defer cancelFn ()
249
256
250
257
proxyRoundTripper := transport .NewAuthProxyRoundTripper (user .GetName (), user .GetUID (), user .GetGroups (), user .GetExtra (), h .proxyTransport )
251
-
252
258
delegate := & epmetrics.ResponseWriterDelegator {ResponseWriter : rw }
253
259
w := responsewriter .WrapForHTTP1Or2 (delegate )
254
260
255
261
handler := proxy .NewUpgradeAwareHandler (location , proxyRoundTripper , true , false , & responder {w : w , ctx : req .Context ()})
256
262
handler .ServeHTTP (w , newReq )
257
- // Increment the count of proxied requests
258
263
metrics .IncPeerProxiedRequest (req .Context (), strconv .Itoa (delegate .Status ()))
259
264
}
260
265
@@ -280,11 +285,13 @@ func (h *peerProxyHandler) updateSV(oldObj interface{}, newObj interface{}) {
280
285
klog .Error ("Invalid StorageVersion provided to updateSV()" )
281
286
return
282
287
}
288
+
283
289
newSV , ok := newObj .(* v1alpha1.StorageVersion )
284
290
if ! ok {
285
291
klog .Error ("Invalid StorageVersion provided to updateSV()" )
286
292
return
287
293
}
294
+
288
295
h .updateSVMap (oldSV , newSV )
289
296
}
290
297
@@ -295,17 +302,17 @@ func (h *peerProxyHandler) deleteSV(obj interface{}) {
295
302
klog .Error ("Invalid StorageVersion provided to deleteSV()" )
296
303
return
297
304
}
305
+
298
306
h .updateSVMap (sv , nil )
299
307
}
300
308
301
309
// Delete old storageversion, add new storagversion
302
310
func (h * peerProxyHandler ) updateSVMap (oldSV * v1alpha1.StorageVersion , newSV * v1alpha1.StorageVersion ) {
303
311
if oldSV != nil {
304
- // delete old SV entries
305
312
h .deleteSVFromMap (oldSV )
306
313
}
314
+
307
315
if newSV != nil {
308
- // add new SV entries
309
316
h .addSVToMap (newSV )
310
317
}
311
318
}
0 commit comments