Dynamic backend switching using nbsrv with Host header

Hi
I am using haproxy 2.4.7, and I would like to dynamically route to the correct backend, if the backend has available servers.
I struggle to find the correct syntax using nbsrv().

The error I am getting is:

# haproxy -c -f /etc/haproxy/haproxy.cfg
[NOTICE]   (31364) : haproxy version is 2.4.7-b5e51a5
[NOTICE]   (31364) : path to executable is /sbin/haproxy
[ALERT]    (31364) : parsing [/etc/haproxy/haproxy.cfg:18] : error detected while parsing switching rule : missing comma after fetch keyword 'nbsrv' in ACL expression 'nbsrv(%[req.hdr(host)])'.
[ALERT]    (31364) : Error(s) found in configuration file : /etc/haproxy/haproxy.cfg
[ALERT]    (31364) : Fatal errors found in configuration.

The error missing comma kind of doesn’t make sense to me.

How can this be done?
Here is my example config:

global
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    log         /dev/log local0 debug
    user        haproxy
    group       haproxy
    daemon
    default-path config

defaults
    timeout connect         10s
    timeout client          1m
    timeout server          1m

frontend EXT_WEB
    bind 10.11.12.13:80
    mode http
    use_backend %[req.hdr(host)]   if { hdr(host) -i -f acls/ishost_applications.acl } { nbsrv(%[req.hdr(host)]) gt 0 }
}

backend app01.test.net
    mode http
    server app01.test.net 10.11.12.101:80

backend app02.test.net
    mode http
    server app02.test.net 10.11.12.102:80

The acl file has the following contents:

# cat acls/ishost_applications.acl
app01.test.net
app02.test.net

Many thanks
Toni

All of the following variations failed with an error:

acl ishost_app  hdr(host) -i -f acls/ishost_applications.acl
http-request set-var(txn.hdr_host) hdr(host)

use_backend %[req.hdr(host)]  if ishost_app { nbsrv(hdr(host)) gt 0 }
use_backend %[req.hdr(host)]  if ishost_app { nbsrv(req.hdr(host)) gt 0 }
use_backend %[req.hdr(host)]  if ishost_app { nbsrv(%[req.hdr(host)]) gt 0 }
use_backend %[req.hdr(host)]  if ishost_app { nbsrv(var(req.hdr(host))) gt 0 }
use_backend %[req.hdr(host)]  if ishost_app { nbsrv(%[var(req.hdr(host))]) gt 0 }

use_backend %[req.hdr(host)]  if ishost_app { nbsrv(var(txn.hdr_host)) gt 0 }
use_backend %[req.hdr(host)]  if ishost_app { nbsrv(%[var(txn.hdr_host)]) gt 0 }
use_backend %[req.hdr(host)]  if ishost_app { nbsrv(%[txn.hdr_host]) gt 0 }
use_backend %[req.hdr(host)]  if ishost_app { nbsrv(txn.hdr_host) gt 0 }

After all, is nbsrv() even capable of dealing with fetches or variables, or does it only work with plain, static strings?

Any comments appreciated.
Thanks

Did you discover any solution to this problem? I struggled about this just a few days ago, since the docs state:

nbsrv
Takes an input value of type string, interprets it as a backend name and
returns the number of usable servers in that backend. Can be used in places
where we want to look up a backend from a dynamic name, like a result of a
map lookup.

This was excatly what I was trying to do, but as in your examples, no way of passing in a variable/fetch etc. was parsed correctly.

Unfortunately, I have not yet discovered a solution.
I will try to ask the question in the Slack space.

When dealing with dynamic values, you want to use the nbsrv converter and not the sample fetch.
The nbsrv sample fetch arguments must be backend names known at config check time.

ie:

use_backend %[hdr(host)] if { hdr(host),nbsrv gt 0 }

1 Like

Many thanks jerome!
I tested it and it works.