Skip to content

Commit 64229d2

Browse files
committed
fix: issue where canary overwrites default backend
Signed-off-by: Spazzy <brendankamp757@gmail.com>
1 parent dc999d8 commit 64229d2

File tree

6 files changed

+253
-29
lines changed

6 files changed

+253
-29
lines changed

rootfs/etc/nginx/lua/balancer.lua

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ local function get_implementation(backend)
7272
return implementation
7373
end
7474

75+
-- used to get the IP address of the upstream to set as the
76+
-- backends endpoint to route to
7577
local function resolve_external_names(original_backend)
7678
local backend = util.deepcopy(original_backend)
7779
local endpoints = {}
@@ -181,6 +183,7 @@ local function sync_backends()
181183
backends_last_synced_at = raw_backends_last_synced_at
182184
end
183185

186+
-- logic used to pick up if request should be routed to an alternative backend
184187
local function route_to_alternative_balancer(balancer)
185188
if balancer.is_affinitized(balancer) then
186189
-- If request is already affinitized to a primary balancer, keep the primary balancer.
@@ -218,7 +221,6 @@ local function route_to_alternative_balancer(balancer)
218221
"of backend: ", tostring(backend_name))
219222
return false
220223
end
221-
222224
local target_header = util.replace_special_char(traffic_shaping_policy.header,
223225
"-", "_")
224226
local header = ngx.var["http_" .. target_header]
@@ -278,14 +280,15 @@ local function get_balancer()
278280
local backend_name = ngx.var.proxy_upstream_name
279281

280282
local balancer = balancers[backend_name]
283+
281284
if not balancer then
282285
return nil
283286
end
284287

285-
if route_to_alternative_balancer(balancer) then
288+
--we should not overwrite balancer when it is the default backend
289+
if route_to_alternative_balancer(balancer) and not balancer.is_default_backend then
286290
local alternative_backend_name = balancer.alternative_backends[1]
287291
ngx.var.proxy_alternative_upstream_name = alternative_backend_name
288-
289292
balancer = balancers[alternative_backend_name]
290293
end
291294

@@ -318,6 +321,7 @@ end
318321

319322
function _M.rewrite()
320323
local balancer = get_balancer()
324+
321325
if not balancer then
322326
ngx.status = ngx.HTTP_SERVICE_UNAVAILABLE
323327
return ngx.exit(ngx.status)
@@ -344,6 +348,7 @@ function _M.balance()
344348
ngx_balancer.set_more_tries(1)
345349

346350
local ok, err = ngx_balancer.set_current_peer(peer)
351+
347352
if not ok then
348353
ngx.log(ngx.ERR, "error while setting current upstream peer ", peer,
349354
": ", err)
@@ -363,6 +368,16 @@ function _M.log()
363368
balancer:after_balance()
364369
end
365370

371+
--this is used to check if we are routing to the
372+
--default backend for sepcific error codes so that we do not overwrite it with
373+
--alternative routes
374+
--https://github.com/kubernetes/ingress-nginx/issues/9944
375+
function _M.is_default_backend()
376+
if ngx.ctx.balancer then
377+
ngx.ctx.balancer.is_default_backend = true
378+
end
379+
end
380+
366381
setmetatable(_M, {__index = {
367382
get_implementation = get_implementation,
368383
sync_backend = sync_backend,

rootfs/etc/nginx/template/nginx.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,10 @@ stream {
931931
rewrite (.*) / break;
932932

933933
proxy_pass http://upstream_balancer;
934+
access_by_lua_block {
935+
balancer.is_default_backend()
936+
}
937+
934938
log_by_lua_block {
935939
{{ if $enableMetrics }}
936940
monitor.call()

test/e2e/DEFAULT_BACKEND_IMAGE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
registry.k8s.io/ingress-nginx/nginx-errors:v20230505@sha256:3600dcd1bbd0d05959bb01af4b272714e94d22d24a64e91838e7183c80e53f7f

test/e2e/annotations/canary.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,54 @@ var _ = framework.DescribeAnnotation("canary-*", func() {
8686
NotContains(canaryService)
8787
})
8888

89+
// issue: https://github.com/kubernetes/ingress-nginx/issues/9944
90+
// canary routing should not overwrite custom errors
91+
ginkgo.It("should respond with a 401 status from the custom errors backend when canary responds with a 401",
92+
func() {
93+
host := "foo"
94+
annotations := map[string]string{
95+
"nginx.ingress.kubernetes.io/custom-http-errors": "401",
96+
"nginx.ingress.kubernetes.io/default-backend": framework.DefaultBackendService,
97+
}
98+
99+
f.NewDefaultBackendDeployment()
100+
101+
f.EnsureIngress(framework.NewSingleIngress(
102+
host,
103+
"/",
104+
host,
105+
f.Namespace,
106+
framework.HTTPBunService,
107+
80,
108+
annotations,
109+
))
110+
111+
f.WaitForNginxServer(host, func(server string) bool {
112+
return strings.Contains(server, "server_name foo")
113+
})
114+
115+
f.EnsureIngress(framework.NewSingleIngress(
116+
canaryService,
117+
"/",
118+
host,
119+
f.Namespace,
120+
canaryService,
121+
80,
122+
map[string]string{
123+
"nginx.ingress.kubernetes.io/canary": "true",
124+
"nginx.ingress.kubernetes.io/canary-by-header": "CanaryByHeader",
125+
},
126+
))
127+
128+
f.HTTPTestClient().
129+
GET("/status/401").
130+
WithHeader("Host", host).
131+
Expect().
132+
Status(http.StatusUnauthorized).
133+
Body().
134+
Contains("401")
135+
})
136+
89137
ginkgo.It("should return 404 status for requests to the canary if no matching ingress is found", func() {
90138
host := fooHost
91139

0 commit comments

Comments
 (0)