[experimental-ims] 41c39c8 Add health control of backends from CLI
Geoff Simmons
geoff at varnish-cache.org
Mon Jan 9 21:52:28 CET 2012
commit 41c39c857907f3b26f8ce540863121b27288649c
Author: Tollef Fog Heen <tfheen at varnish-software.com>
Date: Thu Nov 3 13:03:51 2011 +0100
Add health control of backends from CLI
Make it possible to mark backends as sick or healthy by way of
backend.set_health $backendname (sick|healthy|auto)
diff --git a/bin/varnishd/cache_backend.c b/bin/varnishd/cache_backend.c
index 1a3ae5b..cad637b 100644
--- a/bin/varnishd/cache_backend.c
+++ b/bin/varnishd/cache_backend.c
@@ -256,7 +256,10 @@ vbe_Healthy(const struct vdi_simple *vs, const struct sess *sp)
backend = vs->backend;
CHECK_OBJ_NOTNULL(backend, BACKEND_MAGIC);
- if (!backend->healthy)
+ if (backend->admin_health == from_probe && !backend->healthy)
+ return (0);
+
+ if (backend->admin_health == sick)
return (0);
/* VRT/VCC sets threshold to UINT_MAX to mark that it's not
@@ -267,6 +270,9 @@ vbe_Healthy(const struct vdi_simple *vs, const struct sess *sp)
else
threshold = vs->vrt->saintmode_threshold;
+ if (backend->admin_health == healthy)
+ threshold = UINT_MAX;
+
/* Saintmode is disabled */
if (threshold == 0)
return (1);
diff --git a/bin/varnishd/cache_backend.h b/bin/varnishd/cache_backend.h
index 8937673..880c429 100644
--- a/bin/varnishd/cache_backend.h
+++ b/bin/varnishd/cache_backend.h
@@ -106,6 +106,12 @@ struct trouble {
* An instance of a backend from a VCL program.
*/
+enum health_status {
+ healthy,
+ sick,
+ from_probe
+};
+
struct backend {
unsigned magic;
#define BACKEND_MAGIC 0x64c4c7c6
@@ -130,6 +136,7 @@ struct backend {
struct vbp_target *probe;
unsigned healthy;
+ enum health_status admin_health;
VTAILQ_HEAD(, trouble) troublelist;
struct VSC_C_vbe *vsc;
diff --git a/bin/varnishd/cache_backend_cfg.c b/bin/varnishd/cache_backend_cfg.c
index a4f3285..8168be0 100644
--- a/bin/varnishd/cache_backend_cfg.c
+++ b/bin/varnishd/cache_backend_cfg.c
@@ -38,6 +38,7 @@
#include "cache.h"
#include "cache_backend.h"
+#include "vcli.h"
#include "vcli_priv.h"
#include "vrt.h"
@@ -229,6 +230,7 @@ VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb)
assert(b->ipv4 != NULL || b->ipv6 != NULL);
b->healthy = 1;
+ b->admin_health = from_probe;
VTAILQ_INSERT_TAIL(&backends, b, list);
VSC_C_main->n_backend++;
@@ -274,25 +276,151 @@ VRT_fini_dir(struct cli *cli, struct director *b)
/*--------------------------------------------------------------------*/
+static int
+backend_find(const char *matcher, struct backend **r, int n)
+{
+ struct backend *b;
+ char *vcl_name;
+ char *s;
+ char *match_ip = NULL;
+ char *match_port = NULL;
+ int found = 0;
+
+ s = strchr(matcher, '(');
+
+ if (s == NULL) {
+ /* Simple match, max one hit */
+ VTAILQ_FOREACH(b, &backends, list) {
+ CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+ if (strcmp(b->vcl_name, matcher) == 0) {
+ if (r && found < n)
+ r[found] = b;
+ found++;
+ }
+ }
+ return found;
+ }
+
+ vcl_name = strndup(matcher, s - matcher);
+ AN(vcl_name);
+ s++;
+ while (*s != ')') {
+ if (*s == ':') {
+ /* Port */
+ s++;
+ match_port = s;
+ if (!(s = strchr(match_port, ','))) {
+ s = strchr(match_port, ')');
+ }
+ XXXAN(s);
+ match_port = strndup(match_port, s - match_port);
+ AN(match_port);
+ if (*s == ',')
+ s++;
+ } else {
+ /* IP */
+ match_ip = s;
+ if (!(s = strchr(match_ip, ','))) {
+ s = strchr(match_ip, ')');
+ }
+ XXXAN(s);
+ match_ip = strndup(match_ip, s - match_ip);
+ AN(match_ip);
+ if (*s == ',')
+ s++;
+ }
+ }
+ VTAILQ_FOREACH(b, &backends, list) {
+ CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+ if (match_port && strcmp(b->port, match_port) != 0)
+ continue;
+ if (match_ip &&
+ (strcmp(b->ipv4_addr, match_ip) != 0) &&
+ (strcmp(b->ipv6_addr, match_ip) != 0))
+ continue;
+ if (strcmp(b->vcl_name, vcl_name) == 0) {
+ if (r && found < n)
+ r[found] = b;
+ found++;
+ }
+ }
+ return found;
+}
+
static void
-cli_debug_backend(struct cli *cli, const char * const *av, void *priv)
+cli_backend_list(struct cli *cli, const char * const *av, void *priv)
{
struct backend *b;
+ const char *ah;
(void)av;
(void)priv;
ASSERT_CLI();
+ VCLI_Out(cli, "%-30s %10s %15s %15s", "Backend name",
+ "Conns", "Probed healthy", "Admin health");
VTAILQ_FOREACH(b, &backends, list) {
CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
- VCLI_Out(cli, "%p %s %d %d\n",
- b, b->display_name,
- b->refcount, b->n_conn);
+ if (b->admin_health == from_probe) {
+ ah = "Auto";
+ } else if (b->admin_health == sick) {
+ ah = "Sick";
+ } else {
+ ah = "Healthy";
+ }
+ VCLI_Out(cli, "\n%-30s %10d %15s %15s",
+ b->display_name,
+ b->refcount,
+ (b ->healthy ? "Yes" : "No"),
+ ah);
+ }
+}
+
+static void
+cli_backend_set_health(struct cli *cli, const char * const *av, void *priv)
+{
+ struct backend **b;
+ enum health_status state;
+ int n;
+ const char *wstate;
+
+ (void)av;
+ (void)priv;
+ ASSERT_CLI();
+ wstate = av[3];
+ if (strcmp(wstate, "healthy") == 0) {
+ state = healthy;
+ } else if (strcmp(wstate, "sick") == 0) {
+ state = sick;
+ } else if (strcmp(wstate, "auto") == 0) {
+ state = from_probe;
+ } else {
+ VCLI_Out(cli, "Invalid state %s", wstate);
+ VCLI_SetResult(cli, CLIS_CANT);
+ return;
+ }
+ n = backend_find(av[2], NULL, 0);
+ if (n == 0) {
+ VCLI_Out(cli, "No matching backends");
+ VCLI_SetResult(cli, CLIS_CANT);
+ return;
+ }
+
+ b = calloc(n, sizeof(struct backend *));
+ AN(b);
+ n = backend_find(av[2], b, n);
+
+ VCLI_Out(cli, "Set state to %s for the following backends:", wstate);
+ for (int i = 0; i < n; i++) {
+ b[i]->admin_health = state;
+ VCLI_Out(cli, "\n\t%s", b[i]->display_name);
}
}
-static struct cli_proto debug_cmds[] = {
- { "debug.backend", "debug.backend",
- "\tExamine Backend internals\n", 0, 0, "d", cli_debug_backend },
+static struct cli_proto backend_cmds[] = {
+ { "backend.list", "backend.list",
+ "\tList all backends\n", 0, 0, "d", cli_backend_list },
+ { "backend.set_health", "backend.set_health matcher state",
+ "\tShow a backend\n", 2, 2, "d", cli_backend_set_health },
{ NULL }
};
@@ -303,5 +431,5 @@ VBE_Init(void)
{
Lck_New(&VBE_mtx, lck_vbe);
- CLI_AddFuncs(debug_cmds);
+ CLI_AddFuncs(backend_cmds);
}
diff --git a/bin/varnishtest/tests/c00048.vtc b/bin/varnishtest/tests/c00048.vtc
new file mode 100644
index 0000000..ed8671f
--- /dev/null
+++ b/bin/varnishtest/tests/c00048.vtc
@@ -0,0 +1,55 @@
+varnishtest "Forcing health of backends"
+
+server s1 -repeat 3 {
+ rxreq
+ txresp
+} -start
+
+varnish v1 -vcl {
+ backend s1 {
+ .host = "${s1_addr}";
+ .port = "${s1_port}";
+ .probe = {
+ .window = 8;
+ .initial = 7;
+ .threshold = 8;
+ .interval = 10s;
+ }
+ }
+
+ sub vcl_recv {
+ return(pass);
+ }
+
+} -start
+
+delay 1
+
+varnish v1 -cliok "backend.set_health s1 auto"
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+varnish v1 -cliok "backend.set_health s1 sick"
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 503
+} -run
+
+varnish v1 -cliok "backend.set_health s1 healthy"
+
+client c1 {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+varnish v1 -clierr 300 "backend.set_health s1 foo"
+varnish v1 -clierr 300 "backend.set_health s2 foo"
+varnish v1 -clierr 300 "backend.set_health s2 auto"
+
More information about the varnish-commit
mailing list