[master] 2b874fe Test dynamic creation of backends listening at Unix domain sockets.
Geoff Simmons
geoff at uplex.de
Mon Mar 12 09:45:10 UTC 2018
commit 2b874fe7e19fcddc9f69a29187191a4b1cb6d557
Author: Geoff Simmons <geoff at uplex.de>
Date: Mon Feb 19 03:13:35 2018 +0100
Test dynamic creation of backends listening at Unix domain sockets.
diff --git a/bin/varnishtest/tests/d00032.vtc b/bin/varnishtest/tests/d00032.vtc
new file mode 100644
index 0000000..5e30767
--- /dev/null
+++ b/bin/varnishtest/tests/d00032.vtc
@@ -0,0 +1,70 @@
+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}");
+ }
+}
diff --git a/bin/varnishtest/tests/d00033.vtc b/bin/varnishtest/tests/d00033.vtc
new file mode 100644
index 0000000..1d837ab
--- /dev/null
+++ b/bin/varnishtest/tests/d00033.vtc
@@ -0,0 +1,47 @@
+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
diff --git a/bin/varnishtest/tests/d00034.vtc b/bin/varnishtest/tests/d00034.vtc
new file mode 100644
index 0000000..314673f
--- /dev/null
+++ b/bin/varnishtest/tests/d00034.vtc
@@ -0,0 +1,58 @@
+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
diff --git a/bin/varnishtest/tests/d00035.vtc b/bin/varnishtest/tests/d00035.vtc
new file mode 100644
index 0000000..e47c670
--- /dev/null
+++ b/bin/varnishtest/tests/d00035.vtc
@@ -0,0 +1,59 @@
+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
diff --git a/bin/varnishtest/tests/d00036.vtc b/bin/varnishtest/tests/d00036.vtc
new file mode 100644
index 0000000..3b739c7
--- /dev/null
+++ b/bin/varnishtest/tests/d00036.vtc
@@ -0,0 +1,62 @@
+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
diff --git a/bin/varnishtest/tests/d00037.vtc b/bin/varnishtest/tests/d00037.vtc
new file mode 100644
index 0000000..51c6e8f
--- /dev/null
+++ b/bin/varnishtest/tests/d00037.vtc
@@ -0,0 +1,76 @@
+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
diff --git a/bin/varnishtest/tests/d00038.vtc b/bin/varnishtest/tests/d00038.vtc
new file mode 100644
index 0000000..1b8b704
--- /dev/null
+++ b/bin/varnishtest/tests/d00038.vtc
@@ -0,0 +1,61 @@
+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
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 5e1ac0c..20f75ec 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -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.
diff --git a/lib/libvmod_debug/vmod_debug_dyn.c b/lib/libvmod_debug/vmod_debug_dyn.c
index ebd7330..17b0da2 100644
--- a/lib/libvmod_debug/vmod_debug_dyn.c
+++ b/lib/libvmod_debug/vmod_debug_dyn.c
@@ -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);
+}
More information about the varnish-commit
mailing list