From 0108bb3e401e515d4c304600e822af0de2e45043 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Fri, 20 Oct 2017 21:34:32 +0200 Subject: [PATCH] MEDIUM: mailers: Init alerts during conf parsing and refactor their processing Email alerts relies on checks to send emails. The link between a mailers section and a proxy was resolved during the configuration parsing, But initialization was done when the first alert is triggered. This implied memory allocations and tasks creations. With this patch, everything is now initialized during the configuration parsing. So when an alert is triggered, only the memory required by this alert is dynamically allocated. Moreover, alerts processing had a flaw. The task handler used to process alerts to be sent to the same mailer, process_email_alert, was designed to give back the control to the scheduler when an alert was sent. So there was a delay between the sending of 2 consecutives alerts (the min of "proxy->timeout.connect" and "mailer->timeout.mail"). To fix this problem, now, we try to process as much queued alerts as possible when the task is woken up. --- include/proto/checks.h | 2 + include/types/proxy.h | 1 + src/cfgparse.c | 15 ++-- src/checks.c | 164 +++++++++++++++++++++-------------------- 4 files changed, 96 insertions(+), 86 deletions(-) diff --git a/include/proto/checks.h b/include/proto/checks.h index 853daad45..98dca25c7 100644 --- a/include/proto/checks.h +++ b/include/proto/checks.h @@ -24,6 +24,7 @@ #include #include +#include const char *get_check_status_description(short check_status); const char *get_check_status_info(short check_status); @@ -46,6 +47,7 @@ static inline void health_adjust(struct server *s, short status) 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))); int srv_check_healthcheck_port(struct check *chk); diff --git a/include/types/proxy.h b/include/types/proxy.h index 5306a3b6c..1130f2fae 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -228,6 +228,7 @@ struct error_snapshot { struct email_alert { struct list list; struct list tcpcheck_rules; + struct server *srv; }; struct email_alertq { diff --git a/src/cfgparse.c b/src/cfgparse.c index 8b1d8f8a2..4db59a368 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -7948,20 +7948,23 @@ int check_config_validity() struct mailers *curmailers = mailers; for (curmailers = mailers; curmailers; curmailers = curmailers->next) { - if (strcmp(curmailers->id, curproxy->email_alert.mailers.name) == 0) { - free(curproxy->email_alert.mailers.name); - curproxy->email_alert.mailers.m = curmailers; - curmailers->users++; + if (!strcmp(curmailers->id, curproxy->email_alert.mailers.name)) break; - } } - if (!curmailers) { Alert("Proxy '%s': unable to find mailers '%s'.\n", curproxy->id, curproxy->email_alert.mailers.name); free_email_alert(curproxy); cfgerr++; } + else { + err = NULL; + if (init_email_alert(curmailers, curproxy, &err)) { + Alert("Proxy '%s': %s.\n", curproxy->id, err); + free(err); + cfgerr++; + } + } } if (curproxy->uri_auth && !(curproxy->uri_auth->flags & ST_CONVDONE) && diff --git a/src/checks.c b/src/checks.c index d9c339343..6972f9cb6 100644 --- a/src/checks.c +++ b/src/checks.c @@ -37,7 +37,6 @@ #include #include -#include #include #include @@ -3051,95 +3050,117 @@ void email_alert_free(struct email_alert *alert) static struct task *process_email_alert(struct task *t) { - struct check *check = t->context; + struct check *check = t->context; struct email_alertq *q; + struct email_alert *alert; q = container_of(check, typeof(*q), check); - if (!(check->state & CHK_ST_ENABLED)) { - if (LIST_ISEMPTY(&q->email_alerts)) { - /* All alerts processed, delete check */ - task_delete(t); - task_free(t); - check->task = NULL; - return NULL; - } else { - struct email_alert *alert; + 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); + return t; + } alert = LIST_NEXT(&q->email_alerts, typeof(alert), list); - check->tcpcheck_rules = &alert->tcpcheck_rules; LIST_DEL(&alert->list); - - check->state |= CHK_ST_ENABLED; + t->expire = now_ms; + check->server = alert->srv; + check->tcpcheck_rules = &alert->tcpcheck_rules; + check->status = HCHK_STATUS_INI; + check->state |= CHK_ST_ENABLED; } - } - - process_chk(t); - - if (!(check->state & CHK_ST_INPROGRESS) && check->tcpcheck_rules) { - struct email_alert *alert; + process_chk(t); + if (check->state & CHK_ST_INPROGRESS) + break; alert = container_of(check->tcpcheck_rules, typeof(*alert), tcpcheck_rules); email_alert_free(alert); - check->tcpcheck_rules = NULL; - check->state &= ~CHK_ST_ENABLED; + check->server = NULL; + check->state &= ~CHK_ST_ENABLED; } return t; } -static int init_email_alert_checks(struct server *s) +/* Initializes mailer alerts for the proxy

using 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) { - int i; - struct mailer *mailer; - const char *err_str; - struct proxy *p = s->proxy; + struct mailer *mailer; + struct email_alertq *queues; + const char *err_str; + int i = 0; - if (p->email_alert.queues) - /* Already initialised, nothing to do */ - return 1; - - p->email_alert.queues = calloc(p->email_alert.mailers.m->count, sizeof *p->email_alert.queues); - if (!p->email_alert.queues) { - err_str = "out of memory while allocating checks array"; - goto error_alert; + if ((queues = calloc(mls->count, sizeof(*queues))) == NULL) { + memprintf(err, "out of memory while allocating mailer alerts queues"); + goto error; } - for (i = 0, mailer = p->email_alert.mailers.m->mailer_list; - i < p->email_alert.mailers.m->count; i++, mailer = mailer->next) { - struct email_alertq *q = &p->email_alert.queues[i]; - struct check *check = &q->check; - + 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); - check->inter = p->email_alert.mailers.m->timeout.mail; + check->inter = mls->timeout.mail; check->rise = DEF_AGENT_RISETIME; check->fall = DEF_AGENT_FALLTIME; - err_str = init_check(check, PR_O2_TCPCHK_CHK); - if (err_str) { - goto error_free; + 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; if (!get_host_port(&mailer->addr)) /* Default to submission port */ check->port = 587; - check->addr = mailer->addr; - check->server = s; + //check->server = s; + + if ((t = task_new()) == 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); } - return 1; - -error_free: - while (i-- > 1) - task_free(p->email_alert.queues[i].check.task); - free(p->email_alert.queues); - p->email_alert.queues = NULL; -error_alert: - Alert("Email alert [%s] could not be initialised: %s\n", p->id, err_str); + 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; + + if (check->task) { + task_delete(check->task); + task_free(check->task); + check->task = NULL; + } + free_check(check); + } + free(queues); + return 1; } @@ -3194,19 +3215,19 @@ static int add_tcpcheck_send_strs(struct list *list, const char * const *strs) return 1; } -static int enqueue_one_email_alert(struct email_alertq *q, const char *msg) +static int enqueue_one_email_alert(struct proxy *p, struct server *s, + struct email_alertq *q, const char *msg) { struct email_alert *alert = NULL; struct tcpcheck_rule *tcpcheck; struct check *check = &q->check; - struct proxy *p = check->server->proxy; alert = calloc(1, sizeof *alert); if (!alert) { goto error; } LIST_INIT(&alert->tcpcheck_rules); - + alert->srv = s; tcpcheck = calloc(1, sizeof *tcpcheck); if (!tcpcheck) goto error; @@ -3289,24 +3310,8 @@ static int enqueue_one_email_alert(struct email_alertq *q, const char *msg) if (!add_tcpcheck_expect_str(&alert->tcpcheck_rules, "221 ")) goto error; - if (!check->task) { - struct task *t; - - if ((t = task_new()) == NULL) - goto error; - - check->task = t; - t->process = process_email_alert; - t->context = check; - - /* check this in one ms */ - t->expire = tick_add(now_ms, MS_TO_TICKS(1)); - check->start = now; - task_queue(t); - } - + task_wakeup(check->task, TASK_WOKEN_MSG); LIST_ADDQ(&q->email_alerts, &alert->list); - return 1; error: @@ -3314,14 +3319,14 @@ error: return 0; } -static void enqueue_email_alert(struct proxy *p, const char *msg) +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->email_alert.queues[i], msg)) { + if (!enqueue_one_email_alert(p, s, &p->email_alert.queues[i], msg)) { Alert("Email alert [%s] could not be enqueued: out of memory\n", p->id); return; } @@ -3340,8 +3345,7 @@ void send_email_alert(struct server *s, int level, const char *format, ...) int len; struct proxy *p = s->proxy; - if (!p->email_alert.mailers.m || level > p->email_alert.level || - format == NULL || !init_email_alert_checks(s)) + if (!p->email_alert.mailers.m || level > p->email_alert.level || format == NULL) return; va_start(argp, format); @@ -3353,7 +3357,7 @@ void send_email_alert(struct server *s, int level, const char *format, ...) return; } - enqueue_email_alert(p, buf); + enqueue_email_alert(p, s, buf); } /*