]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: check: move the e-mail alerting code to mailers.c
authorWilly Tarreau <w@1wt.eu>
Fri, 5 Jun 2020 09:40:38 +0000 (11:40 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 11 Jun 2020 08:18:58 +0000 (10:18 +0200)
check.c is one of the largest file and contains too many things. The
e-mail alerting code is stored there while nothing is in mailers.c.
Let's move this code out. That's only 4% of the code but a good start.
In order to do so, a few tcp-check functions had to be exported.

include/haproxy/check.h
include/haproxy/mailers.h
src/cfgparse.c
src/check.c
src/mailers.c
src/server.c

index 66023ce5999d7add2f62d608e05ef5f7c12c18d5..637909cb54bcd935419cc991e7943cba95eb67a3 100644 (file)
 #include <haproxy/action-t.h>
 #include <haproxy/check-t.h>
 #include <haproxy/list-t.h>
-#include <haproxy/mailers.h>
 #include <haproxy/proxy-t.h>
 #include <haproxy/server-t.h>
 
+extern struct action_kw_list tcp_check_keywords;
+extern struct pool_head *pool_head_tcpcheck_rule;
+
 const char *get_check_status_description(short check_status);
 const char *get_check_status_info(short check_status);
 void __health_adjust(struct server *s, short status);
+struct task *process_chk(struct task *t, void *context, unsigned short state);
 
-/* Use this one only. This inline version only ensures that we don't
- * call the function when the observe mode is disabled.
- */
-static inline void health_adjust(struct server *s, short status)
-{
-       HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
-       /* return now if observing nor health check is not enabled */
-       if (!s->observe || !s->check.task) {
-               HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
-               return;
-       }
-
-       __health_adjust(s, status);
-       HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
-}
-
+const char *init_check(struct check *check, int type);
 void free_check(struct check *check);
-
-int init_email_alert(struct mailers *mailers, struct proxy *p, char **err);
-void send_email_alert(struct server *s, int priority, const char *format, ...)
-       __attribute__ ((format(printf, 3, 4)));
-
-extern struct action_kw_list tcp_check_keywords;
-static inline void tcp_check_keywords_register(struct action_kw_list *kw_list)
-{
-       LIST_ADDQ(&tcp_check_keywords.list, &kw_list->list);
-}
+void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool);
 
 void deinit_proxy_tcpcheck(struct proxy *px);
 int dup_tcpcheck_vars(struct list *dst, struct list *src);
+void free_tcpcheck_vars(struct list *vars);
+int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str);
+int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * const *strs);
 
 /* Declared here, but the definitions are in flt_spoe.c */
 int spoe_prepare_healthcheck_request(char **req, int *len);
@@ -91,6 +73,27 @@ int proxy_parse_external_check_opt(char **args, int cur_arg, struct proxy *curpx
 
 int set_srv_agent_send(struct server *srv, const char *send);
 
+/* Use this one only. This inline version only ensures that we don't
+ * call the function when the observe mode is disabled.
+ */
+static inline void health_adjust(struct server *s, short status)
+{
+       HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
+       /* return now if observing nor health check is not enabled */
+       if (!s->observe || !s->check.task) {
+               HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
+               return;
+       }
+
+       __health_adjust(s, status);
+       HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
+}
+
+static inline void tcp_check_keywords_register(struct action_kw_list *kw_list)
+{
+       LIST_ADDQ(&tcp_check_keywords.list, &kw_list->list);
+}
+
 #endif /* _HAPROXY_CHECKS_H */
 
 /*
index 5daad862f2272bfc8e5af021ae7ba4d54540282f..43db167b6f11818417e9e7fcfc2ce792d09193db 100644 (file)
 #define _HAPROXY_MAILERS_H
 
 #include <haproxy/mailers-t.h>
+#include <haproxy/proxy-t.h>
+#include <haproxy/server-t.h>
 
 extern struct mailers *mailers;
 
+int init_email_alert(struct mailers *mailers, struct proxy *p, char **err);
+void send_email_alert(struct server *s, int priority, const char *format, ...)
+       __attribute__ ((format(printf, 3, 4)));
+
+
 #endif /* _HAPROXY_MAILERS_H */
index 0bb4f2bbc39df8509c42228d6329f7dcd05e0597..fa85401872bd542fcda4a110dddedf664a8a62e8 100644 (file)
@@ -57,7 +57,7 @@
 #include <haproxy/lb_map.h>
 #include <haproxy/listener.h>
 #include <haproxy/log.h>
-#include <haproxy/mailers-t.h>
+#include <haproxy/mailers.h>
 #include <haproxy/obj_type-t.h>
 #include <haproxy/peers-t.h>
 #include <haproxy/pool.h>
index f8df0e9f06d51adb83c44183fb2c46bc2379011c..fa608c9df27bb09cb919bba687a00ffc433fa1a0 100644 (file)
@@ -38,6 +38,7 @@
 #include <haproxy/dns.h>
 #include <haproxy/istbuf.h>
 #include <haproxy/list.h>
+#include <haproxy/mailers.h>
 #include <haproxy/queue.h>
 #include <haproxy/regex.h>
 #include <haproxy/tools.h>
@@ -79,8 +80,7 @@ struct data_cb check_conn_cb = {
 struct eb_root shared_tcpchecks = EB_ROOT;
 
 
-DECLARE_STATIC_POOL(pool_head_email_alert,   "email_alert",   sizeof(struct email_alert));
-DECLARE_STATIC_POOL(pool_head_tcpcheck_rule, "tcpcheck_rule", sizeof(struct tcpcheck_rule));
+DECLARE_POOL(pool_head_tcpcheck_rule, "tcpcheck_rule", sizeof(struct tcpcheck_rule));
 
 /* Dummy frontend used to create all checks sessions. */
 static struct proxy checks_fe;
@@ -751,7 +751,7 @@ static void free_tcpcheck_http_hdrs(struct list *hdrs)
  * tcp-check was allocated using a memory pool (it is used to instantiate email
  * alerts).
  */
-static void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool)
+void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool)
 {
        if (!rule)
                return;
@@ -883,7 +883,7 @@ static void free_tcpcheck_var(struct tcpcheck_var *var)
 }
 
 /* Releases a list of preset tcp-check variables */
-static void free_tcpcheck_vars(struct list *vars)
+void free_tcpcheck_vars(struct list *vars)
 {
        struct tcpcheck_var *var, *back;
 
@@ -4939,7 +4939,7 @@ static int tcpcheck_add_http_rule(struct tcpcheck_rule *chk, struct tcpcheck_rul
 /**************************************************************************/
 /************************** Init/deinit checks ****************************/
 /**************************************************************************/
-static const char *init_check(struct check *check, int type)
+const char *init_check(struct check *check, int type)
 {
        check->type = type;
 
@@ -4980,7 +4980,7 @@ void free_check(struct check *check)
 /* manages a server health-check. Returns the time the task accepts to wait, or
  * TIME_ETERNITY for infinity.
  */
-static struct task *process_chk(struct task *t, void *context, unsigned short state)
+struct task *process_chk(struct task *t, void *context, unsigned short state)
 {
        struct check *check = context;
 
@@ -5531,153 +5531,7 @@ static void deinit_tcpchecks()
        }
 }
 
-
-REGISTER_POST_SERVER_CHECK(init_srv_check);
-REGISTER_POST_SERVER_CHECK(init_srv_agent_check);
-REGISTER_POST_PROXY_CHECK(check_proxy_tcpcheck);
-REGISTER_POST_CHECK(start_checks);
-
-REGISTER_SERVER_DEINIT(deinit_srv_check);
-REGISTER_SERVER_DEINIT(deinit_srv_agent_check);
-REGISTER_PROXY_DEINIT(deinit_proxy_tcpcheck);
-REGISTER_POST_DEINIT(deinit_tcpchecks);
-
-/**************************************************************************/
-/****************************** Email alerts ******************************/
-/* NOTE: It may be pertinent to use an applet to handle email alerts      */
-/*        instead of a tcp-check ruleset                                  */
-/**************************************************************************/
-void email_alert_free(struct email_alert *alert)
-{
-       struct tcpcheck_rule *rule, *back;
-
-       if (!alert)
-               return;
-
-       if (alert->rules.list) {
-               list_for_each_entry_safe(rule, back, alert->rules.list, list) {
-                       LIST_DEL(&rule->list);
-                       free_tcpcheck(rule, 1);
-               }
-               free_tcpcheck_vars(&alert->rules.preset_vars);
-               free(alert->rules.list);
-               alert->rules.list = NULL;
-       }
-       pool_free(pool_head_email_alert, alert);
-}
-
-static struct task *process_email_alert(struct task *t, void *context, unsigned short state)
-{
-       struct check        *check = context;
-       struct email_alertq *q;
-       struct email_alert  *alert;
-
-       q = container_of(check, typeof(*q), check);
-
-       HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock);
-       while (1) {
-               if (!(check->state & CHK_ST_ENABLED)) {
-                       if (LIST_ISEMPTY(&q->email_alerts)) {
-                               /* All alerts processed, queue the task */
-                               t->expire = TICK_ETERNITY;
-                               task_queue(t);
-                               goto end;
-                       }
-
-                       alert = LIST_NEXT(&q->email_alerts, typeof(alert), list);
-                       LIST_DEL(&alert->list);
-                       t->expire             = now_ms;
-                       check->tcpcheck_rules = &alert->rules;
-                       check->status         = HCHK_STATUS_INI;
-                       check->state         |= CHK_ST_ENABLED;
-               }
-
-               process_chk(t, context, state);
-               if (check->state & CHK_ST_INPROGRESS)
-                       break;
-
-               alert = container_of(check->tcpcheck_rules, typeof(*alert), rules);
-               email_alert_free(alert);
-               check->tcpcheck_rules = NULL;
-               check->server         = NULL;
-               check->state         &= ~CHK_ST_ENABLED;
-       }
-  end:
-       HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock);
-       return t;
-}
-
-/* Initializes mailer alerts for the proxy <p> using <mls> parameters.
- *
- * The function returns 1 in success case, otherwise, it returns 0 and err is
- * filled.
- */
-int init_email_alert(struct mailers *mls, struct proxy *p, char **err)
-{
-       struct mailer       *mailer;
-       struct email_alertq *queues;
-       const char          *err_str;
-       int                  i = 0;
-
-       if ((queues = calloc(mls->count, sizeof(*queues))) == NULL) {
-               memprintf(err, "out of memory while allocating mailer alerts queues");
-               goto fail_no_queue;
-       }
-
-       for (mailer = mls->mailer_list; mailer; i++, mailer = mailer->next) {
-               struct email_alertq *q     = &queues[i];
-               struct check        *check = &q->check;
-               struct task         *t;
-
-               LIST_INIT(&q->email_alerts);
-               HA_SPIN_INIT(&q->lock);
-               check->inter = mls->timeout.mail;
-               check->rise = DEF_AGENT_RISETIME;
-               check->proxy = p;
-               check->fall = DEF_AGENT_FALLTIME;
-               if ((err_str = init_check(check, PR_O2_TCPCHK_CHK))) {
-                       memprintf(err, "%s", err_str);
-                       goto error;
-               }
-
-               check->xprt = mailer->xprt;
-               check->addr = mailer->addr;
-               check->port = get_host_port(&mailer->addr);
-
-               if ((t = task_new(MAX_THREADS_MASK)) == NULL) {
-                       memprintf(err, "out of memory while allocating mailer alerts task");
-                       goto error;
-               }
-
-               check->task = t;
-               t->process = process_email_alert;
-               t->context = check;
-
-               /* check this in one ms */
-               t->expire    = TICK_ETERNITY;
-               check->start = now;
-               task_queue(t);
-       }
-
-       mls->users++;
-       free(p->email_alert.mailers.name);
-       p->email_alert.mailers.m = mls;
-       p->email_alert.queues    = queues;
-       return 0;
-
-  error:
-       for (i = 0; i < mls->count; i++) {
-               struct email_alertq *q     = &queues[i];
-               struct check        *check = &q->check;
-
-               free_check(check);
-       }
-       free(queues);
-  fail_no_queue:
-       return 1;
-}
-
-static int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str)
+int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str)
 {
        struct tcpcheck_rule *tcpcheck, *prev_check;
        struct tcpcheck_expect *expect;
@@ -5717,7 +5571,7 @@ static int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str
        return 1;
 }
 
-static int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * const *strs)
+int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * const *strs)
 {
        struct tcpcheck_rule *tcpcheck;
        struct tcpcheck_send *send;
@@ -5751,159 +5605,16 @@ static int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * con
        return 1;
 }
 
-static int enqueue_one_email_alert(struct proxy *p, struct server *s,
-                                  struct email_alertq *q, const char *msg)
-{
-       struct email_alert   *alert;
-       struct tcpcheck_rule *tcpcheck;
-       struct check *check = &q->check;
-
-       if ((alert = pool_alloc(pool_head_email_alert)) == NULL)
-               goto error;
-       LIST_INIT(&alert->list);
-       alert->rules.flags = TCPCHK_RULES_TCP_CHK;
-       alert->rules.list = calloc(1, sizeof(*alert->rules.list));
-       if (!alert->rules.list)
-               goto error;
-       LIST_INIT(alert->rules.list);
-       LIST_INIT(&alert->rules.preset_vars); /* unused for email alerts */
-       alert->srv = s;
-
-       if ((tcpcheck = pool_alloc(pool_head_tcpcheck_rule)) == NULL)
-               goto error;
-       memset(tcpcheck, 0, sizeof(*tcpcheck));
-       tcpcheck->action       = TCPCHK_ACT_CONNECT;
-       tcpcheck->comment      = NULL;
-
-       LIST_ADDQ(alert->rules.list, &tcpcheck->list);
-
-       if (!add_tcpcheck_expect_str(&alert->rules, "220 "))
-               goto error;
-
-       {
-               const char * const strs[4] = { "EHLO ", p->email_alert.myhostname, "\r\n" };
-               if (!add_tcpcheck_send_strs(&alert->rules, strs))
-                       goto error;
-       }
-
-       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
-               goto error;
-
-       {
-               const char * const strs[4] = { "MAIL FROM:<", p->email_alert.from, ">\r\n" };
-               if (!add_tcpcheck_send_strs(&alert->rules, strs))
-                       goto error;
-       }
-
-       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
-               goto error;
-
-       {
-               const char * const strs[4] = { "RCPT TO:<", p->email_alert.to, ">\r\n" };
-               if (!add_tcpcheck_send_strs(&alert->rules, strs))
-                       goto error;
-       }
-
-       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
-               goto error;
-
-       {
-               const char * const strs[2] = { "DATA\r\n" };
-               if (!add_tcpcheck_send_strs(&alert->rules, strs))
-                       goto error;
-       }
-
-       if (!add_tcpcheck_expect_str(&alert->rules, "354 "))
-               goto error;
-
-       {
-               struct tm tm;
-               char datestr[48];
-               const char * const strs[18] = {
-                       "From: ", p->email_alert.from, "\r\n",
-                       "To: ", p->email_alert.to, "\r\n",
-                       "Date: ", datestr, "\r\n",
-                       "Subject: [HAproxy Alert] ", msg, "\r\n",
-                       "\r\n",
-                       msg, "\r\n",
-                       "\r\n",
-                       ".\r\n",
-                       NULL
-               };
-
-               get_localtime(date.tv_sec, &tm);
-
-               if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %T %z (%Z)", &tm) == 0) {
-                       goto error;
-               }
-
-               if (!add_tcpcheck_send_strs(&alert->rules, strs))
-                       goto error;
-       }
-
-       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
-               goto error;
-
-       {
-               const char * const strs[2] = { "QUIT\r\n" };
-               if (!add_tcpcheck_send_strs(&alert->rules, strs))
-                       goto error;
-       }
-
-       if (!add_tcpcheck_expect_str(&alert->rules, "221 "))
-               goto error;
-
-       HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock);
-       task_wakeup(check->task, TASK_WOKEN_MSG);
-       LIST_ADDQ(&q->email_alerts, &alert->list);
-       HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock);
-       return 1;
-
-error:
-       email_alert_free(alert);
-       return 0;
-}
-
-static void enqueue_email_alert(struct proxy *p, struct server *s, const char *msg)
-{
-       int i;
-       struct mailer *mailer;
-
-       for (i = 0, mailer = p->email_alert.mailers.m->mailer_list;
-            i < p->email_alert.mailers.m->count; i++, mailer = mailer->next) {
-               if (!enqueue_one_email_alert(p, s, &p->email_alert.queues[i], msg)) {
-                       ha_alert("Email alert [%s] could not be enqueued: out of memory\n", p->id);
-                       return;
-               }
-       }
-
-       return;
-}
-
-/*
- * Send email alert if configured.
- */
-void send_email_alert(struct server *s, int level, const char *format, ...)
-{
-       va_list argp;
-       char buf[1024];
-       int len;
-       struct proxy *p = s->proxy;
-
-       if (!p->email_alert.mailers.m || level > p->email_alert.level || format == NULL)
-               return;
-
-       va_start(argp, format);
-       len = vsnprintf(buf, sizeof(buf), format, argp);
-       va_end(argp);
+REGISTER_POST_SERVER_CHECK(init_srv_check);
+REGISTER_POST_SERVER_CHECK(init_srv_agent_check);
+REGISTER_POST_PROXY_CHECK(check_proxy_tcpcheck);
+REGISTER_POST_CHECK(start_checks);
 
-       if (len < 0 || len >= sizeof(buf)) {
-               ha_alert("Email alert [%s] could not format message\n", p->id);
-               return;
-       }
+REGISTER_SERVER_DEINIT(deinit_srv_check);
+REGISTER_SERVER_DEINIT(deinit_srv_agent_check);
+REGISTER_PROXY_DEINIT(deinit_proxy_tcpcheck);
+REGISTER_POST_DEINIT(deinit_tcpchecks);
 
-       enqueue_email_alert(p, s, buf);
-}
 
 /**************************************************************************/
 /************************** Check sample fetches **************************/
index 601489481ae213103778bbc87f433bbf7806000b..39818ca0bee90edae51a9825e77d7f74c3922d38 100644 (file)
@@ -2,6 +2,7 @@
  * Mailer management.
  *
  * Copyright 2015 Horms Solutions Ltd, Simon Horman <horms@verge.net.au>
+ * Copyright 2020 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 
 #include <stdlib.h>
 
-#include <haproxy/mailers-t.h>
+#include <haproxy/action-t.h>
+#include <haproxy/api.h>
+#include <haproxy/check.h>
+#include <haproxy/list.h>
+#include <haproxy/mailers.h>
+#include <haproxy/pool.h>
+#include <haproxy/tools.h>
+#include <haproxy/time.h>
+#include <haproxy/thread.h>
+#include <haproxy/log.h>
+#include <haproxy/proxy-t.h>
+#include <haproxy/server-t.h>
+#include <haproxy/task.h>
+
 
 struct mailers *mailers = NULL;
+
+DECLARE_STATIC_POOL(pool_head_email_alert,   "email_alert",   sizeof(struct email_alert));
+
+/****************************** Email alerts ******************************/
+/* NOTE: It may be pertinent to use an applet to handle email alerts      */
+/*        instead of a tcp-check ruleset                                  */
+/**************************************************************************/
+void email_alert_free(struct email_alert *alert)
+{
+       struct tcpcheck_rule *rule, *back;
+
+       if (!alert)
+               return;
+
+       if (alert->rules.list) {
+               list_for_each_entry_safe(rule, back, alert->rules.list, list) {
+                       LIST_DEL(&rule->list);
+                       free_tcpcheck(rule, 1);
+               }
+               free_tcpcheck_vars(&alert->rules.preset_vars);
+               free(alert->rules.list);
+               alert->rules.list = NULL;
+       }
+       pool_free(pool_head_email_alert, alert);
+}
+
+static struct task *process_email_alert(struct task *t, void *context, unsigned short state)
+{
+       struct check        *check = context;
+       struct email_alertq *q;
+       struct email_alert  *alert;
+
+       q = container_of(check, typeof(*q), check);
+
+       HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock);
+       while (1) {
+               if (!(check->state & CHK_ST_ENABLED)) {
+                       if (LIST_ISEMPTY(&q->email_alerts)) {
+                               /* All alerts processed, queue the task */
+                               t->expire = TICK_ETERNITY;
+                               task_queue(t);
+                               goto end;
+                       }
+
+                       alert = LIST_NEXT(&q->email_alerts, typeof(alert), list);
+                       LIST_DEL(&alert->list);
+                       t->expire             = now_ms;
+                       check->tcpcheck_rules = &alert->rules;
+                       check->status         = HCHK_STATUS_INI;
+                       check->state         |= CHK_ST_ENABLED;
+               }
+
+               process_chk(t, context, state);
+               if (check->state & CHK_ST_INPROGRESS)
+                       break;
+
+               alert = container_of(check->tcpcheck_rules, typeof(*alert), rules);
+               email_alert_free(alert);
+               check->tcpcheck_rules = NULL;
+               check->server         = NULL;
+               check->state         &= ~CHK_ST_ENABLED;
+       }
+  end:
+       HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock);
+       return t;
+}
+
+/* Initializes mailer alerts for the proxy <p> using <mls> parameters.
+ *
+ * The function returns 1 in success case, otherwise, it returns 0 and err is
+ * filled.
+ */
+int init_email_alert(struct mailers *mls, struct proxy *p, char **err)
+{
+       struct mailer       *mailer;
+       struct email_alertq *queues;
+       const char          *err_str;
+       int                  i = 0;
+
+       if ((queues = calloc(mls->count, sizeof(*queues))) == NULL) {
+               memprintf(err, "out of memory while allocating mailer alerts queues");
+               goto fail_no_queue;
+       }
+
+       for (mailer = mls->mailer_list; mailer; i++, mailer = mailer->next) {
+               struct email_alertq *q     = &queues[i];
+               struct check        *check = &q->check;
+               struct task         *t;
+
+               LIST_INIT(&q->email_alerts);
+               HA_SPIN_INIT(&q->lock);
+               check->inter = mls->timeout.mail;
+               check->rise = DEF_AGENT_RISETIME;
+               check->proxy = p;
+               check->fall = DEF_AGENT_FALLTIME;
+               if ((err_str = init_check(check, PR_O2_TCPCHK_CHK))) {
+                       memprintf(err, "%s", err_str);
+                       goto error;
+               }
+
+               check->xprt = mailer->xprt;
+               check->addr = mailer->addr;
+               check->port = get_host_port(&mailer->addr);
+
+               if ((t = task_new(MAX_THREADS_MASK)) == NULL) {
+                       memprintf(err, "out of memory while allocating mailer alerts task");
+                       goto error;
+               }
+
+               check->task = t;
+               t->process = process_email_alert;
+               t->context = check;
+
+               /* check this in one ms */
+               t->expire    = TICK_ETERNITY;
+               check->start = now;
+               task_queue(t);
+       }
+
+       mls->users++;
+       free(p->email_alert.mailers.name);
+       p->email_alert.mailers.m = mls;
+       p->email_alert.queues    = queues;
+       return 0;
+
+  error:
+       for (i = 0; i < mls->count; i++) {
+               struct email_alertq *q     = &queues[i];
+               struct check        *check = &q->check;
+
+               free_check(check);
+       }
+       free(queues);
+  fail_no_queue:
+       return 1;
+}
+
+static int enqueue_one_email_alert(struct proxy *p, struct server *s,
+                                  struct email_alertq *q, const char *msg)
+{
+       struct email_alert   *alert;
+       struct tcpcheck_rule *tcpcheck;
+       struct check *check = &q->check;
+
+       if ((alert = pool_alloc(pool_head_email_alert)) == NULL)
+               goto error;
+       LIST_INIT(&alert->list);
+       alert->rules.flags = TCPCHK_RULES_TCP_CHK;
+       alert->rules.list = calloc(1, sizeof(*alert->rules.list));
+       if (!alert->rules.list)
+               goto error;
+       LIST_INIT(alert->rules.list);
+       LIST_INIT(&alert->rules.preset_vars); /* unused for email alerts */
+       alert->srv = s;
+
+       if ((tcpcheck = pool_alloc(pool_head_tcpcheck_rule)) == NULL)
+               goto error;
+       memset(tcpcheck, 0, sizeof(*tcpcheck));
+       tcpcheck->action       = TCPCHK_ACT_CONNECT;
+       tcpcheck->comment      = NULL;
+
+       LIST_ADDQ(alert->rules.list, &tcpcheck->list);
+
+       if (!add_tcpcheck_expect_str(&alert->rules, "220 "))
+               goto error;
+
+       {
+               const char * const strs[4] = { "EHLO ", p->email_alert.myhostname, "\r\n" };
+               if (!add_tcpcheck_send_strs(&alert->rules, strs))
+                       goto error;
+       }
+
+       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
+               goto error;
+
+       {
+               const char * const strs[4] = { "MAIL FROM:<", p->email_alert.from, ">\r\n" };
+               if (!add_tcpcheck_send_strs(&alert->rules, strs))
+                       goto error;
+       }
+
+       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
+               goto error;
+
+       {
+               const char * const strs[4] = { "RCPT TO:<", p->email_alert.to, ">\r\n" };
+               if (!add_tcpcheck_send_strs(&alert->rules, strs))
+                       goto error;
+       }
+
+       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
+               goto error;
+
+       {
+               const char * const strs[2] = { "DATA\r\n" };
+               if (!add_tcpcheck_send_strs(&alert->rules, strs))
+                       goto error;
+       }
+
+       if (!add_tcpcheck_expect_str(&alert->rules, "354 "))
+               goto error;
+
+       {
+               struct tm tm;
+               char datestr[48];
+               const char * const strs[18] = {
+                       "From: ", p->email_alert.from, "\r\n",
+                       "To: ", p->email_alert.to, "\r\n",
+                       "Date: ", datestr, "\r\n",
+                       "Subject: [HAproxy Alert] ", msg, "\r\n",
+                       "\r\n",
+                       msg, "\r\n",
+                       "\r\n",
+                       ".\r\n",
+                       NULL
+               };
+
+               get_localtime(date.tv_sec, &tm);
+
+               if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %T %z (%Z)", &tm) == 0) {
+                       goto error;
+               }
+
+               if (!add_tcpcheck_send_strs(&alert->rules, strs))
+                       goto error;
+       }
+
+       if (!add_tcpcheck_expect_str(&alert->rules, "250 "))
+               goto error;
+
+       {
+               const char * const strs[2] = { "QUIT\r\n" };
+               if (!add_tcpcheck_send_strs(&alert->rules, strs))
+                       goto error;
+       }
+
+       if (!add_tcpcheck_expect_str(&alert->rules, "221 "))
+               goto error;
+
+       HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock);
+       task_wakeup(check->task, TASK_WOKEN_MSG);
+       LIST_ADDQ(&q->email_alerts, &alert->list);
+       HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock);
+       return 1;
+
+error:
+       email_alert_free(alert);
+       return 0;
+}
+
+static void enqueue_email_alert(struct proxy *p, struct server *s, const char *msg)
+{
+       int i;
+       struct mailer *mailer;
+
+       for (i = 0, mailer = p->email_alert.mailers.m->mailer_list;
+            i < p->email_alert.mailers.m->count; i++, mailer = mailer->next) {
+               if (!enqueue_one_email_alert(p, s, &p->email_alert.queues[i], msg)) {
+                       ha_alert("Email alert [%s] could not be enqueued: out of memory\n", p->id);
+                       return;
+               }
+       }
+
+       return;
+}
+
+/*
+ * Send email alert if configured.
+ */
+void send_email_alert(struct server *s, int level, const char *format, ...)
+{
+       va_list argp;
+       char buf[1024];
+       int len;
+       struct proxy *p = s->proxy;
+
+       if (!p->email_alert.mailers.m || level > p->email_alert.level || format == NULL)
+               return;
+
+       va_start(argp, format);
+       len = vsnprintf(buf, sizeof(buf), format, argp);
+       va_end(argp);
+
+       if (len < 0 || len >= sizeof(buf)) {
+               ha_alert("Email alert [%s] could not format message\n", p->id);
+               return;
+       }
+
+       enqueue_email_alert(p, s, buf);
+}
index 0d9b533037e5d223ac1620627b44107447566c0a..b2c2853fc7e632f5f9c3ed5c8d3cc5560ac1a91b 100644 (file)
@@ -27,6 +27,7 @@
 #include <haproxy/dns.h>
 #include <haproxy/errors.h>
 #include <haproxy/global.h>
+#include <haproxy/mailers.h>
 #include <haproxy/namespace.h>
 #include <haproxy/queue.h>
 #include <haproxy/sample.h>