[MEDIUM] implemented the 'monitor-uri' keyword.
It is used to test haproxy's status with an HTTP request to which it will reply with HTTP/1.0 200 OK.
This commit is contained in:
parent
f3c692090e
commit
1c47f85292
19
ROADMAP
19
ROADMAP
@ -35,6 +35,12 @@
|
||||
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.
|
||||
@ -93,3 +98,15 @@
|
||||
|
||||
- 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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -50,6 +50,15 @@
|
||||
#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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user