Hello, I apologize for my persistence and realize that everyone if busy with getting 1.5 out of the door. I have no expectations on that front for the patch included here. However any feedback is welcome. I went thru some of the submitted patches and saw one by Simon Horman to use an external process after I made this change and will revisit that again.
I re-did my implementation, and this time I am submitting it as a patch for consideration. I am posting the commit message that explains the change. ================================================================= We add new directives to the http-check keyword The server option is used to specify an external health checking server to use for health checks. Example: http-check server <ipv4|ipv6> The info option is used to specify a http header to communicate information about the server being checked to the external health checking server Example: http-check info [header <http-header>] The default value of the header is 'X-Check-Info' This option is independent of the server directive. When used includes a http header in the health check request of the form <http-header>: <value> Finally, we add to the server directive a 'info' option. This value assigned to this option is passed to the external health checking server. Example: server id <addr> [info <value>] Putting it all togeather backend bck1 mode http # the host header works but wasn't the intent option httpchk GET /health HTTP/1.1\r\nHost:\ www.hst1.com # specify a server to use for the check http-check server chksrv1.dc.hst1.com # request for info about the server using the default host header # the following 2 lines are equivalent # http-check info http-check info X-Check-Info # pass in the info using the default # the following 2 lines are equivalent # server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s info a1 # this is probably a better alternative server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s info a1.dc.hst1.com ================================================================= This implementation can also be used for http health checks when running in tcp mode providing a potential alternative to implementing health checks for tcp mode deployments not directly available in haproxy, also allowing for more advanced health check beyond a hello message. Following is a config that I used to test this global maxconn 10 defaults mode tcp clitimeout 30m srvtimeout 30m contimeout 4s backend myblog option httpchk GET /_health.php HTTP/1.1 http-check server bhaskar-dev:80 http-check info server b1 blackmagic.tumblr.com:80 weight 20 maxconn 5 check inter 2s info blackmagic.tumblr.com frontend myblogfrontend bind *:9080 default_backend myblog Thanks Bhaskar On Thu, Feb 6, 2014 at 2:45 PM, Bhaskar Maddala <madda...@gmail.com> wrote: > Hello, > > Since I did not get any responses on this, I decided to try > motivating a reponse > by attempting an implementation. I am attaching a patch that does > this. Admittedly > this patch is an iteration and I am not submitting it for anything > more than receiving > feedback, on the requirement, alternative ideas and the implementation. > > Following is an explanation > > I added an option httpchksrv which takes an ipv4/6 address (external > health checker) > and an option http header. The http header is used to communicate to the > health > check server the backend server to check. > > option httpchk GET /_health.php HTTP/1.1 > option httpchksrv <ipv4|ipv6> [header > <http-header-name=X-Check-For>] > > Next, I added a "header-value" specification to the server definition > > server a1 magic.tumblr.com:80 weight 20 maxconn 5 check inter > 2s header-value magic.tumblr.com > > the header-value is used for the http-header-name specified in httpchksrv > > Here is an example of the health check request > > GET /_health.php HTTP/1.1 > X-Check-For: magic.tumblr.com > > The default value of header-value is the server id, in this case 'a1' > > The following is a little abstract and describes how health checks can be > cached > using this change, please bear with my attempts to describe it, these may be > in-adequate. Please take this for what it is, broad strokes of an > idea. I am not in any way advocating for this deployment. > > Going back to my original motivation "excessive health checks due to > increasing > proxy and web application deployment", here is a description of how I can > solve > it using this implementation. > > On haproxy I define 2 frontend, one on port 80 and one on port 6777. The > httpchksrv specification is used to direct health checks back to haproxy on > port > 6777. With haproxy in http mode > > option httpchksrv 127.0.0.1:6777 > > Each server specification on the backend for port 80 (production traffic) uses > a server specification as > > server a1 server:80 weight 20 maxconn 5 check inter 2s > > I define a backend of varnish nodes to use with the front end on port 6777. > I also make sure that the varnish backend uses only L4 health checks. > > Health check are passed to varnish from all the proxies consistently hashed on > the http header X-Check-For via their front end on port 6777. Varnish > vcl is used to > obtain the header value 'X-Check-For' and make a health check request to the > appropriate web host if required, it may return cached health check > responses according > the configured TTL. > > > Thanks > Bhaskar > > On Fri, Jan 31, 2014 at 1:46 PM, Bhaskar Maddala <madda...@gmail.com> wrote: >> Hello, >> >> As the number of haproxy deployments (>20) grows in our infrastructure >> along >> with an increase in the number of backends ~1500 we are beginning to >> see a non trivial resources allocated to health checks. Each proxy instance >> health checking each backend every 2 seconds. >> >> In an earlier conversation with Willy I was directed to look into the >> options >> fastinter and on-error configuration options. I have done this but wanted to >> speak about how others might have addressed this and if there was any >> interest in implementing something along these lines and gather >> ideas/comments >> on what such an implementation would look like. >> >> We use haproxy as a http load balancer and I have not given any thought >> about how the following description applies to tcp mode. >> >> Currently we http check our backends using >> >> option httpchk GET /_check.php HTTP/1.1\r\nHost:\ www.domain.com >> >> We were considering adding an additional directive to specify a check >> server >> in addition to the httpchk directive >> >> option httpchk GET /_health.php HTTP/1.1\r\nHost:\ hdr(Host) >> option chksrv server hcm-008dad0f 172.16.114.52:80 >> >> The change would add a dynamic field to the health check request. >> hdr(Host) (http host header in this instance) is the field used to >> communicate >> the server to be health checked to the external check server. >> >> The check server can/will be implemented to cache health check responses from >> the back ends. >> >> One of the justifications for implementing this is the need in my >> environment to take >> into consideration factors not available to the backends when >> responding to a health >> check. As an example we will be implementing in our check server >> ability to force >> success/failure of health checks on groups of backends related in some >> manner. >> We expect this to allow us to avoid brown out scenarios we have >> encountered in the past. >> >> Has anyone considered/achieved something along these lines, or have >> suggestions >> on how we could implement the same? >> >> Thanks >> Bhaskar
From 434317d54ad36e62560454eb0a0f6f43be17b091 Mon Sep 17 00:00:00 2001 From: Bhaskar Maddala <madda...@gmail.com> Date: Fri, 7 Feb 2014 13:55:35 -0500 Subject: [PATCH] Add ability to externalize health check Summary: We add new directives to the http-check keyword The server option is used to specify an external health checking server to use for health checks. Example: http-check server <ipv4|ipv6> The info option is used to specify a http header to communicate information about the server being checked to the external health checking server Example: http-check info [header <http-header>] The default value of the header is 'X-Check-Info' This option is independent of the server directive. When used includes a http header in the health check request of the form <http-header>: <value> Finally, we add to the server directive a 'info' option. This value assigned to this option is passed to the external health checking server. Example: server id <addr> [info <value>] Putting it all togeather backend bck1 mode http # the host header works but wasn't the intent option httpchk GET /health HTTP/1.1\r\nHost:\ www.hst1.com # specify a server to use for the check http-check server chksrv1.dc.hst1.com # request for info about the server using the default host header # the following 2 lines are equivalent # http-check info http-check info X-Check-Info # pass in the info using the default # the following 2 lines are equivalent # server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s info a1 # this is probably a better alternative server a1 a1.dc.hst1.com:80 weight 20 maxconn 5 check inter 2s info a1.dc.hst1.com --- include/common/defaults.h | 2 + include/types/proxy.h | 8 +++- include/types/server.h | 3 ++ src/cfgparse.c | 110 ++++++++++++++++++++++++++++++++++++++------- src/checks.c | 112 +++++++++++++++++++++++++++------------------- 5 files changed, 169 insertions(+), 66 deletions(-) diff --git a/include/common/defaults.h b/include/common/defaults.h index f765e90..17bc5d2 100644 --- a/include/common/defaults.h +++ b/include/common/defaults.h @@ -131,6 +131,8 @@ #define DEF_SMTP_CHECK_REQ "HELO localhost\r\n" #define DEF_LDAP_CHECK_REQ "\x30\x0c\x02\x01\x01\x60\x07\x02\x01\x03\x04\x00\x80\x00" #define DEF_REDIS_CHECK_REQ "*1\r\n$4\r\nPING\r\n" +#define DEF_CHECK_HOST_HDR "X-Check-Info" +#define DEF_CHECK_HOST_PORT 80 #define DEF_HANA_ONERR HANA_ONERR_FAILCHK #define DEF_HANA_ERRLIMIT 10 diff --git a/include/types/proxy.h b/include/types/proxy.h index af2a3ab..638b5f7 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -142,7 +142,8 @@ enum pr_mode { #define PR_O2_SRC_ADDR 0x00100000 /* get the source ip and port for logs */ #define PR_O2_FAKE_KA 0x00200000 /* pretend we do keep-alive with server eventhough we close */ -/* unused: 0x00400000 */ +#define PR_O2_CHK_INFO 0x00400000 /* include info header and value in http health checks */ + #define PR_O2_EXP_NONE 0x00000000 /* http-check : no expect rule */ #define PR_O2_EXP_STS 0x00800000 /* http-check expect status */ #define PR_O2_EXP_RSTS 0x01000000 /* http-check expect rstatus */ @@ -338,7 +339,10 @@ struct proxy { int grace; /* grace time after stop request */ struct list tcpcheck_rules; /* tcp-check send / expect rules */ char *check_req; /* HTTP or SSL request to use for PR_O_HTTP_CHK|PR_O_SSL3_CHK */ - int check_len; /* Length of the HTTP or SSL3 request */ + int check_req_len; /* Length of the HTTP or SSL3 request */ + struct sockaddr_storage check_addr; /* the address to check */ + char *check_for_hdr_name; /* HTTP header used to identify host being checked */ + int check_for_hdr_name_len; /* Length of the HTTP header */ char *expect_str; /* http-check expected content : string or text version of the regex */ regex_t *expect_regex; /* http-check expected content */ struct chunk errmsg[HTTP_ERR_SIZE]; /* default or customized error messages for known errors */ diff --git a/include/types/server.h b/include/types/server.h index 54ab813..ef56a49 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -161,6 +161,9 @@ struct server { struct sockaddr_storage addr; /* the address to check, if different from <addr> */ } check_common; + char *check_for_hdr_val; /* http header value used for health checkes */ + int check_for_hdr_val_len; /* length of the http header value */ + struct check check; /* health-check specific configuration */ struct check agent; /* agent specific configuration */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 9993c61..7e56df8 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1841,12 +1841,19 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) if (curproxy->cap & PR_CAP_BE) { curproxy->fullconn = defproxy.fullconn; curproxy->conn_retries = defproxy.conn_retries; + curproxy->check_addr = defproxy.check_addr; if (defproxy.check_req) { - curproxy->check_req = calloc(1, defproxy.check_len); - memcpy(curproxy->check_req, defproxy.check_req, defproxy.check_len); + curproxy->check_req = calloc(1, defproxy.check_req_len); + memcpy(curproxy->check_req, defproxy.check_req, defproxy.check_req_len); } - curproxy->check_len = defproxy.check_len; + curproxy->check_req_len = defproxy.check_req_len; + + if (defproxy.check_for_hdr_name) { + curproxy->check_for_hdr_name = calloc(1, defproxy.check_for_hdr_name_len); + memcpy(curproxy->check_for_hdr_name, defproxy.check_for_hdr_name, defproxy.check_for_hdr_name_len); + } + curproxy->check_for_hdr_name_len = defproxy.check_for_hdr_name_len; if (defproxy.expect_str) { curproxy->expect_str = strdup(defproxy.expect_str); @@ -1990,6 +1997,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) free(defproxy.monitor_uri); free(defproxy.defbe.name); free(defproxy.conn_src.iface_name); + free(defproxy.check_for_hdr_name); + defproxy.check_for_hdr_name_len = 0; free(defproxy.fwdfor_hdr_name); defproxy.fwdfor_hdr_len = 0; free(defproxy.orgto_hdr_name); @@ -3631,11 +3640,11 @@ stats_error_parsing: curproxy->options2 |= PR_O2_HTTP_CHK; if (!*args[2]) { /* no argument */ curproxy->check_req = strdup(DEF_CHECK_REQ); /* default request */ - curproxy->check_len = strlen(DEF_CHECK_REQ); + curproxy->check_req_len = strlen(DEF_CHECK_REQ); } else if (!*args[3]) { /* one argument : URI */ int reqlen = strlen(args[2]) + strlen("OPTIONS HTTP/1.0\r\n") + 1; curproxy->check_req = (char *)malloc(reqlen); - curproxy->check_len = snprintf(curproxy->check_req, reqlen, + curproxy->check_req_len = snprintf(curproxy->check_req, reqlen, "OPTIONS %s HTTP/1.0\r\n", args[2]); /* URI to use */ } else { /* more arguments : METHOD URI [HTTP_VER] */ int reqlen = strlen(args[2]) + strlen(args[3]) + 3 + strlen("\r\n"); @@ -3645,7 +3654,7 @@ stats_error_parsing: reqlen += strlen("HTTP/1.0"); curproxy->check_req = (char *)malloc(reqlen); - curproxy->check_len = snprintf(curproxy->check_req, reqlen, + curproxy->check_req_len = snprintf(curproxy->check_req, reqlen, "%s %s %s\r\n", args[2], args[3], *args[4]?args[4]:"HTTP/1.0"); } } @@ -3668,18 +3677,18 @@ stats_error_parsing: if (!*args[2] || !*args[3]) { /* no argument or incomplete EHLO host */ curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */ - curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ); + curproxy->check_req_len = strlen(DEF_SMTP_CHECK_REQ); } else { /* ESMTP EHLO, or SMTP HELO, and a hostname */ if (!strcmp(args[2], "EHLO") || !strcmp(args[2], "HELO")) { int reqlen = strlen(args[2]) + strlen(args[3]) + strlen(" \r\n") + 1; curproxy->check_req = (char *)malloc(reqlen); - curproxy->check_len = snprintf(curproxy->check_req, reqlen, + curproxy->check_req_len = snprintf(curproxy->check_req, reqlen, "%s %s\r\n", args[2], args[3]); /* HELO hostname */ } else { /* this just hits the default for now, but you could potentially expand it to allow for other stuff though, it's unlikely you'd want to send anything other than an EHLO or HELO */ curproxy->check_req = strdup(DEF_SMTP_CHECK_REQ); /* default request */ - curproxy->check_len = strlen(DEF_SMTP_CHECK_REQ); + curproxy->check_req_len = strlen(DEF_SMTP_CHECK_REQ); } } } @@ -3726,7 +3735,7 @@ stats_error_parsing: free(curproxy->check_req); curproxy->check_req = packet; - curproxy->check_len = packet_len; + curproxy->check_req_len = packet_len; packet_len = htonl(packet_len); memcpy(packet, &packet_len, 4); @@ -3754,7 +3763,7 @@ stats_error_parsing: curproxy->check_req = (char *) malloc(sizeof(DEF_REDIS_CHECK_REQ) - 1); memcpy(curproxy->check_req, DEF_REDIS_CHECK_REQ, sizeof(DEF_REDIS_CHECK_REQ) - 1); - curproxy->check_len = sizeof(DEF_REDIS_CHECK_REQ) - 1; + curproxy->check_req_len = sizeof(DEF_REDIS_CHECK_REQ) - 1; } else if (!strcmp(args[1], "mysql-check")) { @@ -3803,7 +3812,7 @@ stats_error_parsing: free(curproxy->check_req); curproxy->check_req = (char *)calloc(1, reqlen); - curproxy->check_len = reqlen; + curproxy->check_req_len = reqlen; snprintf(curproxy->check_req, 4, "%c%c%c", ((unsigned char) packetlen & 0xff), @@ -3836,7 +3845,7 @@ stats_error_parsing: curproxy->check_req = (char *) malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1); memcpy(curproxy->check_req, DEF_LDAP_CHECK_REQ, sizeof(DEF_LDAP_CHECK_REQ) - 1); - curproxy->check_len = sizeof(DEF_LDAP_CHECK_REQ) - 1; + curproxy->check_req_len = sizeof(DEF_LDAP_CHECK_REQ) - 1; } else if (!strcmp(args[1], "tcp-check")) { /* use raw TCPCHK send/expect to check servers' health */ @@ -4079,8 +4088,67 @@ stats_error_parsing: goto out; } } + else if (!strcmp(args[1], "server")) { + if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) + err_code |= ERR_WARN; + + /* use a external http check server instead of querying the server for health checks */ + if (!*args[2]) { + Alert("parsing [%s:%d]: '%s' expects an <ipv4|ipv6> address.\n", + file, linenum, args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + struct sockaddr_storage *sk; + int port1, port2; + struct protocol *proto; + + sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL); + if (!sk) { + Alert("parsing [%s:%d] : '%s' : %s\n", + file, linenum, args[2], errmsg); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + proto = protocol_by_family(sk->ss_family); + if (!proto || !proto->connect) { + Alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n", + file, linenum, args[1], args[2]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + if (port1 != port2) { + Alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n", + file, linenum, args[1], args[2]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + if (!port1) + set_host_port(sk, DEF_CHECK_HOST_PORT); + + curproxy->check_addr = *sk; + } + else if (!strcmp(args[1], "info")) { + curproxy->options2 |= PR_O2_CHK_INFO; + if (!*args[2]) { /* no argument */ + curproxy->check_for_hdr_name = strdup(DEF_CHECK_HOST_HDR); + curproxy->check_for_hdr_name_len = strlen(DEF_CHECK_HOST_HDR); + } else if (*args[2] && !strcmp(args[2], "header")) { + curproxy->check_for_hdr_name = strdup(args[3]); + curproxy->check_for_hdr_name_len = strlen(args[3]); + } else { + Alert("parsing [%s:%d] : '%s' : expect valid http header it can be specified using 'header'\n", + file, linenum, args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } else { - Alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect'.\n", file, linenum, args[0]); + Alert("parsing [%s:%d] : '%s' only supports 'disable-on-404', 'send-state', 'expect', 'server', 'info'.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } @@ -4563,6 +4631,8 @@ stats_error_parsing: newsrv->state = SRV_RUNNING; /* early server setup */ newsrv->last_change = now.tv_sec; newsrv->id = strdup(args[1]); + newsrv->check_for_hdr_val = strdup(args[1]); + newsrv->check_for_hdr_val_len = strlen(args[1]); /* several ways to check the port component : * - IP => port=+0, relative (IPv4 only) @@ -4812,6 +4882,11 @@ stats_error_parsing: newsrv->check_common.addr = *sk; cur_arg += 2; } + else if (!strcmp(args[cur_arg], "info")) { + newsrv->check_for_hdr_val = strdup(args[cur_arg + 1]); + newsrv->check_for_hdr_val_len = strlen(args[cur_arg + 1]); + cur_arg += 2; + } else if (!strcmp(args[cur_arg], "port")) { newsrv->check.port = atol(args[cur_arg + 1]); cur_arg += 2; @@ -5258,6 +5333,7 @@ stats_error_parsing: #endif newsrv->check.send_proxy |= (newsrv->state & SRV_SEND_PROXY); } + /* try to get the port from check_core.addr if check.port not set */ if (!newsrv->check.port) newsrv->check.port = get_host_port(&newsrv->check_common.addr); @@ -7078,9 +7154,9 @@ out_uri_auth_compat: } if ((curproxy->options2 & PR_O2_CHK_ANY) == PR_O2_SSL3_CHK) { - curproxy->check_len = sizeof(sslv3_client_hello_pkt) - 1; - curproxy->check_req = (char *)malloc(curproxy->check_len); - memcpy(curproxy->check_req, sslv3_client_hello_pkt, curproxy->check_len); + curproxy->check_req_len = sizeof(sslv3_client_hello_pkt) - 1; + curproxy->check_req = (char *)malloc(curproxy->check_req_len); + memcpy(curproxy->check_req, sslv3_client_hello_pkt, curproxy->check_req_len); } /* ensure that cookie capture length is not too large */ diff --git a/src/checks.c b/src/checks.c index c3051aa..c559307 100644 --- a/src/checks.c +++ b/src/checks.c @@ -733,58 +733,65 @@ void __health_adjust(struct server *s, short status) } } -static int httpchk_build_status_header(struct server *s, char *buffer) +static int httpchk_build_headers(struct server *s, char* buffer) { int sv_state; int ratio; - int hlen = 0; const char *srv_hlt_st[7] = { "DOWN", "DOWN %d/%d", "UP %d/%d", "UP", "NOLB %d/%d", "NOLB", "no check" }; + int hlen = 0; - memcpy(buffer + hlen, "X-Haproxy-Server-State: ", 24); - hlen += 24; + if (s->proxy->options2 & PR_O2_CHK_INFO) { + hlen += s->proxy->check_for_hdr_name_len + strlen(": ") + s->check_for_hdr_val_len + strlen("\r\n"); + sprintf(buffer, "%s: %s\r\n", s->proxy->check_for_hdr_name, s->check_for_hdr_val); + } - if (!(s->check.state & CHK_ST_ENABLED)) - sv_state = 6; - else if (s->state & SRV_RUNNING) { - if (s->check.health == s->check.rise + s->check.fall - 1) - sv_state = 3; /* UP */ - else - sv_state = 2; /* going down */ + if (s->proxy->options2 & PR_O2_CHK_SNDST) { + memcpy(buffer + hlen, "X-Haproxy-Server-State: ", 24); + hlen += 24; - if (s->state & SRV_GOINGDOWN) - sv_state += 2; - } else { - if (s->check.health) - sv_state = 1; /* going up */ - else - sv_state = 0; /* DOWN */ - } + if (!(s->check.state & CHK_ST_ENABLED)) + sv_state = 6; + else if (s->state & SRV_RUNNING) { + if (s->check.health == s->check.rise + s->check.fall - 1) + sv_state = 3; /* UP */ + else + sv_state = 2; /* going down */ - hlen += sprintf(buffer + hlen, - srv_hlt_st[sv_state], - (s->state & SRV_RUNNING) ? (s->check.health - s->check.rise + 1) : (s->check.health), - (s->state & SRV_RUNNING) ? (s->check.fall) : (s->check.rise)); - - hlen += sprintf(buffer + hlen, "; name=%s/%s; node=%s; weight=%d/%d; scur=%d/%d; qcur=%d", - s->proxy->id, s->id, - global.node, - (s->eweight * s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv, - (s->proxy->lbprm.tot_weight * s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv, - s->cur_sess, s->proxy->beconn - s->proxy->nbpend, - s->nbpend); - - if ((s->state & SRV_WARMINGUP) && - now.tv_sec < s->last_change + s->slowstart && - now.tv_sec >= s->last_change) { - ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart); - hlen += sprintf(buffer + hlen, "; throttle=%d%%", ratio); - } + if (s->state & SRV_GOINGDOWN) + sv_state += 2; + } else { + if (s->check.health) + sv_state = 1; /* going up */ + else + sv_state = 0; /* DOWN */ + } + + hlen += sprintf(buffer + hlen, + srv_hlt_st[sv_state], + (s->state & SRV_RUNNING) ? (s->check.health - s->check.rise + 1) : (s->check.health), + (s->state & SRV_RUNNING) ? (s->check.fall) : (s->check.rise)); + + hlen += sprintf(buffer + hlen, "; name=%s/%s; node=%s; weight=%d/%d; scur=%d/%d; qcur=%d", + s->proxy->id, s->id, + global.node, + (s->eweight * s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv, + (s->proxy->lbprm.tot_weight * s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv, + s->cur_sess, s->proxy->beconn - s->proxy->nbpend, + s->nbpend); + + if ((s->state & SRV_WARMINGUP) && + now.tv_sec < s->last_change + s->slowstart && + now.tv_sec >= s->last_change) { + ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart); + hlen += sprintf(buffer + hlen, "; throttle=%d%%", ratio); + } - buffer[hlen++] = '\r'; - buffer[hlen++] = '\n'; + buffer[hlen++] = '\r'; + buffer[hlen++] = '\n'; + } return hlen; } @@ -1254,7 +1261,7 @@ static void event_srv_chk_r(struct connection *conn) if (!done && check->bi->i < 5) goto wait_more_data; - if (s->proxy->check_len == 0) { // old mode + if (s->proxy->check_req_len == 0) { // old mode if (*(check->bi->data + 4) != '\xff') { /* We set the MySQL Version in description for information purpose * FIXME : it can be cool to use MySQL Version for other purpose, @@ -1505,6 +1512,7 @@ static struct task *process_chk(struct task *t) int rv; int ret; int expired = tick_is_expired(t->expire, now_ms); + int hlen = 0; if (!(check->state & CHK_ST_INPROGRESS)) { /* no check currently running */ @@ -1539,7 +1547,7 @@ static struct task *process_chk(struct task *t) * its own strings. */ if (check->type && check->type != PR_O2_TCPCHK_CHK && !(check->state & CHK_ST_AGENT)) { - bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_len); + bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_req_len); /* we want to check if this host replies to HTTP or SSLv3 requests * so we'll send the request, and won't wake the checker up now. @@ -1550,8 +1558,13 @@ static struct task *process_chk(struct task *t) memcpy(check->bo->data + 11, &gmt_time, 4); } else if ((check->type) == PR_O2_HTTP_CHK) { - if (s->proxy->options2 & PR_O2_CHK_SNDST) - bo_putblk(check->bo, trash.str, httpchk_build_status_header(s, trash.str)); + + /* set up the http request with headers correctly */ + hlen = httpchk_build_headers(s, trash.str); + + if (hlen) + bo_putblk(check->bo, trash.str, hlen); + bo_putstr(check->bo, "\r\n"); *check->bo->p = '\0'; /* to make gdb output easier to read */ } @@ -1569,9 +1582,14 @@ static struct task *process_chk(struct task *t) if (is_addr(&s->check_common.addr)) /* we'll connect to the check addr specified on the server */ conn->addr.to = s->check_common.addr; - else - /* we'll connect to the addr on the server */ - conn->addr.to = s->addr; + else { + if ((check->type) == PR_O2_HTTP_CHK && is_addr(&s->proxy->check_addr)) + /* we will connect to the check addr specified on the proxy, only http checks*/ + conn->addr.to = s->proxy->check_addr; + else + /* we'll connect to the addr on the server */ + conn->addr.to = s->addr; + } if (check->port) { set_host_port(&conn->addr.to, check->port); -- 1.8.3.4 (Apple Git-47)