Mailing List Archive

How to compare 'bereq.backend' and 'req.backend_hint' against a director/backend in Varnish 4.1
We are in upgrading from Varnish 3 to Varnish 4.1 and we have
experienced a problem when comparing 'bereq.backend' or
'req.backend_hint' to a director or a backend.

We created Varnish Test Cases to demonstrate this behavior.

In Varnish 3 this tests runs successfully:

------------------------------------------------------------------------------------------------------
varnishtest "Test backends and directors"

server s1 {
rxreq
txresp -status 200
} -start


varnish v1 -vcl {
backend b_1 {
.host = "${s1_addr}";
.port = "${s1_port}";
}

director d1 round-robin {
{ .backend = b_1; }
}

sub vcl_recv {
set req.backend = d1;
}

sub vcl_fetch {
if ( req.backend == d1 ) {
set beresp.http.X-Backend-Fetch = "d1";
}
}

sub vcl_deliver {
if ( req.backend == d1 ) {
set resp.http.X-Backend-Deliver = "d1";
}
}

} -start

client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.X-Backend-Fetch == "d1"
expect resp.http.X-Backend-Deliver == "d1"
} -run
------------------------------------------------------------------------------------------------------

In Varnish 4 the following adapted test:

------------------------------------------------------------------------------------------------------
varnishtest "Test backends and directors"

server s1 {
rxreq
txresp -status 200
} -start


varnish v1 -vcl {
import std;
import directors;
backend b1 {
.host = "${s1_addr}";
.port = "${s1_port}";
}

sub vcl_init {
new d1 = directors.round_robin();
d1.add_backend(b1);
}

sub vcl_recv {
set req.backend_hint = d1.backend();
}

sub vcl_backend_response {
if ( bereq.backend == d1 ) {
set beresp.http.X-Backend-Response = "d1";
}
}

sub vcl_deliver {
if ( req.backend_hint == d1 ) {
set resp.http.X-Backend-Deliver = "d1";
}
}

} -start

client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.X-Backend-Response == "d1"
expect resp.http.X-Backend-Deliver == "d1"
} -run
------------------------------------------------------------------------------------------------------

fails with this message:

**** v1 0.4 CLI RX| Message from VCC-compiler:\n
**** v1 0.4 CLI RX| Backend not found: 'd1'\n
**** v1 0.4 CLI RX| ('<vcl.inline>' Line 21 Pos 27)\n
**** v1 0.4 CLI RX| if ( bereq.backend == d1 ) {\n
**** v1 0.4 CLI RX| --------------------------##----\n

and when we comment out the 'vcl_backend_response' sub it fails with
this message:

**** v1 0.5 CLI RX| Message from VCC-compiler:\n
**** v1 0.5 CLI RX| Backend not found: 'd1'\n
**** v1 0.5 CLI RX| ('<vcl.inline>' Line 28 Pos 30)\n
**** v1 0.5 CLI RX| if ( req.backend_hint == d1 ) {\n
**** v1 0.5 CLI RX| -----------------------------##----\n


When we change this test to compare against the backend directly and not
against the director the test compiles

------------------------------------------------------------------------------------------------------
varnishtest "Test backends and directors"

server s1 {
rxreq
txresp -status 200
} -start


varnish v1 -vcl {
import std;
import directors;
backend b1 {
.host = "${s1_addr}";
.port = "${s1_port}";
}

sub vcl_init {
new d1 = directors.round_robin();
d1.add_backend(b1);
}

sub vcl_recv {
set req.backend_hint = d1.backend();
}

sub vcl_backend_response {
std.log("xxxxxxxx-vcl_backend_response: " + bereq.backend);
if ( bereq.backend == b1 ) {
set beresp.http.X-Backend-Response = "d1";
}
}

sub vcl_deliver {
std.log("xxxxxxxx-vcl_deliver: " + req.backend_hint);
if ( req.backend_hint == b1 ) {
set resp.http.X-Backend-Deliver = "d1";
}
}

} -start

client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.X-Backend-Response == "d1"
expect resp.http.X-Backend-Deliver == "d1"
} -run
------------------------------------------------------------------------------------------------------

The test also fails because the expectations of the client are not met:

** c1 1.0 === expect resp.http.X-Backend-Response == "d1"
---- c1 1.0 EXPECT resp.http.X-Backend-Response (<undef>) == "d1" failed

and we can see in the log that 'bereq.backend' and 'req.backend_hint'
are set to 'd1'

...
**** v1 1.0 vsl| 1002 VCL_call b BACKEND_RESPONSE
**** v1 1.0 vsl| 1002 VCL_Log b
xxxxxxxx-vcl_backend_response: d1
**** v1 1.0 vsl| 1002 VCL_return b deliver
...
**** v1 1.0 vsl| 1001 VCL_call c DELIVER
**** v1 1.0 vsl| 1001 VCL_Log c xxxxxxxx-vcl_deliver: d1
**** v1 1.0 vsl| 1001 VCL_return c deliver
...

The question is how to compare 'bereq.backend' and 'req.backend_hint'
properly against a director/backend.
Are we missing something or is this a bug?


Thanks,

Ronald


_______________________________________________
varnish-misc mailing list
varnish-misc@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-misc
Re: How to compare 'bereq.backend' and 'req.backend_hint' against a director/backend in Varnish 4.1 [ In reply to ]
On Thu, Dec 15, 2016 at 9:10 AM, Plöger, Ronald <ronald.ploeger@gmx.de> wrote:
> We are in upgrading from Varnish 3 to Varnish 4.1 and we have experienced a
> problem when comparing 'bereq.backend' or 'req.backend_hint' to a director
> or a backend.

Hi Ronald,

Nice to see some varnishtest usage! The main problem with your code is
that you are confusing directors with VMOD objects. Because the whole
thing is confusing, and we really need to come with good docs because
I can't keep on explaining it. We have bad docs [1] on the topic if you
are interested in the details, but since Varnish 4.0 the things that were
confusing in the code base have become visible to end-users...

> fails with this message:
>
> **** v1 0.4 CLI RX| Message from VCC-compiler:\n
> **** v1 0.4 CLI RX| Backend not found: 'd1'\n
> **** v1 0.4 CLI RX| ('<vcl.inline>' Line 21 Pos 27)\n
> **** v1 0.4 CLI RX| if ( bereq.backend == d1 ) {\n
> **** v1 0.4 CLI RX| --------------------------##----\n

The type system:

- b1 is a backend
- d1 is an object, not a backend
- d1.backend() is a director (and also a backend)
- req.backend_hint takes a director (or a backend)
- bereq.backend takes a backend (or a director)

Why did I distinguish between the last two? Because of how backend
resolution [1] works by default.

What you can do instead is this:

if ( bereq.backend == d1.backend() ) {
...
}

It will work depending on the semantics of the VMOD object. For
objects defined in VMOD directors, it should work with all of them
except the hash director. It appears to fail in Varnish 4.1.3 on my
system. Please check with the latest 4.1 and open a bug if that's
still the case. It works on the master branch, I haven't tried the 5.0
release.

> The question is how to compare 'bereq.backend' and 'req.backend_hint'
> properly against a director/backend.
> Are we missing something or is this a bug?

See above, probably a bit of both!

Also please note that you can avoid the comparisons altogether if it's
only about keeping track of backend selection. You should have seen in
your logs that req.backend_hint would give you the director "d1" and
bereq.backend would give you the selected backend "b1".

This test cases passes on both 4.1.3 and master:

varnishtest "Test backends and directors"

server s1 {
rxreq
txresp
} -start

server s2 {
rxreq
txresp
} -start

varnish v1 -vcl+backend {
import directors;

sub vcl_init {
new d1 = directors.round_robin();
d1.add_backend(s1);
d1.add_backend(s2);
}

sub vcl_recv {
set req.backend_hint = d1.backend();
}

sub vcl_backend_response {
set beresp.http.X-Backend-Response = beresp.backend;
}

sub vcl_deliver {
set resp.http.X-Backend-Deliver = req.backend_hint;
}
} -start

client c1 {
txreq -url "/foo"
rxresp
expect resp.status == 200
expect resp.http.X-Backend-Response == "s1"
expect resp.http.X-Backend-Deliver == "d1"

txreq -url "/bar"
rxresp
expect resp.status == 200
expect resp.http.X-Backend-Response == "s2"
expect resp.http.X-Backend-Deliver == "d1"
} -run

Cheers,
Dridi

Head of the Backends&Directors department

[1] https://www.varnish-cache.org/docs/4.1/reference/directors.html

_______________________________________________
varnish-misc mailing list
varnish-misc@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-misc
How to compare 'bereq.backend' and 'req.backend_hint' against a director/backend in Varnish 4.1 [ In reply to ]
Hi Dridi,

thank you for your quick answer.

> Nice to see some varnishtest usage!

We do love varnishtest :-)

> What you can do instead is this:
>
> if ( bereq.backend == d1.backend() ) {
> ...
> }

>
> It will work depending on the semantics of the VMOD object. For
> objects defined in VMOD directors, it should work with all of them
> except the hash director. It appears to fail in Varnish 4.1.3 on my
> system. Please check with the latest 4.1 and open a bug if that's
> still the case. It works on the master branch, I haven't tried the 5.0
> release.

We are testing against "varnishd (varnish-4.1.4 revision 4529ff7)" from
"https://repo.varnish-cache.org/ubuntu/" and I adapted the test to use
"d1.backend()"

------------------------------------------------------------------------------------------------------

varnishtest "Test backends and directors"

server s1 {
rxreq
txresp -status 200
} -start


varnish v1 -vcl {
import std;
import directors;
backend b1 {
.host = "${s1_addr}";
.port = "${s1_port}";
}

sub vcl_init {
new d1 = directors.round_robin();
d1.add_backend(b1);
}

sub vcl_recv {
set req.backend_hint = d1.backend();
}

sub vcl_backend_response {
std.log("xxxxxxxx-vcl_backend_response-bereq: " + bereq.backend);
std.log("xxxxxxxx-vcl_backend_response-beresp: " + beresp.backend);
if ( bereq.backend == d1.backend() ) {
set beresp.http.X-Backend-Response = "d1";
}
}

sub vcl_deliver {
std.log("xxxxxxxx-vcl_deliver: " + req.backend_hint);
if ( req.backend_hint == d1.backend() ) {
set resp.http.X-Backend-Deliver = "d1";
}
}

} -start

client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.X-Backend-Response == "d1"
expect resp.http.X-Backend-Deliver == "d1"
} -run
------------------------------------------------------------------------------------------------------

But this also does not compile:

**** v1 0.5 CLI RX| Message from VCC-compiler:\n
**** v1 0.5 CLI RX| Backend not found: 'd1.backend'\n
**** v1 0.5 CLI RX| ('<vcl.inline>' Line 22 Pos 27)\n
**** v1 0.5 CLI RX| if ( bereq.backend == d1.backend() ) {\n
**** v1 0.5 CLI RX| --------------------------##########------\n

So I am going to open a bug/issue here
"https://github.com/varnishcache/varnish-cache", right?


Thanks again and best regards,

Ronald



_______________________________________________
varnish-misc mailing list
varnish-misc@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-misc
Re: How to compare 'bereq.backend' and 'req.backend_hint' against a director/backend in Varnish 4.1 [ In reply to ]
> So I am going to open a bug/issue here
> "https://github.com/varnishcache/varnish-cache", right?

Yes please, and mention that it does work on the master branch. You
can quote me as @dridi on github.

I'd like to stress one more time that comparing bereq.backend to
d1.backend() is likely to always fail because in the backend context
you will should the resolved backend.

Cheers

_______________________________________________
varnish-misc mailing list
varnish-misc@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-misc
How to compare 'bereq.backend' and 'req.backend_hint' against a director/backend in Varnish 4.1 [ In reply to ]
Hi Dridi,

thanks for your comment.

> I'd like to stress one more time that comparing bereq.backend to
> d1.backend() is likely to always fail because in the backend context
> you will should the resolved backend.


From the log output for:

std.log("xxxxxxxx-vcl_backend_response-bereq: " + bereq.backend);
std.log("xxxxxxxx-vcl_backend_response-beresp: " + beresp.backend);
...
std.log("xxxxxxxx-vcl_deliver: " + req.backend_hint);


**** v1 1.0 vsl| 1002 VCL_Log b xxxxxxxx-vcl_backend_response-bereq: d1
**** v1 1.0 vsl| 1002 VCL_Log b xxxxxxxx-vcl_backend_response-beresp: b1
...
**** v1 1.0 vsl| 1001 VCL_Log c xxxxxxxx-vcl_deliver: d1

I got the impression that both "req.backend_hint" and "bereq.backend" hold the director (because they both output "d1") and that only "beresp.backend" holds the backend (because it outputs "b1").
Therefore I assumed that a comparison against "d1.backend()" would work for "req.backend_hint" and "bereq.backend" but not for "beresp.backend".

Best,
Ronald
Re: How to compare 'bereq.backend' and 'req.backend_hint' against a director/backend in Varnish 4.1 [ In reply to ]
> I got the impression that both "req.backend_hint" and "bereq.backend" hold
> the director (because they both output "d1") and that only "beresp.backend"
> holds the backend (because it outputs "b1").

You're right, I meant beresp.backend and confused it with bereq.backend
in my previous response. I somehow mixed up your usage of bereq.backend
and my own test case using beresp.backend...

> Therefore I assumed that a comparison against "d1.backend()" would work for
> "req.backend_hint" and "bereq.backend" but not for "beresp.backend".

That is correct!

Cheers

PS. I had to proof-read this one twice to avoid further confusion

_______________________________________________
varnish-misc mailing list
varnish-misc@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-misc