Commit 2b874fe7 authored by Geoff Simmons's avatar Geoff Simmons

Test dynamic creation of backends listening at Unix domain sockets.

parent 0f5b4350
varnishtest "Test dynamic backends listening at Unix domain sockets"
server s1 -listen "${tmpdir}/s1.sock" {
rxreq
txresp
} -start
varnish v1 -vcl {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${s1_sock}");
}
sub vcl_recv {
set req.backend_hint = s1.backend();
}
} -start
varnish v1 -expect MAIN.n_backend == 2
client c1 {
txreq
rxresp
expect resp.status == 200
} -run
varnish v1 -errvcl {path must be an absolute path} {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("");
}
}
varnish v1 -errvcl {path must be an absolute path} {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("s1.sock");
}
}
shell { rm -f ${tmpdir}/foo }
varnish v1 -errvcl {Cannot stat path} {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${tmpdir}/foo");
}
}
varnish v1 -errvcl {is not a socket} {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${tmpdir}");
}
}
varnishtest "Test dynamic UDS backends hot swap"
server s1 -listen "${tmpdir}/s1.sock" {
rxreq
expect req.url == "/foo"
txresp
} -start
server s2 -listen "${tmpdir}/s2.sock" {
rxreq
expect req.url == "/bar"
txresp
} -start
varnish v1 -vcl {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${s1_sock}");
}
sub vcl_recv {
if (req.method == "SWAP") {
s1.refresh(req.http.X-Path);
return (synth(200));
}
set req.backend_hint = s1.backend();
}
} -start
varnish v1 -expect MAIN.n_backend == 2
client c1 {
txreq -url "/foo"
rxresp
expect resp.status == 200
txreq -req "SWAP" -hdr "X-Path: ${s2_sock}"
rxresp
expect resp.status == 200
txreq -url "/bar"
rxresp
expect resp.status == 200
} -run
varnishtest "Test dynamic UDS backends hot swap while being used"
barrier b1 cond 2
barrier b2 cond 2
server s1 -listen "${tmpdir}/s1.sock" {
rxreq
expect req.url == "/foo"
barrier b1 sync
barrier b2 sync
txresp
} -start
server s2 -listen "${tmpdir}/s2.sock" {
rxreq
expect req.url == "/bar"
barrier b2 sync
txresp
} -start
varnish v1 -vcl {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${s1_sock}");
}
sub vcl_recv {
if (req.method == "SWAP") {
s1.refresh(req.http.X-Path);
return (synth(200));
}
set req.backend_hint = s1.backend();
}
} -start
varnish v1 -expect MAIN.n_backend == 2
client c1 {
txreq -url "/foo"
rxresp
expect resp.status == 200
} -start
client c2 {
barrier b1 sync
txreq -req "SWAP" -hdr "X-Path: ${s2_sock}"
rxresp
expect resp.status == 200
txreq -url "/bar"
rxresp
expect resp.status == 200
} -run
client c1 -wait
varnishtest "Test dynamic UDS backends hot swap during a pipe"
barrier b1 cond 2
barrier b2 cond 2
server s1 -listen "${tmpdir}/s1.sock" {
rxreq
expect req.url == "/foo"
barrier b1 sync
barrier b2 sync
txresp
} -start
server s2 -listen "${tmpdir}/s2.sock" {
rxreq
expect req.url == "/bar"
barrier b2 sync
txresp
} -start
varnish v1 -vcl {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${s1_sock}");
}
sub vcl_recv {
if (req.method == "SWAP") {
s1.refresh(req.http.X-Path);
return (synth(200));
}
set req.backend_hint = s1.backend();
return (pipe);
}
} -start
varnish v1 -expect MAIN.n_backend == 2
client c1 {
txreq -url "/foo"
rxresp
expect resp.status == 200
} -start
client c2 {
barrier b1 sync
txreq -req "SWAP" -hdr "X-Path: ${s2_sock}"
rxresp
expect resp.status == 200
txreq -url "/bar"
rxresp
expect resp.status == 200
} -run
client c1 -wait
varnishtest "Test dynamic UDS backend hot swap after it was picked by a bereq"
barrier b1 cond 2
server s1 -listen "${tmpdir}/s1.sock" {
} -start
server s2 -listen "${tmpdir}/s2.sock" {
rxreq
txresp
} -start
varnish v1 -vcl {
import std;
import debug;
import vtc;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${s1_sock}");
}
sub vcl_recv {
if (req.method == "SWAP") {
s1.refresh(req.http.X-Path);
return (synth(200));
}
}
sub vcl_backend_fetch {
set bereq.backend = s1.backend();
# hot swap should happen while we sleep
vtc.sleep(2s);
if (std.healthy(bereq.backend)) {
return(abandon);
} else {
set bereq.backend = s1.backend();
}
}
} -start
varnish v1 -expect MAIN.n_backend == 2
client c1 {
txreq
barrier b1 sync
rxresp
expect resp.status == 200
}
client c2 {
barrier b1 sync
delay 0.1
txreq -req "SWAP" -hdr "X-Path: ${s2_sock}"
rxresp
expect resp.status == 200
}
client c1 -start
client c2 -run
client c1 -wait
varnishtest "Test a dynamic UDS backend discard during a request"
barrier b1 cond 2
barrier b2 cond 2
server s1 -listen "${tmpdir}/s1.sock" {
rxreq
expect req.url == "/foo"
barrier b1 sync
barrier b2 sync
txresp
} -start
varnish v1 -arg "-p thread_pools=1" -vcl {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${s1_sock}");
}
sub vcl_recv {
set req.backend_hint = s1.backend();
}
} -start
client c1 {
txreq -url "/foo"
rxresp
expect resp.status == 200
} -start
varnish v1 -expect MAIN.n_backend == 2
server s2 -listen "${tmpdir}/s2.sock" {
rxreq
expect req.url == "/bar"
txresp
} -start
barrier b1 sync
varnish v1 -vcl {
import debug;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s2 = debug.dyn_uds("${s2_sock}");
}
sub vcl_recv {
set req.backend_hint = s2.backend();
}
}
varnish v1 -cli "vcl.discard vcl1"
barrier b2 sync
client c1 -wait
delay 2
varnish v1 -expect MAIN.n_backend == 4
varnish v1 -expect n_vcl_avail == 1
varnish v1 -expect n_vcl_discard == 1
client c1 {
txreq -url "/bar"
rxresp
expect resp.status == 200
} -run
varnish v1 -cli "vcl.list"
varnish v1 -expect n_vcl_avail == 1
varnishtest "Test a dynamic UDS backend hot swap after it was hinted to a req"
barrier b1 cond 2
server s1 -listen "${tmpdir}/s1.sock" {
} -start
server s2 -listen "${tmpdir}/s2.sock" {
rxreq
txresp
} -start
varnish v1 -vcl {
import std;
import debug;
import vtc;
backend dummy { .host = "${bad_ip}"; }
sub vcl_init {
new s1 = debug.dyn_uds("${s1_sock}");
}
sub vcl_recv {
if (req.method == "SWAP") {
s1.refresh(req.http.X-Path);
return (synth(200));
}
set req.backend_hint = s1.backend();
# hot swap should happen while we sleep
vtc.sleep(2s);
if (std.healthy(req.backend_hint)) {
return(synth(800));
} else {
set req.backend_hint = s1.backend();
}
}
} -start
varnish v1 -expect MAIN.n_backend == 2
client c1 {
txreq
barrier b1 sync
rxresp
expect resp.status == 200
}
client c2 {
barrier b1 sync
delay 0.1
txreq -req "SWAP" -hdr "X-Path: ${s2_sock}"
rxresp
expect resp.status == 200
}
client c1 -start
client c2 -run
client c1 -wait
varnish v1 -cli backend.list
......@@ -141,6 +141,19 @@ $Method VOID .refresh(STRING addr, STRING port)
Dynamically refresh & (always!) replace the backend by a new one.
$Object dyn_uds(STRING path)
Dynamically create a single-backend director listening at a Unix
domain socket, path must not be empty.
$Method BACKEND .backend()
Return the dynamic UDS backend.
$Method VOID .refresh(STRING path)
Dynamically refresh & (always!) replace the backend by a new UDS backend.
$Function VOID vcl_release_delay(DURATION)
Hold a reference to the VCL when it goes cold for the given delay.
......
......@@ -32,6 +32,10 @@
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include "cache/cache.h"
#include "cache/cache_director.h"
......@@ -47,6 +51,14 @@ struct xyzzy_debug_dyn {
struct director *dir;
};
struct xyzzy_debug_dyn_uds {
unsigned magic;
#define VMOD_DEBUG_UDS_MAGIC 0x6c7370e6
pthread_mutex_t mtx;
char *vcl_name;
struct director *dir;
};
static void
dyn_dir_init(VRT_CTX, struct xyzzy_debug_dyn *dyn,
VCL_STRING addr, VCL_STRING port)
......@@ -167,3 +179,105 @@ xyzzy_dyn_refresh(VRT_CTX, struct xyzzy_debug_dyn *dyn,
CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
dyn_dir_init(ctx, dyn, addr, port);
}
static int
dyn_uds_init(VRT_CTX, struct xyzzy_debug_dyn_uds *uds, VCL_STRING path)
{
struct director *dir, *dir2;
struct vrt_backend vrt;
struct stat st;
if (path == NULL) {
VRT_fail(ctx, "path is NULL");
return (-1);
}
if (*path != '/') {
VRT_fail(ctx, "path must be an absolute path: %s", path);
return (-1);
}
errno = 0;
if (stat(path, &st) != 0) {
VRT_fail(ctx, "Cannot stat path %s: %s", path, strerror(errno));
return (-1);
}
if (! S_ISSOCK(st.st_mode)) {
VRT_fail(ctx, "%s is not a socket", path);
return (-1);
}
INIT_OBJ(&vrt, VRT_BACKEND_MAGIC);
vrt.path = path;
vrt.vcl_name = uds->vcl_name;
vrt.hosthdr = "localhost";
vrt.ipv4_suckaddr = NULL;
vrt.ipv6_suckaddr = NULL;
if ((dir = VRT_new_backend(ctx, &vrt)) == NULL)
return (-1);
AZ(pthread_mutex_lock(&uds->mtx));
dir2 = uds->dir;
uds->dir = dir;
AZ(pthread_mutex_unlock(&uds->mtx));
if (dir2 != NULL)
VRT_delete_backend(ctx, &dir2);
return (0);
}
VCL_VOID v_matchproto_(td_debug_dyn_uds__init)
xyzzy_dyn_uds__init(VRT_CTX, struct xyzzy_debug_dyn_uds **udsp,
const char *vcl_name, VCL_STRING path)
{
struct xyzzy_debug_dyn_uds *uds;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(udsp);
AZ(*udsp);
AN(vcl_name);
ALLOC_OBJ(uds, VMOD_DEBUG_UDS_MAGIC);
AN(uds);
REPLACE(uds->vcl_name, vcl_name);
AZ(pthread_mutex_init(&uds->mtx, NULL));
if (dyn_uds_init(ctx, uds, path) != 0) {
free(uds->vcl_name);
AZ(pthread_mutex_destroy(&uds->mtx));
FREE_OBJ(uds);
return;
}
*udsp = uds;
}
VCL_VOID v_matchproto_(td_debug_dyn_uds__fini)
xyzzy_dyn_uds__fini(struct xyzzy_debug_dyn_uds **udsp)
{
struct xyzzy_debug_dyn_uds *uds;
if (udsp == NULL || *udsp == NULL)
return;
CHECK_OBJ(*udsp, VMOD_DEBUG_UDS_MAGIC);
uds = *udsp;
free(uds->vcl_name);
AZ(pthread_mutex_destroy(&uds->mtx));
FREE_OBJ(uds);
udsp = NULL;
}
VCL_BACKEND v_matchproto_(td_debug_dyn_uds_backend)
xyzzy_dyn_uds_backend(VRT_CTX, struct xyzzy_debug_dyn_uds *uds)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(uds, VMOD_DEBUG_UDS_MAGIC);
AN(uds->dir);
return (uds->dir);
}
VCL_VOID v_matchproto_(td_debug_dyn_uds_refresh)
xyzzy_dyn_uds_refresh(VRT_CTX, struct xyzzy_debug_dyn_uds *uds, VCL_STRING path)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(uds, VMOD_DEBUG_UDS_MAGIC);
(void) dyn_uds_init(ctx, uds, path);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment