]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: checks: Avoid having an associated server for email checks.
authorOlivier Houchard <ohouchard@haproxy.com>
Fri, 11 Jan 2019 17:43:04 +0000 (18:43 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 14 Jan 2019 10:15:11 +0000 (11:15 +0100)
When using a check to send email, avoid having an associated server, so that
we don't modify the server state if we fail to send an email.
Also revert back to initialize the check status to HCHK_STATUS_INI, now that
set_server_check_status() stops early if there's no server, we shouldn't
get in a mail loop anymore.

This should be backported to 1.9.

src/checks.c

index edb61b4f5a781edf2830410b9de70ae9cdcee237..1a81ccdb3763ff07a5c085a5c9c7380e17369e7d 100644 (file)
@@ -236,6 +236,11 @@ static void set_server_check_status(struct check *check, short status, const cha
        if (check->result == CHK_RES_NEUTRAL)
                return;
 
+       /* If the check was really just sending a mail, it won't have an
+        * associated server, so we're done now.
+        */
+       if (!s)
+           return;
        report = 0;
 
        switch (check->result) {
@@ -681,7 +686,8 @@ static void chk_report_conn_err(struct check *check, int errno_bck, int expired)
                 * might be due to a server IP change.
                 * Let's trigger a DNS resolution if none are currently running.
                 */
-               dns_trigger_resolution(check->server->dns_requester);
+               if (check->server)
+                       dns_trigger_resolution(check->server->dns_requester);
 
        }
        else if ((conn->flags & (CO_FL_CONNECTED|CO_FL_WAIT_L6_CONN)) == CO_FL_WAIT_L6_CONN) {
@@ -711,13 +717,20 @@ static struct task *event_srv_chk_io(struct task *t, void *ctx, unsigned short s
 {
        struct check *check = ctx;
        struct conn_stream *cs = check->cs;
+       struct email_alertq *q = container_of(check, typeof(*q), check);
 
        if (!(check->wait_list.events & SUB_RETRY_SEND))
                wake_srv_chk(cs);
        if (!(check->wait_list.events & SUB_RETRY_RECV)) {
-               HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock);
+               if (check->server)
+                       HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock);
+               else
+                       HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock);
                __event_srv_chk_r(cs);
-               HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);
+               if (check->server)
+                       HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);
+               else
+                       HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock);
        }
        return NULL;
 }
@@ -1394,9 +1407,13 @@ static int wake_srv_chk(struct conn_stream *cs)
 {
        struct connection *conn = cs->conn;
        struct check *check = cs->data;
+       struct email_alertq *q = container_of(check, typeof(*q), check);
        int ret = 0;
 
-       HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock);
+       if (check->server)
+               HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock);
+       else
+               HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock);
 
        /* we may have to make progress on the TCP checks */
        if (check->type == PR_O2_TCPCHK_CHK) {
@@ -1433,7 +1450,10 @@ static int wake_srv_chk(struct conn_stream *cs)
                ret = -1;
        }
 
-       HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);
+       if (check->server)
+               HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);
+       else
+               HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock);
 
        /* if a connection got replaced, we must absolutely prevent the connection
         * handler from touching its fd, and perform the FD polling updates ourselves
@@ -2131,7 +2151,8 @@ static struct task *process_chk_conn(struct task *t, void *context, unsigned sho
        int ret;
        int expired = tick_is_expired(t->expire, now_ms);
 
-       HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock);
+       if (check->server)
+               HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock);
        if (!(check->state & CHK_ST_INPROGRESS)) {
                /* no check currently running */
                if (!expired) /* woke up too early */
@@ -2257,34 +2278,39 @@ static struct task *process_chk_conn(struct task *t, void *context, unsigned sho
                        conn = NULL;
                }
 
-               if (check->result == CHK_RES_FAILED) {
-                       /* a failure or timeout detected */
-                       check_notify_failure(check);
-               }
-               else if (check->result == CHK_RES_CONDPASS) {
-                       /* check is OK but asks for stopping mode */
-                       check_notify_stopping(check);
-               }
-               else if (check->result == CHK_RES_PASSED) {
-                       /* a success was detected */
-                       check_notify_success(check);
+               if (check->server) {
+                       if (check->result == CHK_RES_FAILED) {
+                               /* a failure or timeout detected */
+                               check_notify_failure(check);
+                       }
+                       else if (check->result == CHK_RES_CONDPASS) {
+                               /* check is OK but asks for stopping mode */
+                               check_notify_stopping(check);
+                       }
+                       else if (check->result == CHK_RES_PASSED) {
+                               /* a success was detected */
+                               check_notify_success(check);
+                       }
                }
                task_set_affinity(t, MAX_THREADS_MASK);
                check->state &= ~CHK_ST_INPROGRESS;
 
-               rv = 0;
-               if (global.spread_checks > 0) {
-                       rv = srv_getinter(check) * global.spread_checks / 100;
-                       rv -= (int) (2 * rv * (rand() / (RAND_MAX + 1.0)));
+               if (check->server) {
+                       rv = 0;
+                       if (global.spread_checks > 0) {
+                               rv = srv_getinter(check) * global.spread_checks / 100;
+                               rv -= (int) (2 * rv * (rand() / (RAND_MAX + 1.0)));
+                       }
+                       t->expire = tick_add(now_ms, MS_TO_TICKS(srv_getinter(check) + rv));
                }
-               t->expire = tick_add(now_ms, MS_TO_TICKS(srv_getinter(check) + rv));
        }
 
  reschedule:
        while (tick_is_expired(t->expire, now_ms))
                t->expire = tick_add(t->expire, MS_TO_TICKS(check->inter));
  out_unlock:
-       HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);
+       if (check->server)
+               HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);
        return t;
 }
 
@@ -2760,7 +2786,7 @@ static int tcpcheck_main(struct check *check)
                        conn = cs->conn;
                        /* Maybe there were an older connection we were waiting on */
                        check->wait_list.events = 0;
-                       conn->target = &s->obj_type;
+                       conn->target = s ? &s->obj_type : &proxy->obj_type;
 
                        /* no client address */
                        clear_addr(&conn->addr.from);
@@ -3173,9 +3199,8 @@ static struct task *process_email_alert(struct task *t, void *context, unsigned
                        alert = LIST_NEXT(&q->email_alerts, typeof(alert), list);
                        LIST_DEL(&alert->list);
                        t->expire             = now_ms;
-                       check->server         = alert->srv;
                        check->tcpcheck_rules = &alert->tcpcheck_rules;
-                       check->status         = HCHK_STATUS_UNKNOWN; // the UNKNOWN status is used to exit set_server_check_status(.) early
+                       check->status         = HCHK_STATUS_INI;
                        check->state         |= CHK_ST_ENABLED;
                }
 
@@ -3230,7 +3255,6 @@ int init_email_alert(struct mailers *mls, struct proxy *p, char **err)
                check->xprt = mailer->xprt;
                check->addr = mailer->addr;
                check->port = get_host_port(&mailer->addr);
-               //check->server = s;
 
                if ((t = task_new(MAX_THREADS_MASK)) == NULL) {
                        memprintf(err, "out of memory while allocating mailer alerts task");