]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] checks: add PostgreSQL health check
authorRauf Kuliyev <rauf@kuliyev.com>
Tue, 4 Jan 2011 14:14:13 +0000 (15:14 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 4 Jan 2011 14:14:13 +0000 (15:14 +0100)
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

doc/configuration.txt
include/types/proxy.h
src/cfgparse.c
src/checks.c

index cc4ecad90a6dd023b3ffa8c2f135bc8536dd50cb..bb25448ea1b3a97900439b2b7783e9014f0a9a96 100644 (file)
@@ -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 <method> <uri> <version>
           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 <username> ]
 
   See also: "option httpchk"
 
+option pgsql-check [ user <username> ]
+  Use PostgreSQL health checks for server testing
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    no    |   yes  |   yes
+  Arguments :
+    user <username> 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
 
index 8da98a6c21b8a3d47990d7deb05b90931733e06c..7a3276e2c25d74da7ca637530d676dc87f7de6ff 100644 (file)
 #define PR_O2_EXP_TYPE  0x03800000      /* mask for http-check expect type */
 #define PR_O2_EXP_INV   0x04000000      /* http-check expect !<rule> */
 #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 */
index 28eb1cab7f8c6a622d400b6f3338dbe057d75b1d..dd266af320fe1ad48e2eb8a032989a7efa4aad78 100644 (file)
@@ -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 <username> 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);
index a23fd41e9100f728968fc25faf0d336959ef731f..ee0b97bd73bc60928217f55ac83ef1692a8b378d 100644 (file)
@@ -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;