]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] acl: add srv_is_up() to check that a specific server is up or not
authorWilly Tarreau <w@1wt.eu>
Sun, 16 May 2010 20:18:27 +0000 (22:18 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 16 May 2010 20:18:27 +0000 (22:18 +0200)
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.

doc/configuration.txt
include/types/acl.h
src/acl.c
src/backend.c

index 08712655978f35d0ee86d1083cc2052c3cce2059..096aac6d2defc8d1a5c2e488bf187e631cd5eedc 100644 (file)
@@ -6156,6 +6156,17 @@ src <ip_address>
 src_port <integer>
   Applies to the client's TCP source port. This has a very limited usage.
 
+srv_is_up(<server>)
+srv_is_up(<backend>/<server>)
+  Returns true when the designated server is UP, and false when it is either
+  DOWN or in maintenance mode. If <backend> 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
 -----------------------------------
index 831b4d105f6c2e91a5572e386c3de8d3f29004b0..1fda0e467fdb9fbcd524fd34ac94b9c62a13334e 100644 (file)
@@ -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 <types/auth.h>
 #include <types/proxy.h>
+#include <types/server.h>
 #include <types/session.h>
 
 #include <ebmbtree.h>
@@ -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 */
index bdd12045c814146fefa97deef94b362119877aca..a4c61a039133d8128d985f45912b7132d7fe9b55 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -24,6 +24,7 @@
 #include <proto/acl.h>
 #include <proto/auth.h>
 #include <proto/log.h>
+#include <proto/proxy.h>
 
 #include <ebsttree.h>
 
@@ -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) {
index ffd3bcab543a84ed6686787fd29bbb96a69519a8..6f1eefe679afc13f244f78821fededcd94f778bf 100644 (file)
@@ -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 },
 }};