7d3267
From 7b952299ea7dbe17289d5f34d5c2867a8077fb19 Mon Sep 17 00:00:00 2001
7d3267
From: Ryan O'Hara <rohara@redhat.com>
7d3267
Date: Thu, 28 Feb 2019 08:22:45 -0600
7d3267
Subject: [PATCH] BUG/MEDIUM: tcp-check: single connect rule can't detect DOWN
7d3267
 servers
7d3267
7d3267
When tcpcheck is used to do TCP port monitoring only and the script is
7d3267
composed by a single "tcp-check connect" rule (whatever port and ssl
7d3267
options enabled), then the server can't be seen as DOWN.
7d3267
Simple configuration to reproduce:
7d3267
7d3267
  backend b
7d3267
    [...]
7d3267
    option tcp-check
7d3267
    tcp-check connect
7d3267
    server s1 127.0.0.1:22 check
7d3267
7d3267
The main reason for this issue is that the piece of code which validates
7d3267
that we're not at the end of the chained list (of rules) prevents
7d3267
executing the validation of the establishment of the TCP connection.
7d3267
Since validation is not executed, the rule is terminated and the report
7d3267
says no errors were encountered, hence the server is UP all the time.
7d3267
7d3267
The workaround is simple: move the connection validation outsied the
7d3267
CONNECT rule processing loop, into the main function.
7d3267
That way, if the connection status is not CONNECTED, then HAProxy will
7d3267
now add more time to wait for it. If the time is expired, an error is
7d3267
now well reported.
7d3267
---
7d3267
 src/checks.c | 19 +++++++++++++++++++
7d3267
 1 file changed, 19 insertions(+)
7d3267
7d3267
diff --git a/src/checks.c b/src/checks.c
7d3267
index 27a23b21..f280367b 100644
7d3267
--- a/src/checks.c
7d3267
+++ b/src/checks.c
7d3267
@@ -2246,6 +2246,25 @@ static void tcpcheck_main(struct connection *conn)
7d3267
 		} /* end expect */
7d3267
 	} /* end loop over double chained step list */
7d3267
 
7d3267
+	/* don't do anything until the connection is established */
7d3267
+	if (!(conn->flags & CO_FL_CONNECTED)) {
7d3267
+		/* update expire time, should be done by process_chk */
7d3267
+		/* we allow up to min(inter, timeout.connect) for a connection
7d3267
+		 * to establish but only when timeout.check is set
7d3267
+		 * as it may be to short for a full check otherwise
7d3267
+		 */
7d3267
+                while (tick_is_expired(t->expire, now_ms)) {
7d3267
+                        int t_con;
7d3267
+
7d3267
+                        t_con = tick_add(t->expire, s->proxy->timeout.connect);
7d3267
+                        t->expire = tick_add(t->expire, MS_TO_TICKS(check->inter));
7d3267
+
7d3267
+                        if (s->proxy->timeout.check)
7d3267
+                                t->expire = tick_first(t->expire, t_con);
7d3267
+                }
7d3267
+		return;
7d3267
+        }
7d3267
+
7d3267
 	/* We're waiting for some I/O to complete, we've reached the end of the
7d3267
 	 * rules, or both. Do what we have to do, otherwise we're done.
7d3267
 	 */
7d3267
-- 
7d3267
2.20.1
7d3267