]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] implemented the 'monitor-uri' keyword.
authorWilly Tarreau <w@1wt.eu>
Sun, 9 Jul 2006 06:22:27 +0000 (08:22 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 9 Jul 2006 15:01:40 +0000 (17:01 +0200)
It is used to test haproxy's status with an HTTP request to which
it will reply with HTTP/1.0 200 OK.

ROADMAP
doc/haproxy-en.txt
doc/haproxy-fr.txt
include/types/proxy.h
src/cfgparse.c
src/proto_http.c

diff --git a/ROADMAP b/ROADMAP
index e529eb1fc74591d7861b65e1fc06be62d8b604d7..f5c638fff50b45d98761295bd4e07690ddd2b610 100644 (file)
--- a/ROADMAP
+++ b/ROADMAP
      srv->effective_maxconn =
           max(srv->maxconn * px->nbsess / px->maxconn, srv->minconn)
 
+1.2.15 :
+ + monitor-uri : specify an URI for which we will always return 'HTTP/1.0 200'
+   and never forward nor log it.
+
+ + option ssl-hello-chk : send SSLv3 client hello messages to check the servers
+
 1.3 :
  - remove unused STATTIME
 
@@ -75,7 +81,6 @@
 
  - clarify licence by adding a 'MODULE_LICENCE("GPL")' or something equivalent.
 
-
  - handle half-closed connections better (cli/srv would not distinguish
    DATA/SHUTR/SHUTW, it would be a session flag which would tell shutr/shutw).
    Check how it got changed in httpterm.
 
  - verify if it would be worth implementing an epoll_ctl_batch() for Linux
 
+ - balance LC/WLC (patch available)
+
+ - option minservers XXX : activates some backup servers when active servers
+   are insufficient
+
+ - monitor minservers XXX : monitor-net and monitor-uri could report a failure
+   when the number of active servers is below this threshold.
+
+ - option smtp-chk : use SMTP health checks (avoid logs if possible)
+
+ - new keyword 'check' : check http xxx, check smtp xxx, check ssl-hello
+
index 14554f2bad2df171e070a2eb1c918dabe54da8b8..ea7180784fd41526b697162dfd642d8c5d22c0b7 100644 (file)
@@ -494,6 +494,27 @@ Example :
        monitor-net 192.168.1.252/31   # L4 load-balancers on .252 and .253
 
 
+When the system executing the checks is located behind a proxy, the monitor-net
+keyword cannot be used because haproxy will always see the proxy's address. To
+overcome this limitation, version 1.2.15 brought the 'monitor-uri' keyword. It
+defines an URI which will not be forwarded nor logged, but for which haproxy
+will immediately send an "HTTP/1.0 200 OK" response. This makes it possible to
+check the validity of the reverse-proxy->haproxy chain with one request. It can
+be used in HTTPS checks in front of an stunnel -> haproxy combination for
+instance. Obviously, this keyword is only valid in HTTP mode, otherwise there
+is no notion of URI. Note that the method and HTTP versions are simply ignored.
+
+Example :
+---------
+
+    listen stunnel_backend :8080
+       mode http
+       balance roundrobin
+       server web1 192.168.1.10:80 check
+       server web2 192.168.1.11:80 check
+       monitor-uri /haproxy_test
+
+
 2.3) Limiting the number of simultaneous connections
 ----------------------------------------------------
 The 'maxconn' parameter allows a proxy to refuse connections above a certain
index dd02891de24958a020ff1501e5d9c39c761146a2..157028abee38c7be6e6200656d7ed0f96d09015b 100644 (file)
@@ -520,6 +520,28 @@ Exemple :
        monitor-net 192.168.1.252/31   # L4 load-balancers on .252 and .253
 
 
+Lorsque le système effectuant les tests est situé derrière un proxy, le mot-clé
+'monitor-net' n'est pas utilisable du fait que haproxy verra toujours la même
+adresse pour le proxy. Pour pallier à cette limitation, la version 1.2.15 a
+apporté le mot-clé 'monitor-uri'. Il définit une URI qui ne sera ni retransmise
+ni logée, mais pour laquelle haproxy retournera immédiatement une réponse
+"HTTP/1.0 200 OK". Cela rend possibles les tests de validité d'une chaîne
+reverse-proxy->haproxy en une requête HTTP. Cela peut être utilisé pour valider
+une combinaision de stunnel+haproxy à l'aide de tests HTTPS par exemple. Bien
+entendu, ce mot-clé n'est valide qu'en mode HTTP, sinon il n'y a pas de notion
+d'URI. Noter que la méthode et la version HTTP sont simplement ignorées.
+
+Exemple :
+---------
+
+    listen stunnel_backend :8080
+       mode http
+       balance roundrobin
+       server web1 192.168.1.10:80 check
+       server web2 192.168.1.11:80 check
+       monitor-uri /haproxy_test
+
+
 2.3) Limitation du nombre de connexions simultanées
 ---------------------------------------------------
 Le paramètre "maxconn" permet de fixer la limite acceptable en nombre de
index 50c16ecadb26cda146d4819f3ac55b6f04cc6975..7a262dab551ff89497677db983ef83d467acf134 100644 (file)
@@ -67,42 +67,44 @@ struct proxy {
        int state;                              /* proxy state */
        struct sockaddr_in dispatch_addr;       /* the default address to connect to */
        struct server *srv;                     /* known servers */
-       int srv_act, srv_bck;           /* # of running servers */
-       int tot_wact, tot_wbck;         /* total weights of active and backup servers */
+       int srv_act, srv_bck;                   /* # of running servers */
+       int tot_wact, tot_wbck;                 /* total weights of active and backup servers */
        struct server **srv_map;                /* the server map used to apply weights */
-       int srv_map_sz;                 /* the size of the effective server map */
-       int srv_rr_idx;                 /* next server to be elected in round robin mode */
+       int srv_map_sz;                         /* the size of the effective server map */
+       int srv_rr_idx;                         /* next server to be elected in round robin mode */
        char *cookie_name;                      /* name of the cookie to look for */
        int  cookie_len;                        /* strlen(cookie_name), computed only once */
-       char *appsession_name;          /* name of the cookie to look for */
+       char *appsession_name;                  /* name of the cookie to look for */
        int  appsession_name_len;               /* strlen(appsession_name), computed only once */
-       int  appsession_len;            /* length of the appsession cookie value to be used */
+       int  appsession_len;                    /* length of the appsession cookie value to be used */
        int  appsession_timeout;
        CHTbl htbl_proxy;                       /* Per Proxy hashtable */
        char *capture_name;                     /* beginning of the name of the cookie to capture */
-       int  capture_namelen;           /* length of the cookie name to match */
+       int  capture_namelen;                   /* length of the cookie name to match */
        int  capture_len;                       /* length of the string to be captured */
        struct uri_auth *uri_auth;              /* if non-NULL, the (list of) per-URI authentications */
-       int clitimeout;                 /* client I/O timeout (in milliseconds) */
-       int srvtimeout;                 /* server I/O timeout (in milliseconds) */
-       int contimeout;                 /* connect timeout (in milliseconds) */
+       char *monitor_uri;                      /* a special URI to which we respond with HTTP/200 OK */
+       int monitor_uri_len;                    /* length of the string above. 0 if unused */
+       int clitimeout;                         /* client I/O timeout (in milliseconds) */
+       int srvtimeout;                         /* server I/O timeout (in milliseconds) */
+       int contimeout;                         /* connect timeout (in milliseconds) */
        char *id;                               /* proxy id */
-       struct list pendconns;          /* pending connections with no server assigned yet */
-       int nbpend, nbpend_max;         /* number of pending connections with no server assigned yet */
-       int totpend;                    /* total number of pending connections on this instance (for stats) */
+       struct list pendconns;                  /* pending connections with no server assigned yet */
+       int nbpend, nbpend_max;                 /* number of pending connections with no server assigned yet */
+       int totpend;                            /* total number of pending connections on this instance (for stats) */
        unsigned int nbconn, nbconn_max;        /* # of active sessions */
-       unsigned int cum_conn;          /* cumulated number of processed sessions */
-       unsigned int maxconn;           /* max # of active sessions */
+       unsigned int cum_conn;                  /* cumulated number of processed sessions */
+       unsigned int maxconn;                   /* max # of active sessions */
        unsigned failed_conns, failed_resp;     /* failed connect() and responses */
-       unsigned failed_secu;           /* blocked responses because of security concerns */
+       unsigned failed_secu;                   /* blocked responses because of security concerns */
        int conn_retries;                       /* maximum number of connect retries */
-       int options;                    /* PR_O_REDISP, PR_O_TRANSP, ... */
+       int options;                            /* PR_O_REDISP, PR_O_TRANSP, ... */
        int mode;                               /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
-       struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */
+       struct sockaddr_in source_addr;         /* the address to which we want to bind for connect() */
        struct proxy *next;
-       struct sockaddr_in logsrv1, logsrv2; /* 2 syslog servers */
-       signed char logfac1, logfac2;   /* log facility for both servers. -1 = disabled */
-       int loglev1, loglev2;           /* log level for each server, 7 by default */
+       struct sockaddr_in logsrv1, logsrv2;    /* 2 syslog servers */
+       signed char logfac1, logfac2;           /* log facility for both servers. -1 = disabled */
+       int loglev1, loglev2;                   /* log level for each server, 7 by default */
        int to_log;                             /* things to be logged (LW_*) */
        struct timeval stop_time;               /* date to stop listening, when stopping != 0 */
        int nb_reqadd, nb_rspadd;
index 5e4aa51ee036ce95b446f6dc205aa5b424a6ae0d..836dc9aa313a8e03dd961d46d0607559c5986fae 100644 (file)
@@ -521,6 +521,11 @@ int cfg_parse_listen(char *file, int linenum, char **args)
                curproxy->source_addr = defproxy.source_addr;
                curproxy->mon_net = defproxy.mon_net;
                curproxy->mon_mask = defproxy.mon_mask;
+
+               if (defproxy.monitor_uri)
+                       curproxy->monitor_uri = strdup(defproxy.monitor_uri);
+               curproxy->monitor_uri_len = defproxy.monitor_uri_len;
+
                return 0;
        }
        else if (!strcmp(args[0], "defaults")) {  /* use this one to assign default values */
@@ -535,6 +540,7 @@ int cfg_parse_listen(char *file, int linenum, char **args)
                if (defproxy.errmsg.msg502) free(defproxy.errmsg.msg502);
                if (defproxy.errmsg.msg503) free(defproxy.errmsg.msg503);
                if (defproxy.errmsg.msg504) free(defproxy.errmsg.msg504);
+               if (defproxy.monitor_uri)   free(defproxy.monitor_uri);
                /* we cannot free uri_auth because it might already be used */
                init_default_instance();
                curproxy = &defproxy;
@@ -572,6 +578,24 @@ int cfg_parse_listen(char *file, int linenum, char **args)
                curproxy->mon_net.s_addr &= curproxy->mon_mask.s_addr;
                return 0;
        }
+       else if (!strcmp(args[0], "monitor-uri")) {  /* set the URI to intercept */
+               if (!*args[1]) {
+                       Alert("parsing [%s:%d] : '%s' expects an URI.\n",
+                             file, linenum, args[0]);
+                       return -1;
+               }
+
+               if (curproxy->monitor_uri != NULL)
+                       free(curproxy->monitor_uri);
+
+               curproxy->monitor_uri_len = strlen(args[1]) + 2; /* include leading and trailing spaces */
+               curproxy->monitor_uri = (char *)calloc(1, curproxy->monitor_uri_len + 1);
+               memcpy(curproxy->monitor_uri + 1, args[1], curproxy->monitor_uri_len - 2);
+               curproxy->monitor_uri[curproxy->monitor_uri_len-1] = curproxy->monitor_uri[0] = ' ';
+               curproxy->monitor_uri[curproxy->monitor_uri_len] = '\0';
+
+               return 0;
+       }
        else if (!strcmp(args[0], "mode")) {  /* sets the proxy mode */
                if (!strcmp(args[1], "http")) curproxy->mode = PR_MODE_HTTP;
                else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
@@ -1903,6 +1927,10 @@ int readcfgfile(char *file)
                                Warning("parsing %s : client regular expressions will be ignored for listener %s.\n",
                                        file, curproxy->id);
                        }
+                       if (curproxy->monitor_uri != NULL) {
+                               Warning("parsing %s : monitor-uri will be ignored for listener %s.\n",
+                                       file, curproxy->id);
+                       }
                }
                else if (curproxy->mode == PR_MODE_HTTP) { /* HTTP PROXY */
                        if ((curproxy->cookie_name != NULL) && ((newsrv = curproxy->srv) == NULL)) {
index e1a7d17348376f82d0179f69da1663a65df49a79..d4e97641d47e048e110fe0656b2e281ff0bba52f 100644 (file)
 #include <proto/task.h>
 
 
+/* This is used by remote monitoring */
+const char *HTTP_200 =
+       "HTTP/1.0 200 OK\r\n"
+       "Cache-Control: no-cache\r\n"
+       "Connection: close\r\n"
+       "Content-Type: text/html\r\n"
+       "\r\n"
+       "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
+
 /* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
 const char *HTTP_401_fmt =
        "HTTP/1.0 401 Unauthorized\r\n"
@@ -180,7 +189,9 @@ int process_session(struct task *t)
                s->logs.bytes = s->rep->total;
 
        /* let's do a final log if we need it */
-       if (s->logs.logwait && (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
+       if (s->logs.logwait && 
+           !(s->flags & SN_MONITOR) &&
+           (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
                sess_log(s);
 
        /* the task MUST not be in the run queue anymore */
@@ -282,6 +293,37 @@ int process_cli(struct session *t)
                                 * whatever we want.
                                 */
 
+
+                               /* check if the URI matches the monitor_uri. To speed-up the
+                                * test, we include the leading and trailing spaces in the
+                                * comparison.
+                                */
+                               if ((t->proxy->monitor_uri_len != 0) &&
+                                   (t->req_line.len >= t->proxy->monitor_uri_len)) {
+                                       char *p = t->req_line.str;
+                                       int idx = 0;
+
+                                       /* skip the method so that we accept any method */
+                                       while (idx < t->req_line.len && p[idx] != ' ')
+                                               idx++;
+                                       p += idx;
+
+                                       if (t->req_line.len - idx >= t->proxy->monitor_uri_len &&
+                                           !memcmp(p, t->proxy->monitor_uri, t->proxy->monitor_uri_len)) {
+                                               /*
+                                                * We have found the monitor URI
+                                                */
+                                               t->flags |= SN_MONITOR;
+                                               t->logs.status = 200;
+                                               client_retnclose(t, strlen(HTTP_200), HTTP_200);
+                                               if (!(t->flags & SN_ERR_MASK))
+                                                       t->flags |= SN_ERR_PRXCOND;
+                                               if (!(t->flags & SN_FINST_MASK))
+                                                       t->flags |= SN_FINST_R;
+                                               return 1;
+                                       }
+                               }
+
                                if (t->proxy->uri_auth != NULL
                                    && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) {   /* +4 for "GET /" */
                                        if (!memcmp(t->req_line.str + 4,