Hi,

It turns out my trainees were so quiet during exercises that I could
explore this a bit more.

I have come to the point where you don't need a backend declaration in
your VCL, as long as you have a director that will dynamically create
one. Once backend check was deferred to *after* vcl_init, it made very
easy to allow a director to become the default backend.

See the test d00007.vtc for a pure dynamic backend:

varnish v1 -vcl {
        import ${vmod_debug};

        sub vcl_init {
                new s1 = debug.dyn("${s1_addr}", "${s1_port}");
        }
} -start

See the test d00008.vtc for a director as the default:

varnish v1 -vcl+backend {
        import ${vmod_directors};

        # no need for `set bereq.backend = default;`
        sub vcl_init {
                new default = directors.round_robin();
                default.add_backend(s1);
                default.add_backend(s2);
        }
} -start

There are still caveats with the current implementation, and it's still not
enough to implement a new dns director. Dynamically created backend
won't receive events, which is not a problem *so far* since we can't pass
probes to VMODs yet. Instead of emitting per-backend code for events,
it could rely on backend_find() to fire events on both static and dynamic
backends.

Comments?

Cheers,
Dridi

On Mon, Apr 13, 2015 at 10:17 AM, Dridi Boukelmoune <[email protected]> wrote:
> Hi,
>
> It turned out you couldn't properly create backends dynamically, or at
> least remove them. Please find attached a patch set that fixes that,
> and adds a "director" capability to the debug vmod with an initial
> test case. This is still incomplete, and I want to push this further. For
> example I've created a Backend_added log record, but nothing for
> deletion.
>
> Before I do anything else, I'll wait for feedback :)
>
> Cheers,
> Dridi
>
> PS. today I'm doing training and the customer is blocking IRC
From f3dac3ac5aef87a60f350a81e2fb8705b1e08894 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Tue, 14 Apr 2015 11:27:49 +0200
Subject: [PATCH 4/7] Rename static function VCL_Load to vcl_load

---
 bin/varnishd/cache/cache_vcl.c | 4 ++--
 doc/graphviz/cache_req_fsm.dot | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/bin/varnishd/cache/cache_vcl.c b/bin/varnishd/cache/cache_vcl.c
index a5a7da4..8df784e 100644
--- a/bin/varnishd/cache/cache_vcl.c
+++ b/bin/varnishd/cache/cache_vcl.c
@@ -191,7 +191,7 @@ vcl_set_state(struct vcls *vcl, const char *state)
 }
 
 static int
-VCL_Load(struct cli *cli, const char *name, const char *fn, const char *state)
+vcl_load(struct cli *cli, const char *name, const char *fn, const char *state)
 {
 	struct vcls *vcl;
 	struct VCL_conf const *cnf;
@@ -345,7 +345,7 @@ ccf_config_load(struct cli *cli, const char * const *av, void *priv)
 
 	AZ(priv);
 	ASSERT_CLI();
-	if (VCL_Load(cli, av[2], av[3], av[4]))
+	if (vcl_load(cli, av[2], av[3], av[4]))
 		VCLI_SetResult(cli, CLIS_PARAM);
 	return;
 }
diff --git a/doc/graphviz/cache_req_fsm.dot b/doc/graphviz/cache_req_fsm.dot
index 5856984..4c29d0a 100644
--- a/doc/graphviz/cache_req_fsm.dot
+++ b/doc/graphviz/cache_req_fsm.dot
@@ -28,7 +28,7 @@ digraph cache_req_fsm {
 	init [
 	      shape=record
 	      label="
-	      {VCL_Load:|
+	      {vcl_load:|
 		      {vcl_init}|
 		      {<ok>ok|<fail>fail}}"
 	]
-- 
2.1.0

From 825aa8b3f61842afd13e6175d51d2cff1ed749b4 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Tue, 14 Apr 2015 15:22:40 +0200
Subject: [PATCH 5/7] Defer backend existence check after vcl_init{}

At this point you still need to declare a backend anyway.
---
 bin/varnishd/cache/cache_vcl.c     | 13 +++++++++++++
 lib/libvcc/vcc_compile.c           | 21 +++++++--------------
 lib/libvmod_debug/vmod_debug_dyn.c |  1 +
 3 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/bin/varnishd/cache/cache_vcl.c b/bin/varnishd/cache/cache_vcl.c
index 8df784e..f7a3f82 100644
--- a/bin/varnishd/cache/cache_vcl.c
+++ b/bin/varnishd/cache/cache_vcl.c
@@ -257,6 +257,19 @@ vcl_load(struct cli *cli, const char *name, const char *fn, const char *state)
 		FREE_OBJ(vcl);
 		return (1);
 	}
+	if (vcl->conf->director[0] == NULL) {
+		assert(vcl->conf->ndirector == 1);
+		VCLI_Out(cli,
+		    "No backends or directors found in VCL program, "
+		    "at least one is necessary after vcl_init{}.");
+		/* XXX below is dirty copy/paste */
+		ctx.method = VCL_MET_FINI;
+		(void)vcl->conf->fini_func(&ctx);
+		AZ(vcl->conf->event_vcl(&ctx, VCL_EVENT_DISCARD));
+		(void)dlclose(vcl->dlh);
+		FREE_OBJ(vcl);
+		return (1);
+	}
 	vcl_set_state(vcl, state);
 	assert(hand == VCL_RET_OK);
 	VCLI_Out(cli, "Loaded \"%s\" as \"%s\"", fn , name);
diff --git a/lib/libvcc/vcc_compile.c b/lib/libvcc/vcc_compile.c
index f651ed7..c1a9299 100644
--- a/lib/libvcc/vcc_compile.c
+++ b/lib/libvcc/vcc_compile.c
@@ -664,22 +664,15 @@ vcc_CompileSource(const struct vcc *tl0, struct vsb *sb, struct source *sp)
 	if (tl->err)
 		return (vcc_DestroyTokenList(tl, NULL));
 
-	/* Check if we have any backends at all */
-	if (tl->ndirector == 1) {
-		VSB_printf(tl->sb,
-		    "No backends or directors found in VCL program, "
-		    "at least one is necessary.\n");
-		tl->err = 1;
-		return (vcc_DestroyTokenList(tl, NULL));
+	/* Configure the default director, if any at this point */
+	if (tl->ndirector > 1) {
+		ifp = New_IniFin(tl);
+		VSB_printf(ifp->ini,
+		    "\tVCL_conf.director[0] = VCL_conf.director[%d];",
+		    tl->defaultdir);
+		vcc_AddRef(tl, tl->t_defaultdir, SYM_BACKEND);
 	}
 
-	/* Configure the default director */
-	ifp = New_IniFin(tl);
-	VSB_printf(ifp->ini,
-	    "\tVCL_conf.director[0] = VCL_conf.director[%d];",
-	    tl->defaultdir);
-	vcc_AddRef(tl, tl->t_defaultdir, SYM_BACKEND);
-
 	/* Check for orphans */
 	if (vcc_CheckReferences(tl))
 		return (vcc_DestroyTokenList(tl, NULL));
diff --git a/lib/libvmod_debug/vmod_debug_dyn.c b/lib/libvmod_debug/vmod_debug_dyn.c
index 342ca5e..6d1a761 100644
--- a/lib/libvmod_debug/vmod_debug_dyn.c
+++ b/lib/libvmod_debug/vmod_debug_dyn.c
@@ -98,6 +98,7 @@ vmod_dyn__fini(struct vmod_debug_dyn **op)
 	CAST_OBJ_NOTNULL(o, *op, VMOD_DEBUG_DYN_MAGIC);
 	CHECK_OBJ_NOTNULL(&o->vrt, VRT_BACKEND_MAGIC);
 	AN(o->dir);
+	VRT_event_vbe(VCL_EVENT_COLD, o->dir, &o->vrt);
 	VRT_fini_vbe(&o->dir, &o->vrt);
 	AZ(o->dir);
 	free(o->addr);
-- 
2.1.0

From a5e57056607c8c7e3de17f280dd0d3f0494faa83 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Tue, 14 Apr 2015 16:09:38 +0200
Subject: [PATCH 6/7] VCL doesn't require static backends anymore

---
 bin/varnishd/cache/cache_backend.c | 20 ++++++++++++++++++++
 bin/varnishtest/tests/d00007.vtc   | 11 +----------
 include/vrt.h                      |  1 +
 lib/libvmod_debug/vmod_debug_dyn.c |  1 +
 4 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c
index 3ec17d7..35c9103 100644
--- a/bin/varnishd/cache/cache_backend.c
+++ b/bin/varnishd/cache/cache_backend.c
@@ -373,3 +373,23 @@ VRT_fini_vbe(struct director **dp, const struct vrt_backend *vrt)
 	free(d->vcl_name);
 	FREE_OBJ(d);
 }
+
+/*--------------------------------------------------------------------
+ * This function uses the specified director as the default one if relevant.
+ */
+
+void
+VRT_event_vdi(VRT_CTX, struct director *dir)
+{
+	ASSERT_CLI();
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC);
+
+	if (ctx->vcl->director[0] == NULL ||
+	    !strcmp("default", dir->vcl_name)) {
+		VSL(SLT_Debug, 0, "Registered director %s", dir->vcl_name);
+		ctx->vcl->director[0] = dir;
+	}
+
+	AN(ctx->vcl->director[0]);
+}
diff --git a/bin/varnishtest/tests/d00007.vtc b/bin/varnishtest/tests/d00007.vtc
index 4695514..250dcb3 100644
--- a/bin/varnishtest/tests/d00007.vtc
+++ b/bin/varnishtest/tests/d00007.vtc
@@ -8,25 +8,16 @@ server s1 {
 varnish v1 -vcl {
 	import ${vmod_debug};
 
-	backend dummy {
-		.host = "${bad_ip}";
-	}
-
 	sub vcl_init {
 		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
 	}
-
-	sub vcl_recv {
-		set req.backend_hint = s1.backend();
-	}
 } -start
 
 logexpect l1 -v v1 -g raw -d {
-        expect * 0 Backend_added "dummy vcl1.dummy"
         expect * 0 Backend_added "s1 vcl1.s1"
 } -start
 
-varnish v1 -expect MAIN.n_backend == 2
+varnish v1 -expect MAIN.n_backend == 1
 
 logexpect l1 -wait
 
diff --git a/include/vrt.h b/include/vrt.h
index b5442d8..a0fc083 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -238,6 +238,7 @@ void VRT_event_vbe(enum vcl_event_e, const struct director *,
     const struct vrt_backend *);
 #endif
 void VRT_fini_vbe(struct director **, const struct vrt_backend *);
+void VRT_event_vdi(VRT_CTX, struct director *dir);
 
 /* Suckaddr related */
 int VRT_VSA_GetPtr(const struct suckaddr *sua, const unsigned char ** dst);
diff --git a/lib/libvmod_debug/vmod_debug_dyn.c b/lib/libvmod_debug/vmod_debug_dyn.c
index 6d1a761..106b568 100644
--- a/lib/libvmod_debug/vmod_debug_dyn.c
+++ b/lib/libvmod_debug/vmod_debug_dyn.c
@@ -87,6 +87,7 @@ vmod_dyn__init(VRT_CTX, struct vmod_debug_dyn **op,
 		*op = o;
 
 	VRT_event_vbe(VCL_EVENT_WARM, o->dir, &o->vrt);
+	VRT_event_vdi(ctx, o->dir);
 }
 
 VCL_VOID
-- 
2.1.0

From f4598639bfe890231b3a8d87a82d29c735e2864f Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Tue, 14 Apr 2015 16:52:31 +0200
Subject: [PATCH 7/7] Built-in directors now register themselves

And can be the default director if named "default".
---
 bin/varnishtest/tests/d00008.vtc    | 31 +++++++++++++++++++++++++++++++
 lib/libvmod_directors/fall_back.c   |  2 +-
 lib/libvmod_directors/hash.c        |  2 +-
 lib/libvmod_directors/random.c      |  4 ++--
 lib/libvmod_directors/round_robin.c |  2 +-
 lib/libvmod_directors/vdir.c        |  5 +++--
 lib/libvmod_directors/vdir.h        |  4 ++--
 7 files changed, 41 insertions(+), 9 deletions(-)
 create mode 100644 bin/varnishtest/tests/d00008.vtc

diff --git a/bin/varnishtest/tests/d00008.vtc b/bin/varnishtest/tests/d00008.vtc
new file mode 100644
index 0000000..9419387
--- /dev/null
+++ b/bin/varnishtest/tests/d00008.vtc
@@ -0,0 +1,31 @@
+varnishtest "Test a director as a default backend"
+
+server s1 {
+	rxreq
+	txresp -hdr "backend: s1"
+} -start
+
+server s2 {
+	rxreq
+	txresp -hdr "backend: s2"
+} -start
+
+varnish v1 -vcl+backend {
+	import ${vmod_directors};
+
+	# no need for `set bereq.backend = default;`
+	sub vcl_init {
+		new default = directors.round_robin();
+		default.add_backend(s1);
+		default.add_backend(s2);
+	}
+} -start
+
+client c1 {
+	txreq -url "/foo1"
+	rxresp
+	expect resp.http.backend == "s1"
+	txreq -url "/foo2"
+	rxresp
+	expect resp.http.backend == "s2"
+} -run
diff --git a/lib/libvmod_directors/fall_back.c b/lib/libvmod_directors/fall_back.c
index 77ec45c..f4d81fb 100644
--- a/lib/libvmod_directors/fall_back.c
+++ b/lib/libvmod_directors/fall_back.c
@@ -91,7 +91,7 @@ vmod_fallback__init(VRT_CTX,
 	ALLOC_OBJ(rr, VMOD_DIRECTORS_FALLBACK_MAGIC);
 	AN(rr);
 	*rrp = rr;
-	vdir_new(&rr->vd, vcl_name, vmod_fallback_healthy,
+	vdir_new(ctx, &rr->vd, vcl_name, vmod_fallback_healthy,
 	    vmod_fallback_resolve, rr);
 }
 
diff --git a/lib/libvmod_directors/hash.c b/lib/libvmod_directors/hash.c
index c3def17..4d43309 100644
--- a/lib/libvmod_directors/hash.c
+++ b/lib/libvmod_directors/hash.c
@@ -64,7 +64,7 @@ vmod_hash__init(VRT_CTX, struct vmod_directors_hash **rrp,
 	rr->vbm = vbit_init(8);
 	AN(rr->vbm);
 	*rrp = rr;
-	vdir_new(&rr->vd, vcl_name, NULL, NULL, rr);
+	vdir_new(ctx, &rr->vd, vcl_name, NULL, NULL, rr);
 }
 
 VCL_VOID __match_proto__()
diff --git a/lib/libvmod_directors/random.c b/lib/libvmod_directors/random.c
index a0612f3..761025f 100644
--- a/lib/libvmod_directors/random.c
+++ b/lib/libvmod_directors/random.c
@@ -87,8 +87,8 @@ vmod_random__init(VRT_CTX, struct vmod_directors_random **rrp,
 	ALLOC_OBJ(rr, VMOD_DIRECTORS_RANDOM_MAGIC);
 	AN(rr);
 	*rrp = rr;
-	vdir_new(&rr->vd, vcl_name, vmod_random_healthy, vmod_random_resolve,
-	    rr);
+	vdir_new(ctx, &rr->vd, vcl_name, vmod_random_healthy,
+	    vmod_random_resolve, rr);
 }
 
 VCL_VOID __match_proto__()
diff --git a/lib/libvmod_directors/round_robin.c b/lib/libvmod_directors/round_robin.c
index be92545..49a8ad5 100644
--- a/lib/libvmod_directors/round_robin.c
+++ b/lib/libvmod_directors/round_robin.c
@@ -94,7 +94,7 @@ vmod_round_robin__init(VRT_CTX,
 	ALLOC_OBJ(rr, VMOD_DIRECTORS_ROUND_ROBIN_MAGIC);
 	AN(rr);
 	*rrp = rr;
-	vdir_new(&rr->vd, vcl_name, vmod_rr_healthy, vmod_rr_resolve, rr);
+	vdir_new(ctx, &rr->vd, vcl_name, vmod_rr_healthy, vmod_rr_resolve, rr);
 }
 
 VCL_VOID __match_proto__()
diff --git a/lib/libvmod_directors/vdir.c b/lib/libvmod_directors/vdir.c
index 938d6de..9ee900a 100644
--- a/lib/libvmod_directors/vdir.c
+++ b/lib/libvmod_directors/vdir.c
@@ -51,8 +51,8 @@ vdir_expand(struct vdir *vd, unsigned n)
 }
 
 void
-vdir_new(struct vdir **vdp, const char *vcl_name, vdi_healthy_f *healthy,
-    vdi_resolve_f *resolve, void *priv)
+vdir_new(VRT_CTX, struct vdir **vdp, const char *vcl_name,
+    vdi_healthy_f *healthy, vdi_resolve_f *resolve, void *priv)
 {
 	struct vdir *vd;
 
@@ -72,6 +72,7 @@ vdir_new(struct vdir **vdp, const char *vcl_name, vdi_healthy_f *healthy,
 	vd->dir->resolve = resolve;
 	vd->vbm = vbit_init(8);
 	AN(vd->vbm);
+	VRT_event_vdi(ctx, vd->dir);
 }
 
 void
diff --git a/lib/libvmod_directors/vdir.h b/lib/libvmod_directors/vdir.h
index 9214911..b46e16a 100644
--- a/lib/libvmod_directors/vdir.h
+++ b/lib/libvmod_directors/vdir.h
@@ -41,8 +41,8 @@ struct vdir {
 	struct vbitmap				*vbm;
 };
 
-void vdir_new(struct vdir **vdp, const char *vcl_name, vdi_healthy_f *healthy,
-    vdi_resolve_f *resolve, void *priv);
+void vdir_new(VRT_CTX, struct vdir **vdp, const char *vcl_name,
+    vdi_healthy_f *healthy, vdi_resolve_f *resolve, void *priv);
 void vdir_delete(struct vdir **vdp);
 void vdir_lock(struct vdir *vd);
 void vdir_unlock(struct vdir *vd);
-- 
2.1.0

_______________________________________________
varnish-dev mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to