A proxy can be marked as disabled using the keyword with the same name.
The doc mentions that it won't process any traffic. However, this is not
really the case for backends as they may still be selected via switching
rules during stream processing.
In fact, currently access to disabled backends will be conducted up to
assign_server(). However, no eligible server is found at this stage,
resulting in a connection closure or an HTTP 503, which is expected. So
in the end, servers in disabled backends won't receive any traffic. But
this is only because post-parsing steps are not performed on such
backends. Thus, this can be considered as functional but only via
side-effects.
This patch clarifies the handling of disable backends, so that they are
never selected via switching rules. Now, process_switching_rules() will
ignore disable backends and continue rules evaluation.
As this is a behavior change, this patch is labelled as medium. The
documentation manuel for use_backend is updated accordingly.
used when no rule has matched. It generally is the dynamic backend which
will catch all undetermined requests.
+ If a backend used as default is disabled, no traffic will be redirected to
+ it.
+
Example :
use_backend dynamic if url_dyn
There may be as many "use_backend" rules as desired. All of these rules are
evaluated in their declaration order, and the first one which matches will
- assign the backend.
+ assign the backend. This is even the case if the backend is considered as
+ down. However, if a matching rule targets a disabled backend, it is ignored
+ instead and rules evaluation continue.
In the first form, the backend will be used if the condition is met. In the
second form, the backend will be used if the condition is not met. If no
- condition is valid, the backend defined with "default_backend" will be used.
- If no default backend is defined, either the servers in the same section are
- used (in case of a "listen" section) or, in case of a frontend, no server is
- used and a 503 service unavailable response is returned.
+ condition is valid, the backend defined with "default_backend" will be used
+ unless it is disabled. If no default backend is defined, either the servers
+ in the same section are used (in case of a "listen" section) or, in case of a
+ frontend, no server is used and a 503 service unavailable response is
+ returned.
Note that it is possible to switch from a TCP frontend to an HTTP backend. In
this case, either the frontend has already checked that the protocol is HTTP,
return be->srv_bck;
}
+/* Returns true if <be> backend can be used as target to a switching rules. */
+static inline int be_is_eligible(const struct proxy *be)
+{
+ /* A disabled backend cannot be selected for traffic. Note that STOPPED
+ * state is ignored as there is a risk of breaking requests during
+ * soft-stop.
+ */
+ return !(be->flags & PR_FL_DISABLED);
+}
+
/* set the time of last session on the backend */
static inline void be_set_sess_last(struct proxy *be)
{
frontend fe
bind "fd@${fe1S}"
use_backend %[req.hdr("x-target")] if { req.hdr("x-dyn") "1" }
+ use_backend be if { req.hdr("x-target") "be" }
frontend fe_default
bind "fd@${fe2S}"
use_backend %[req.hdr("x-target")] if { req.hdr("x-dyn") "1" }
+ use_backend be_disabled if { req.hdr("x-target") "be_disabled" }
use_backend be
default_backend be_default
backend be
http-request return status 200 hdr "x-be" %[be_name]
+ backend be_disabled
+ disabled
+ http-request return status 200 hdr "x-be" %[be_name]
+
backend be_default
http-request return status 200 hdr "x-be" %[be_name]
} -start
rxresp
expect resp.status == 200
expect resp.http.x-be == "be_default"
+
+ # Static rule on disabled backend -> continue to next rule
+ txreq -hdr "x-target: be_disabled"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-be == "be"
} -run
# Connect to listen proxy type
backend = rule->be.backend;
}
+ /* If backend is ineligible, continue rules processing. */
+ if (backend && !be_is_eligible(backend)) {
+ backend = NULL;
+ continue;
+ }
+
/* Break the loop at the first matching rule found. If
* the dynamic name resolution has fail, fallback will
* be performed on the default backend.
return 0;
}
- backend = fe->defbe.be ? fe->defbe.be : s->be;
+ /* Use default backend if possible or stay on the current proxy. */
+ if (fe->defbe.be && be_is_eligible(fe->defbe.be))
+ backend = fe->defbe.be;
+ else
+ backend = s->be;
}
if (!stream_set_backend(s, backend))