From: Willy Tarreau Date: Sun, 16 May 2010 20:18:27 +0000 (+0200) Subject: [MINOR] acl: add srv_is_up() to check that a specific server is up or not X-Git-Tag: v1.4.6~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0b1cd94c8b3a5c8c088223f1b1c4d0a327b5147c;p=thirdparty%2Fhaproxy.git [MINOR] acl: add srv_is_up() to check that a specific server is up or not This ACL was missing in complex setups where the status of a remote site has to be considered in switching decisions. Until there, using a server's status in an ACL required to have a dedicated backend, which is a bit heavy when multiple servers have to be monitored. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 0871265597..096aac6d2d 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -6156,6 +6156,17 @@ src src_port Applies to the client's TCP source port. This has a very limited usage. +srv_is_up() +srv_is_up(/) + Returns true when the designated server is UP, and false when it is either + DOWN or in maintenance mode. If is omitted, then the server is + looked up in the current backend. The function takes no arguments since it + is used as a boolean. It is mainly used to take action based on an external + status reported via a health check (eg: a geographical site's availability). + Another possible use which is more of a hack consists in using dummy servers + as boolean variables that can be enabled or disabled from the CLI, so that + rules depending on those ACLs can be tweaked in realtime. + 7.5.2. Matching contents at Layer 4 ----------------------------------- diff --git a/include/types/acl.h b/include/types/acl.h index 831b4d105f..1fda0e467f 100644 --- a/include/types/acl.h +++ b/include/types/acl.h @@ -2,7 +2,7 @@ * include/types/acl.h * This file provides structures and types for ACLs. * - * Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu + * Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -304,6 +305,7 @@ struct acl_expr { union { /* optional argument of the subject (eg: header or cookie name) */ char *str; struct userlist *ul; + struct server *srv; } arg; int arg_len; /* optional argument length */ struct list patterns; /* list of acl_patterns */ diff --git a/src/acl.c b/src/acl.c index bdd12045c8..a4c61a0391 100644 --- a/src/acl.c +++ b/src/acl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -1428,6 +1429,53 @@ acl_find_targets(struct proxy *p) list_for_each_entry(acl, &p->acl, list) { list_for_each_entry(expr, &acl->expr, list) { + if (strcmp(expr->kw->kw, "srv_is_up") == 0) { + struct proxy *px; + struct server *srv; + char *pname, *sname; + + if (!expr->arg.str || !*expr->arg.str) { + Alert("proxy %s: acl %s %s(): missing server name.\n", + p->id, acl->name, expr->kw->kw); + cfgerr++; + continue; + } + + pname = expr->arg.str; + sname = strrchr(pname, '/'); + + if (sname) + *sname++ = '\0'; + else { + sname = pname; + pname = NULL; + } + + px = p; + if (pname) { + px = findproxy(pname, PR_CAP_BE); + if (!px) { + Alert("proxy %s: acl %s %s(): unable to find proxy '%s'.\n", + p->id, acl->name, expr->kw->kw, pname); + cfgerr++; + continue; + } + } + + srv = findserver(px, sname); + if (!srv) { + Alert("proxy %s: acl %s %s(): unable to find server '%s'.\n", + p->id, acl->name, expr->kw->kw, sname); + cfgerr++; + continue; + } + + free(expr->arg.str); + expr->arg_len = 0; + expr->arg.srv = srv; + continue; + } + if (strstr(expr->kw->kw, "http_auth") == expr->kw->kw) { if (!expr->arg.str || !*expr->arg.str) { diff --git a/src/backend.c b/src/backend.c index ffd3bcab54..6f1eefe679 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1232,6 +1232,24 @@ acl_fetch_nbsrv(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } +/* report in test->flags a success or failure depending on the designated + * server's state. There is no match function involved since there's no pattern. + */ +static int +acl_fetch_srv_is_up(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + struct server *srv = expr->arg.srv; + + test->flags = ACL_TEST_F_VOL_TEST; + if (!(srv->state & SRV_MAINTAIN) && + (!(srv->state & SRV_CHECKED) || (srv->state & SRV_RUNNING))) + test->flags |= ACL_TEST_F_SET_RES_PASS; + else + test->flags |= ACL_TEST_F_SET_RES_FAIL; + return 1; +} + /* set test->i to the number of enabled servers on the proxy */ static int acl_fetch_connslots(struct proxy *px, struct session *l4, void *l7, int dir, @@ -1410,6 +1428,7 @@ static struct acl_kw_list acl_kws = {{ },{ { "be_conn", acl_parse_int, acl_fetch_be_conn, acl_match_int, ACL_USE_NOTHING }, { "queue", acl_parse_int, acl_fetch_queue_size, acl_match_int, ACL_USE_NOTHING }, { "avg_queue", acl_parse_int, acl_fetch_avg_queue_size, acl_match_int, ACL_USE_NOTHING }, + { "srv_is_up", acl_parse_nothing, acl_fetch_srv_is_up, acl_match_nothing, ACL_USE_NOTHING }, { NULL, NULL, NULL, NULL }, }};