1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21
22 #include "db.h"
23 #include "log.h"
24 #include "daemon.h"
25 #include "zbxself.h"
26 #include "zbxalgo.h"
27
28 #include "../alerter/alerter.h"
29
30 #include "watchdog.h"
31
32 #define STR_REPLACE(str1, str2) if (NULL == str1 || 0 != strcmp(str1, str2)) str1 = zbx_strdup(str1, str2)
33
34 #define ALERT_FREQUENCY (15 * SEC_PER_MIN)
35 #define DB_PING_FREQUENCY SEC_PER_MIN
36
37 typedef struct
38 {
39 DB_ALERT alert;
40 DB_MEDIATYPE mediatype;
41 }
42 ZBX_RECIPIENT;
43
44 static zbx_vector_ptr_t recipients;
45 static int lastsent = 0;
46
47 extern int CONFIG_CONFSYNCER_FREQUENCY;
48 extern unsigned char process_type, program_type;
49 extern int server_num, process_num;
50
51 /******************************************************************************
52 * *
53 * Function: send_alerts *
54 * *
55 * Purpose: send warning message to all interested *
56 * *
57 * Author: Alexei Vladishev *
58 * *
59 * Comments: messages are sent only every ALERT_FREQUENCY seconds *
60 * *
61 ******************************************************************************/
send_alerts(void)62 static void send_alerts(void)
63 {
64 int i, now;
65 char error[MAX_STRING_LEN];
66
67 now = time(NULL);
68
69 if (now > lastsent + ALERT_FREQUENCY)
70 {
71 for (i = 0; i < recipients.values_num; i++)
72 {
73 execute_action(&((ZBX_RECIPIENT *)recipients.values[i])->alert,
74 &((ZBX_RECIPIENT *)recipients.values[i])->mediatype, error, sizeof(error));
75 }
76
77 lastsent = now;
78 }
79 }
80
81 /******************************************************************************
82 * *
83 * Function: sync_config *
84 * *
85 * Purpose: sync list of medias to send notifications in case if DB is down *
86 * *
87 * Author: Alexei Vladishev, Rudolfs Kreicbergs *
88 * *
89 ******************************************************************************/
sync_config(void)90 static void sync_config(void)
91 {
92 const char *__function_name = "sync_config";
93
94 DB_RESULT result;
95 DB_ROW row;
96 ZBX_RECIPIENT *recipient;
97 int count = 0, old_count;
98 static int no_recipients = 0;
99
100 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
101
102 result = DBselect_once(
103 "select mt.mediatypeid,mt.type,mt.description,mt.smtp_server,mt.smtp_helo,mt.smtp_email,"
104 "mt.exec_path,mt.gsm_modem,mt.username,mt.passwd,mt.smtp_port,mt.smtp_security,"
105 "mt.smtp_verify_peer,mt.smtp_verify_host,mt.smtp_authentication,mt.exec_params,m.sendto"
106 " from media m,users_groups u,config c,media_type mt"
107 " where m.userid=u.userid"
108 " and u.usrgrpid=c.alert_usrgrpid"
109 " and m.mediatypeid=mt.mediatypeid"
110 " and m.active=%d"
111 " and mt.status=%d",
112 MEDIA_STATUS_ACTIVE,
113 MEDIA_TYPE_STATUS_ACTIVE);
114
115 if (NULL == result || (DB_RESULT)ZBX_DB_DOWN == result)
116 {
117 zabbix_log(LOG_LEVEL_WARNING, "watchdog: database is down");
118 send_alerts();
119 goto exit;
120 }
121
122 old_count = recipients.values_num;
123
124 while (NULL != (row = DBfetch(result)))
125 {
126 /* add the recipients to the list */
127
128 if (count >= recipients.values_num)
129 {
130 recipient = zbx_calloc(NULL, 1, sizeof(ZBX_RECIPIENT));
131 zbx_vector_ptr_append(&recipients, recipient);
132 }
133 else
134 recipient = recipients.values[count];
135
136 ZBX_STR2UINT64(recipient->mediatype.mediatypeid, row[0]);
137 recipient->mediatype.type = atoi(row[1]);
138
139 /* the recipients are likely to be the same, change only what's different */
140
141 STR_REPLACE(recipient->mediatype.description, row[2]);
142 STR_REPLACE(recipient->mediatype.smtp_server, row[3]);
143 STR_REPLACE(recipient->mediatype.smtp_helo, row[4]);
144 STR_REPLACE(recipient->mediatype.smtp_email, row[5]);
145 STR_REPLACE(recipient->mediatype.exec_path, row[6]);
146 STR_REPLACE(recipient->mediatype.exec_params, row[15]);
147 STR_REPLACE(recipient->mediatype.gsm_modem, row[7]);
148 STR_REPLACE(recipient->mediatype.username, row[8]);
149 STR_REPLACE(recipient->mediatype.passwd, row[9]);
150 recipient->mediatype.smtp_port = (unsigned short)atoi(row[10]);
151 ZBX_STR2UCHAR(recipient->mediatype.smtp_security, row[11]);
152 ZBX_STR2UCHAR(recipient->mediatype.smtp_verify_peer, row[12]);
153 ZBX_STR2UCHAR(recipient->mediatype.smtp_verify_host, row[13]);
154 ZBX_STR2UCHAR(recipient->mediatype.smtp_authentication, row[14]);
155
156 STR_REPLACE(recipient->alert.sendto, row[16]);
157
158 if (NULL == recipient->alert.subject)
159 recipient->alert.message = recipient->alert.subject = zbx_strdup(NULL, "Zabbix database is down.");
160
161 count++;
162 }
163 DBfree_result(result);
164
165 if (0 < old_count && 0 == count)
166 {
167 zabbix_log(LOG_LEVEL_WARNING, "watchdog: no recipients found for database down messages");
168 no_recipients = 1;
169 }
170 else if (1 == no_recipients && 0 < count)
171 {
172 zabbix_log(LOG_LEVEL_WARNING, "watchdog: %d recipient(s) found for database down messages", count);
173 no_recipients = 0;
174 }
175
176 recipients.values_num = count;
177
178 while (count < old_count)
179 {
180 /* some recipients have been deleted, free the older entries */
181
182 recipient = recipients.values[count++];
183
184 zbx_free(recipient->mediatype.description);
185 zbx_free(recipient->mediatype.smtp_server);
186 zbx_free(recipient->mediatype.smtp_helo);
187 zbx_free(recipient->mediatype.smtp_email);
188 zbx_free(recipient->mediatype.exec_path);
189 zbx_free(recipient->mediatype.gsm_modem);
190 zbx_free(recipient->mediatype.username);
191 zbx_free(recipient->mediatype.passwd);
192 zbx_free(recipient->alert.sendto);
193 zbx_free(recipient->alert.subject);
194
195 zbx_free(recipient);
196 }
197 exit:
198 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() values_num:%d", __function_name, recipients.values_num);
199 }
200
201 /******************************************************************************
202 * *
203 * Function: main_watchdog_loop *
204 * *
205 * Purpose: check database availability every DB_PING_FREQUENCY seconds and *
206 * alert admins if it is down *
207 * *
208 * Author: Alexei Vladishev, Rudolfs Kreicbergs *
209 * *
210 ******************************************************************************/
ZBX_THREAD_ENTRY(watchdog_thread,args)211 ZBX_THREAD_ENTRY(watchdog_thread, args)
212 {
213 int now, nextsync = 0, action;
214 double sec;
215
216 process_type = ((zbx_thread_args_t *)args)->process_type;
217 server_num = ((zbx_thread_args_t *)args)->server_num;
218 process_num = ((zbx_thread_args_t *)args)->process_num;
219
220 zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
221 server_num, get_process_type_string(process_type), process_num);
222
223 zbx_vector_ptr_create(&recipients);
224
225 for (;;)
226 {
227 zbx_handle_log();
228
229 zbx_setproctitle("%s [pinging database]", get_process_type_string(process_type));
230
231 sec = zbx_time();
232 action = 0;
233
234 if (ZBX_DB_OK != DBconnect(ZBX_DB_CONNECT_ONCE))
235 {
236 zabbix_log(LOG_LEVEL_WARNING, "watchdog: database is down");
237 send_alerts();
238 action = 1;
239 }
240 else if (nextsync <= (now = (int)time(NULL)))
241 {
242 zbx_setproctitle("%s [syncing configuration]", get_process_type_string(process_type));
243
244 sync_config();
245
246 nextsync = now + CONFIG_CONFSYNCER_FREQUENCY;
247
248 action = 2;
249 }
250
251 DBclose();
252
253 sec = zbx_time() - sec;
254
255 if (1 == action)
256 {
257 zbx_setproctitle("%s [database is down, checking took " ZBX_FS_DBL " sec, idle %d sec]",
258 get_process_type_string(process_type), sec, (int)DB_PING_FREQUENCY);
259 }
260 else if (2 == action)
261 {
262 zbx_setproctitle("%s [synced alerts config in " ZBX_FS_DBL " sec, idle %d sec]",
263 get_process_type_string(process_type), sec, (int)DB_PING_FREQUENCY);
264 }
265
266 zbx_sleep_loop(DB_PING_FREQUENCY);
267
268 #if !defined(_WINDOWS) && defined(HAVE_RESOLV_H)
269 zbx_update_resolver_conf(); /* handle /etc/resolv.conf update */
270 #endif
271 }
272 }
273