mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
REORG: check: move the e-mail alerting code to mailers.c
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.
This commit is contained in:
parent
4f6535d734
commit
cee013e4e0
@ -25,44 +25,26 @@
|
||||
#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 */
|
||||
|
||||
/*
|
||||
|
@ -28,7 +28,14 @@
|
||||
#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 */
|
||||
|
@ -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>
|
||||
|
321
src/check.c
321
src/check.c
@ -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;
|
||||
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 ((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;
|
||||
REGISTER_SERVER_DEINIT(deinit_srv_check);
|
||||
REGISTER_SERVER_DEINIT(deinit_srv_agent_check);
|
||||
REGISTER_PROXY_DEINIT(deinit_proxy_tcpcheck);
|
||||
REGISTER_POST_DEINIT(deinit_tcpchecks);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/************************** Check sample fetches **************************/
|
||||
|
306
src/mailers.c
306
src/mailers.c
@ -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
|
||||
@ -12,6 +13,309 @@
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user