From: Rauf Kuliyev Date: Tue, 4 Jan 2011 14:14:13 +0000 (+0100) Subject: [MINOR] checks: add PostgreSQL health check X-Git-Tag: v1.5-dev8~325 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=38b4156a691557f4eda30445f0ef8ce61f280dfc;p=thirdparty%2Fhaproxy.git [MINOR] checks: add PostgreSQL health check I have written a small patch to enable a correct PostgreSQL health check It works similar to mysql-check with the very same parameters. E.g.: listen pgsql 127.0.0.1:5432 mode tcp option pgsql-check user pgsql server masterdb pgsql.server.com:5432 check inter 10000 --- diff --git a/doc/configuration.txt b/doc/configuration.txt index cc4ecad90a..bb25448ea1 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -993,6 +993,7 @@ option log-health-checks (*) X - X X option log-separate-errors (*) X X X - option logasap (*) X X X - option mysql-check X - X X +option pgsql-check X - X X option nolinger (*) X X X X option originalto X X X X option persist (*) X - X X @@ -3266,7 +3267,8 @@ option httpchk server apache1 192.168.1.1:443 check port 80 See also : "option ssl-hello-chk", "option smtpchk", "option mysql-check", - "http-check" and the "check", "port" and "inter" server options. + "option pgsql-check", "http-check" and the "check", "port" and + "inter" server options. option httpclose @@ -3540,6 +3542,20 @@ option mysql-check [ user ] See also: "option httpchk" +option pgsql-check [ user ] + Use PostgreSQL health checks for server testing + May be used in sections : defaults | frontend | listen | backend + yes | no | yes | yes + Arguments : + user This is the username which will be used when connecting + to PostgreSQL server. + + The check sends a PostgreSQL StartupMessage and waits for either + Authentication request or ErrorResponse message. It is a basic but useful + test which does not produce error nor aborted connect on the server. + This check is identical with the "mysql-check". + + See also: "option httpchk" option nolinger no option nolinger @@ -6457,8 +6473,8 @@ check "port" parameter, the source address using the "source" address, and the interval and timers using the "inter", "rise" and "fall" parameters. The request method is define in the backend using the "httpchk", "smtpchk", - "mysql-check" and "ssl-hello-chk" options. Please refer to those options and - parameters for more information. + "mysql-check", "pgsql-check" and "ssl-hello-chk" options. Please refer to + those options and parameters for more information. Supported in default-server: No diff --git a/include/types/proxy.h b/include/types/proxy.h index 8da98a6c21..7a3276e2c2 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -149,6 +149,8 @@ #define PR_O2_EXP_TYPE 0x03800000 /* mask for http-check expect type */ #define PR_O2_EXP_INV 0x04000000 /* http-check expect ! */ #define PR_O2_COOK_PSV 0x08000000 /* cookie ... preserve */ + +#define PR_O2_PGSQL_CHK 0x10000000 /* use PGSQL check for server health */ /* end of proxy->options2 */ /* bits for sticking rules */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 28eb1cab7f..dd266af320 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -3312,6 +3312,7 @@ stats_error_parsing: curproxy->options &= ~PR_O_SMTP_CHK; curproxy->options2 &= ~PR_O2_SSL3_CHK; curproxy->options2 &= ~PR_O2_MYSQL_CHK; + curproxy->options2 &= ~PR_O2_PGSQL_CHK; curproxy->options2 &= ~PR_O2_LDAP_CHK; curproxy->options |= PR_O_HTTP_CHK; if (!*args[2]) { /* no argument */ @@ -3344,6 +3345,7 @@ stats_error_parsing: curproxy->options &= ~PR_O_HTTP_CHK; curproxy->options &= ~PR_O_SMTP_CHK; curproxy->options2 &= ~PR_O2_MYSQL_CHK; + curproxy->options2 &= ~PR_O2_PGSQL_CHK; curproxy->options2 &= ~PR_O2_LDAP_CHK; curproxy->options2 |= PR_O2_SSL3_CHK; } @@ -3354,6 +3356,7 @@ stats_error_parsing: curproxy->options &= ~PR_O_HTTP_CHK; curproxy->options2 &= ~PR_O2_SSL3_CHK; curproxy->options2 &= ~PR_O2_MYSQL_CHK; + curproxy->options2 &= ~PR_O2_PGSQL_CHK; curproxy->options2 &= ~PR_O2_LDAP_CHK; curproxy->options |= PR_O_SMTP_CHK; @@ -3374,6 +3377,69 @@ stats_error_parsing: } } } + else if (!strcmp(args[1], "pgsql-check")) { + /* use PostgreSQL request to check servers' health */ + if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) + err_code |= ERR_WARN; + + free(curproxy->check_req); + curproxy->check_req = NULL; + curproxy->options &= ~PR_O_HTTP_CHK; + curproxy->options &= ~PR_O_SMTP_CHK; + curproxy->options2 &= ~PR_O2_SSL3_CHK; + curproxy->options2 &= ~PR_O2_LDAP_CHK; + curproxy->options2 &= ~PR_O2_MYSQL_CHK; + curproxy->options2 |= PR_O2_PGSQL_CHK; + + if (*(args[2])) { + int cur_arg = 2; + + while (*(args[cur_arg])) { + if (strcmp(args[cur_arg], "user") == 0) { + char * packet; + uint32_t packet_len; + uint32_t pv; + + /* suboption header - needs additional argument for it */ + if (*(args[cur_arg+1]) == 0) { + Alert("parsing [%s:%d] : '%s %s %s' expects as argument.\n", + file, linenum, args[0], args[1], args[cur_arg]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + /* uint32_t + uint32_t + strlen("user")+1 + strlen(username)+1 + 1 */ + packet_len = 4 + 4 + 5 + strlen(args[cur_arg + 1])+1 +1; + pv = htonl(0x30000); /* protocol version 3.0 */ + + packet = (char*) calloc(1, packet_len); + + memcpy(packet + 4, &pv, 4); + + /* copy "user" */ + memcpy(packet + 8, "user", 4); + + /* copy username */ + memcpy(packet + 13, args[cur_arg+1], strlen(args[cur_arg+1])); + + free(curproxy->check_req); + curproxy->check_req = packet; + curproxy->check_len = packet_len; + + packet_len = htonl(packet_len); + memcpy(packet, &packet_len, 4); + cur_arg += 2; + } else { + /* unknown suboption - catchall */ + Alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n", + file, linenum, args[0], args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } /* end while loop */ + } + } + else if (!strcmp(args[1], "mysql-check")) { /* use MYSQL request to check servers' health */ if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[1], NULL)) @@ -3385,6 +3451,7 @@ stats_error_parsing: curproxy->options &= ~PR_O_SMTP_CHK; curproxy->options2 &= ~PR_O2_SSL3_CHK; curproxy->options2 &= ~PR_O2_LDAP_CHK; + curproxy->options2 &= ~PR_O2_PGSQL_CHK; curproxy->options2 |= PR_O2_MYSQL_CHK; /* This is an exemple of an MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte. @@ -3454,6 +3521,7 @@ stats_error_parsing: curproxy->options &= ~PR_O_SMTP_CHK; curproxy->options2 &= ~PR_O2_SSL3_CHK; curproxy->options2 &= ~PR_O2_MYSQL_CHK; + curproxy->options2 &= ~PR_O2_PGSQL_CHK; curproxy->options2 |= PR_O2_LDAP_CHK; curproxy->check_req = (char *) malloc(sizeof(DEF_LDAP_CHECK_REQ) - 1); diff --git a/src/checks.c b/src/checks.c index a23fd41e91..ee0b97bd73 100644 --- a/src/checks.c +++ b/src/checks.c @@ -747,6 +747,7 @@ static int event_srv_chk_w(int fd) (s->proxy->options & PR_O_SMTP_CHK) || (s->proxy->options2 & PR_O2_SSL3_CHK) || (s->proxy->options2 & PR_O2_MYSQL_CHK) || + (s->proxy->options2 & PR_O2_PGSQL_CHK) || (s->proxy->options2 & PR_O2_LDAP_CHK)) { int ret; const char *check_req = s->proxy->check_req; @@ -1001,6 +1002,22 @@ static int event_srv_chk_r(int fd) else set_server_check_status(s, HCHK_STATUS_L7STS, desc); } + else if (s->proxy->options2 & PR_O2_PGSQL_CHK) { + if (!done && s->check_data_len < 9) + goto wait_more_data; + + if (s->check_data[0] == 'R') { + set_server_check_status(s, HCHK_STATUS_L7OKD, "PostgreSQL server is ok"); + } + else { + if ((s->check_data[0] == 'E') && (s->check_data[5]!=0) && (s->check_data[6]!=0)) + desc = &s->check_data[6]; + else + desc = "PostgreSQL unknown error"; + + set_server_check_status(s, HCHK_STATUS_L7STS, desc); + } + } else if (s->proxy->options2 & PR_O2_MYSQL_CHK) { if (!done && s->check_data_len < 5) goto wait_more_data;