@@ -196,7 +196,7 @@ func (s *ServiceController) watchServices(serviceQueue *cache.DeltaFIFO) {
196
196
// Returns an error if processing the delta failed, along with a boolean
197
197
// indicator of whether the processing should be retried.
198
198
func (s * ServiceController ) processDelta (delta * cache.Delta ) (error , bool ) {
199
- service , ok := delta .Object .(* api.Service )
199
+ deltaService , ok := delta .Object .(* api.Service )
200
200
var namespacedName types.NamespacedName
201
201
var cachedService * cachedService
202
202
if ! ok {
@@ -211,70 +211,74 @@ func (s *ServiceController) processDelta(delta *cache.Delta) (error, bool) {
211
211
if ! ok {
212
212
return fmt .Errorf ("Service %s not in cache even though the watcher thought it was. Ignoring the deletion." , key ), notRetryable
213
213
}
214
- service = cachedService .lastState
215
- delta .Object = cachedService . lastState
216
- namespacedName = types.NamespacedName {Namespace : service .Namespace , Name : service .Name }
214
+ deltaService = cachedService .lastState
215
+ delta .Object = deltaService
216
+ namespacedName = types.NamespacedName {Namespace : deltaService .Namespace , Name : deltaService .Name }
217
217
} else {
218
- namespacedName .Namespace = service .Namespace
219
- namespacedName .Name = service .Name
218
+ namespacedName .Namespace = deltaService .Namespace
219
+ namespacedName .Name = deltaService .Name
220
220
cachedService = s .cache .getOrCreate (namespacedName .String ())
221
221
}
222
- glog .V (2 ).Infof ("Got new %s delta for service: %+v" , delta .Type , service )
222
+ glog .V (2 ).Infof ("Got new %s delta for service: %+v" , delta .Type , deltaService )
223
223
224
224
// Ensure that no other goroutine will interfere with our processing of the
225
225
// service.
226
226
cachedService .mu .Lock ()
227
227
defer cachedService .mu .Unlock ()
228
228
229
- // Update the cached service (used above for populating synthetic deletes)
230
- cachedService .lastState = service
231
-
232
- // TODO: Handle added, updated, and sync differently?
233
- switch delta .Type {
234
- case cache .Added :
235
- fallthrough
236
- case cache .Updated :
237
- fallthrough
238
- case cache .Sync :
239
- err , retry := s .createLoadBalancerIfNeeded (namespacedName , service , cachedService .appliedState )
240
- if err != nil {
241
- message := "Error creating load balancer"
242
- if retry {
243
- message += " (will retry): "
244
- } else {
245
- message += " (will not retry): "
246
- }
247
- message += err .Error ()
248
- s .eventRecorder .Event (service , "CreatingLoadBalancerFailed" , message )
249
- return err , retry
250
- }
251
- // Always update the cache upon success.
252
- // NOTE: Since we update the cached service if and only if we successfully
253
- // processed it, a cached service being nil implies that it hasn't yet
254
- // been successfully processed.
255
- cachedService .appliedState = service
256
- s .cache .set (namespacedName .String (), cachedService )
257
- case cache .Deleted :
229
+ // Get the most recent state of the service from the API directly rather than
230
+ // trusting the body of the delta. This avoids update re-ordering problems.
231
+ // TODO: Handle sync delta types differently rather than doing a get on every
232
+ // service every time we sync?
233
+ service , err := s .kubeClient .Services (namespacedName .Namespace ).Get (namespacedName .Name )
234
+ if err != nil && ! errors .IsNotFound (err ) {
235
+ glog .Warningf ("Failed to get most recent state of service %v from API (will retry): %v" , namespacedName , err )
236
+ return err , retryable
237
+ } else if errors .IsNotFound (err ) {
238
+ glog .V (2 ).Infof ("Service %v not found, ensuring load balancer is deleted" , namespacedName )
258
239
s .eventRecorder .Event (service , "DeletingLoadBalancer" , "Deleting load balancer" )
259
- err := s .balancer .EnsureTCPLoadBalancerDeleted (s .loadBalancerName (service ), s .zone .Region )
240
+ err := s .balancer .EnsureTCPLoadBalancerDeleted (s .loadBalancerName (deltaService ), s .zone .Region )
260
241
if err != nil {
261
242
message := "Error deleting load balancer (will retry): " + err .Error ()
262
243
s .eventRecorder .Event (service , "DeletingLoadBalancerFailed" , message )
263
244
return err , retryable
264
245
}
265
246
s .eventRecorder .Event (service , "DeletedLoadBalancer" , "Deleted load balancer" )
266
247
s .cache .delete (namespacedName .String ())
267
- default :
268
- glog .Errorf ("Unexpected delta type: %v" , delta .Type )
248
+ return nil , notRetryable
269
249
}
250
+
251
+ // Update the cached service (used above for populating synthetic deletes)
252
+ cachedService .lastState = service
253
+
254
+ err , retry := s .createLoadBalancerIfNeeded (namespacedName , service , cachedService .appliedState )
255
+ if err != nil {
256
+ message := "Error creating load balancer"
257
+ if retry {
258
+ message += " (will retry): "
259
+ } else {
260
+ message += " (will not retry): "
261
+ }
262
+ message += err .Error ()
263
+ s .eventRecorder .Event (service , "CreatingLoadBalancerFailed" , message )
264
+
265
+ return err , retry
266
+ }
267
+ // Always update the cache upon success.
268
+ // NOTE: Since we update the cached service if and only if we successfully
269
+ // processed it, a cached service being nil implies that it hasn't yet
270
+ // been successfully processed.
271
+ cachedService .appliedState = service
272
+ s .cache .set (namespacedName .String (), cachedService )
273
+
270
274
return nil , notRetryable
271
275
}
272
276
273
277
// Returns whatever error occurred along with a boolean indicator of whether it
274
278
// should be retried.
275
279
func (s * ServiceController ) createLoadBalancerIfNeeded (namespacedName types.NamespacedName , service , appliedState * api.Service ) (error , bool ) {
276
280
if appliedState != nil && ! needsUpdate (appliedState , service ) {
277
- glog .Infof ("LB already exists and doesn't need update for service %s" , namespacedName )
281
+ glog .Infof ("LB doesn't need update for service %s" , namespacedName )
278
282
return nil , notRetryable
279
283
}
280
284
0 commit comments