Skip to content

Commit bfa8d87

Browse files
committed
Ensure router reload on initial sync
Previously, the router wouldn't reload HAProxy after the initial sync if the last item of the initial list of any of the watched resources didn't reach the router to trigger a commit. One possible trigger for this condition is a route specifying a host already claimed by another namespace. The router could be left in its initial state until another commit-triggering event occurred (e.g. a watch event). This change ensures that the router will always reload after the initial sync.
1 parent 4e5c579 commit bfa8d87

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed

pkg/router/controller/controller.go

+14-13
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,17 @@ func (c *RouterController) HandleNamespaces() {
116116
c.lock.Lock()
117117
defer c.lock.Unlock()
118118

119+
glog.V(4).Infof("Updating watched namespaces: %v", namespaces)
120+
if err := c.Plugin.HandleNamespaces(namespaces); err != nil {
121+
utilruntime.HandleError(err)
122+
}
123+
119124
// Namespace filtering is assumed to be have been
120125
// performed so long as the plugin event handler is called
121126
// at least once.
122127
c.filteredByNamespace = true
123128
c.updateLastSyncProcessed()
124129

125-
glog.V(4).Infof("Updating watched namespaces: %v", namespaces)
126-
if err := c.Plugin.HandleNamespaces(namespaces); err != nil {
127-
utilruntime.HandleError(err)
128-
}
129130
return
130131
}
131132
utilruntime.HandleError(fmt.Errorf("unable to find namespaces for router: %v", err))
@@ -164,18 +165,18 @@ func (c *RouterController) HandleRoute() {
164165
c.lock.Lock()
165166
defer c.lock.Unlock()
166167

167-
// Change the local sync state within the lock to ensure that all
168-
// event handlers have the same view of sync state.
169-
c.routesListConsumed = c.RoutesListConsumed()
170-
c.updateLastSyncProcessed()
171-
172168
glog.V(4).Infof("Processing Route: %s -> %s", route.Name, route.Spec.To.Name)
173169
glog.V(4).Infof(" Alias: %s", route.Spec.Host)
174170
glog.V(4).Infof(" Event: %s", eventType)
175171

176172
if err := c.Plugin.HandleRoute(eventType, route); err != nil {
177173
utilruntime.HandleError(err)
178174
}
175+
176+
// Change the local sync state within the lock to ensure that all
177+
// event handlers have the same view of sync state.
178+
c.routesListConsumed = c.RoutesListConsumed()
179+
c.updateLastSyncProcessed()
179180
}
180181

181182
// HandleEndpoints handles a single Endpoints event and refreshes the router backend.
@@ -189,14 +190,14 @@ func (c *RouterController) HandleEndpoints() {
189190
c.lock.Lock()
190191
defer c.lock.Unlock()
191192

193+
if err := c.Plugin.HandleEndpoints(eventType, endpoints); err != nil {
194+
utilruntime.HandleError(err)
195+
}
196+
192197
// Change the local sync state within the lock to ensure that all
193198
// event handlers have the same view of sync state.
194199
c.endpointsListConsumed = c.EndpointsListConsumed()
195200
c.updateLastSyncProcessed()
196-
197-
if err := c.Plugin.HandleEndpoints(eventType, endpoints); err != nil {
198-
utilruntime.HandleError(err)
199-
}
200201
}
201202

202203
// updateLastSyncProcessed notifies the plugin if the most recent sync

pkg/router/template/router.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ type templateRouter struct {
9090
bindPortsAfterSync bool
9191
// whether the router state has been read from the api at least once
9292
syncedAtLeastOnce bool
93+
// whether a commit has been requested when skipCommit was true
94+
commitRequested bool
9395
}
9496

9597
// templateRouterCfg holds all configuration items required to initialize the template router
@@ -348,8 +350,10 @@ func (r *templateRouter) readState() error {
348350
func (r *templateRouter) Commit() {
349351
if r.skipCommit {
350352
glog.V(4).Infof("Skipping router commit until last sync has been processed")
353+
r.commitRequested = true
351354
} else {
352355
r.rateLimitedCommitFunction.Invoke(r.rateLimitedCommitFunction)
356+
r.commitRequested = false
353357
}
354358
}
355359

@@ -742,9 +746,13 @@ func (r *templateRouter) shouldWriteCerts(cfg *ServiceAliasConfig) bool {
742746
// SetSkipCommit indicates to the router whether requests to
743747
// commit/reload should be skipped.
744748
func (r *templateRouter) SetSkipCommit(skipCommit bool) {
745-
if r.skipCommit != skipCommit {
746-
glog.V(4).Infof("Updating skip commit to: %t", skipCommit)
747-
r.skipCommit = skipCommit
749+
if r.skipCommit == skipCommit {
750+
return
751+
}
752+
glog.V(4).Infof("Updating skip commit to: %t", skipCommit)
753+
r.skipCommit = skipCommit
754+
if r.skipCommit && r.commitRequested {
755+
r.Commit()
748756
}
749757
}
750758

test/integration/router_stress_test.go

+18-4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,17 @@ func stressRouter(t *testing.T, namespaceCount, routesPerNamespace, routerCount,
8585
t.Fatalf("unexpected error: %v", err)
8686
}
8787
routes = append(routes, route)
88+
89+
}
90+
// Create a final route that uses the same host as the
91+
// previous route to create a conflict. This will validate
92+
// whether a router still reloads if the last item in the
93+
// initial list is rejected.
94+
host := routes[len(routes)-1].Spec.Host
95+
routeProperties := createRouteProperties("invalid-service", host)
96+
_, err = oc.Routes(namespace.Name).Create(routeProperties)
97+
if err != nil {
98+
t.Fatalf("unexpected error: %v", err)
8899
}
89100
}
90101

@@ -105,9 +116,9 @@ func stressRouter(t *testing.T, namespaceCount, routesPerNamespace, routerCount,
105116
plugins = append(plugins, router)
106117
}
107118

108-
// Wait until the routers have processed all the routes. The test
109-
// runner is assumed enforce a timeout that ensures termination in
110-
// the event of a failure.
119+
// Wait until routers have processed all the routes. The test
120+
// runner is assumed to enforce a timeout that ensures termination
121+
// in the event of failure.
111122
expectedRouteCount := len(routes)
112123
for {
113124
routeCount := 0
@@ -126,7 +137,10 @@ func stressRouter(t *testing.T, namespaceCount, routesPerNamespace, routerCount,
126137
}
127138

128139
for _, reloadCount := range reloadCounts {
129-
if reloadCount > 1 {
140+
switch {
141+
case reloadCount == 0:
142+
t.Fatalf("One or more routers didn't reload")
143+
case reloadCount > 1:
130144
t.Fatalf("One or more routers reloaded more than once")
131145
}
132146
}

0 commit comments

Comments
 (0)