Willy,

Thank you for the feedback. I believe that the patch attached at the
bottom of this email incorporates your suggestions. Please let me know
any further steps I need to take.

As for testing, I ran the following test:

=== Test Setup  ===
I set up a config, used netcat to create some dummy services, and
looked at what the sent headers looked like. I bound the server to
127.0.0.1 and my http test server backend was at 127.0.0.2.

=== /tmp/haproxy.cfg ===
global
    daemon
defaults
    timeout connect 200ms
    timeout client 1000ms
    timeout server 1000ms
    mode http
    option forceclose

listen stats :3217
    mode http
    stats enable
    stats uri /
    stats refresh 1m
    stats show-node

frontend test.main
    bind 127.0.0.1:16000
    default_backend test.main

backend test.main
    option httpchk GET /
    http-check send-state

    server testhttp 127.0.0.2:8001 observe layer7 check

frontend test_socket.main
    bind 127.0.0.1:16001
    default_backend test_socket.main

backend test_socket.main
    option httpchk
    http-check send-state

    server tstsocket /tmp/test.sock observe layer7 check

=== end /tmp/haproxy.cfg ===

I (re)started haproxy with:

./haproxy -f /tmp/haproxy.cfg -p /tmp/haproxy.pid -sf $(cat /tmp/haproxy.pid)

And than used netcat to create dummy servers at these two addresses:

jlynch@<host>:~$ nc.openbsd -l 127.0.0.2 8001
GET / HTTP/1.0
X-Haproxy-Server-State: DOWN; address=127.0.0.2; port=8001;
name=test.main/testhttp; node=<host>; weight=1/0; scur=0/0; qcur=0

jlynch@<host>:~$ rm /tmp/test.sock; nc.openbsd -lU /tmp/test.sock
OPTIONS / HTTP/1.0
X-Haproxy-Server-State: DOWN; address=unix; port=unix;
name=test_socket.main/tstsocket; node=<host>; weight=1/0; scur=0/0;
qcur=0

=== End Test ===

It appears that the address and port have "unix" for domain sockets,
which is consistent with my understanding of the addr_to_str and
port_to_str methods in src/standard.c . If you like I can inspect the
return value from addr_to_str and try to find the path or some such.

Thank you,
-Joey Lynch

=== Patch ===
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 3ae6624..c8b648b 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -2896,6 +2896,14 @@ http-check send-state
   checks on the total number before transition, just as appears in the stats
   interface. Next headers are in the form "<variable>=<value>", indicating in
   no specific order some values available in the stats interface :
+    - a variable "address", containing the address of the backend server.
+      This corresponds to the <address> field in the server declaration. For
+      unix domain sockets, it will read "unix".
+
+    - a variable "port", containing the port of the backend server. This
+      corresponds to the <port> field in the server declaration. For unix
+      domain sockets, it will read "unix".
+
     - a variable "name", containing the name of the backend followed by a slash
       ("/") then the name of the server. This can be used when a server is
       checked in multiple backends.
diff --git a/src/checks.c b/src/checks.c
index 71debb6..1959c98 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -471,6 +471,8 @@ static int httpchk_build_status_header(struct
server *s, char *buffer, int size)
    int sv_state;
    int ratio;
    int hlen = 0;
+   char addr[46];
+   char port[6];
    const char *srv_hlt_st[7] = { "DOWN", "DOWN %d/%d",
                      "UP %d/%d", "UP",
                      "NOLB %d/%d", "NOLB",
@@ -501,8 +503,11 @@ static int httpchk_build_status_header(struct
server *s, char *buffer, int size)
                 (s->state != SRV_ST_STOPPED) ? (s->check.health -
s->check.rise + 1) : (s->check.health),
                 (s->state != SRV_ST_STOPPED) ? (s->check.fall) :
(s->check.rise));

-   hlen += snprintf(buffer + hlen,  size - hlen, "; name=%s/%s;
node=%s; weight=%d/%d; scur=%d/%d; qcur=%d",
-                s->proxy->id, s->id,
+   addr_to_str(&s->addr, addr, sizeof(addr));
+   port_to_str(&s->addr, port, sizeof(port));
+
+   hlen += snprintf(buffer + hlen,  size - hlen, "; address=%s;
port=%s; name=%s/%s; node=%s; weight=%d/%d; scur=%d/%d; qcur=%d",
+                addr, port, 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,

On Sat, Jan 31, 2015 at 10:35 PM, Willy Tarreau <[email protected]> wrote:
> Hello Joseph,
>
> I'm CCing Bhaskar since he was the one proposing the first solution, he
> may have some useful insights. Other points below.
>
> On Thu, Jan 15, 2015 at 01:23:59PM -0800, Joseph Lynch wrote:
>> Hello,
>>
>> I am trying to set up a health check service similar to the inetd solutions
>> suggested in the documentation. Unfortunately, my backends run on different
>> ports because they are being created dynamically and as far as I can tell I
>> cannot include the server port in my healthcheck either as part of the
>> server declaration, a header, or as part of the healthcheck uri itself.
>>
>> I have been trying to come up with potential solutions that are not overly
>> invasive, and I think that the simplest solution is to include the server
>> host and port in the existing send-state header. I have included a patch
>> that I believe does this at the end of this email. Before I go off
>> maintaining a local fork, I wanted to ask if the haproxy devs would be
>> sympathetic to me trying to upstream this patch?
>
> I'm personally fine with it. As you say, it's really not invasive, so we
> could merge it and even backport it into 1.5-stable. I'd slightly change
> something however, I'd use "address" instead of "host" in the field, since
> that's what you're copying there. "Host" could be used later to copy the
> equivalent of a host name, so let's not misuse the field name.
>
>> As for prior art, I found a few posts on this mailing list about the
>> ability to add headers to http checks. I believe that something like
>> http://marc.info/?l=haproxy&m=139181606417120&w=2 would be more then what
>> we need to solve this problem, but that thread seems to have died. I do
>> believe that a general ability to add headers to healthchecks would be
>> superior to my patch, but the general solution is significantly harder to
>> pull off.
>
> I'd like to re-heat that thread. I didn't even remember about it, indeed
> we were busy finalizing 1.5. Bhaskar, I still think your work makes sense
> for 1.6, so if you still have your patch, it's probably time to resend it :-)
>
>> If you guys agree that this patch is ok, please let me know what
>> I need to do next. I don't see any tests for the send-state option but I
>> presume that I would need to update the documentation.
>
> Please check what your patch does with servers not having any IP nor port
> (ie: the ones reached over a unix socket). I suspect you'll have the socket
> path in the host part, and "0" as the port, but I'm not sure, so I'd like
> to be certain. Also, please verify that it's really the server's address
> and port, and not the ones from the check, that are passed in the header.
> So if you specify "addr" and "port" on the server line, these ones are only
> used for the check, and we want to be sure that the real ones are properly
> used. Once everything's OK, please update the doc about "send-state".
>
> Thanks,
> Willy

Reply via email to