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 "dbcache.h"
25 #include "zbxserver.h"
26 #include "template.h"
27 #include "events.h"
28
29 #define ZBX_FLAGS_TRIGGER_CREATE_NOTHING 0x00
30 #define ZBX_FLAGS_TRIGGER_CREATE_TRIGGER_EVENT 0x01
31 #define ZBX_FLAGS_TRIGGER_CREATE_INTERNAL_EVENT 0x02
32 #define ZBX_FLAGS_TRIGGER_CREATE_EVENT \
33 (ZBX_FLAGS_TRIGGER_CREATE_TRIGGER_EVENT | ZBX_FLAGS_TRIGGER_CREATE_INTERNAL_EVENT)
34
35 /******************************************************************************
36 * *
37 * Function: zbx_process_trigger *
38 * *
39 * Purpose: 1) calculate changeset of trigger fields to be updated *
40 * 2) generate events *
41 * *
42 * Parameters: trigger - [IN] the trigger to process *
43 * diffs - [OUT] the vector with trigger changes *
44 * *
45 * Return value: SUCCEED - trigger processed successfully *
46 * FAIL - no changes *
47 * *
48 * Comments: Trigger dependency checks will be done during event processing. *
49 * *
50 * Event generation depending on trigger value/state changes: *
51 * *
52 * From \ To | OK | OK(?) | PROBLEM | PROBLEM(?) | NONE *
53 *----------------------------------------------------------------------------*
54 * OK | . | I | E | I | . *
55 * | | | | | *
56 * OK(?) | I | . | E,I | - | I *
57 * | | | | | *
58 * PROBLEM | E | I | E(m) | I | . *
59 * | | | | | *
60 * PROBLEM(?) | E,I | - | E(m),I | . | I *
61 * *
62 * Legend: *
63 * 'E' - trigger event *
64 * 'I' - internal event *
65 * '.' - nothing *
66 * '-' - should never happen *
67 * *
68 ******************************************************************************/
zbx_process_trigger(struct _DC_TRIGGER * trigger,zbx_vector_ptr_t * diffs)69 static int zbx_process_trigger(struct _DC_TRIGGER *trigger, zbx_vector_ptr_t *diffs)
70 {
71 const char *__function_name = "zbx_process_trigger";
72
73 const char *new_error;
74 int new_state, new_value, ret = FAIL;
75 zbx_uint64_t flags = ZBX_FLAGS_TRIGGER_DIFF_UNSET, event_flags = ZBX_FLAGS_TRIGGER_CREATE_NOTHING;
76
77 zabbix_log(LOG_LEVEL_DEBUG, "In %s() triggerid:" ZBX_FS_UI64 " value:%d(%d) new_value:%d",
78 __function_name, trigger->triggerid, trigger->value, trigger->state, trigger->new_value);
79
80 if (TRIGGER_VALUE_UNKNOWN == trigger->new_value)
81 {
82 new_state = TRIGGER_STATE_UNKNOWN;
83 new_value = trigger->value;
84 }
85 else
86 {
87 new_state = TRIGGER_STATE_NORMAL;
88 new_value = trigger->new_value;
89 }
90 new_error = (NULL == trigger->new_error ? "" : trigger->new_error);
91
92 if (trigger->state != new_state)
93 {
94 flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_STATE;
95 event_flags |= ZBX_FLAGS_TRIGGER_CREATE_INTERNAL_EVENT;
96 }
97
98 if (0 != strcmp(trigger->error, new_error))
99 flags |= ZBX_FLAGS_TRIGGER_DIFF_UPDATE_ERROR;
100
101 if (TRIGGER_STATE_NORMAL == new_state)
102 {
103 if (TRIGGER_VALUE_PROBLEM == new_value)
104 {
105 if (TRIGGER_VALUE_OK == trigger->value || TRIGGER_TYPE_MULTIPLE_TRUE == trigger->type)
106 event_flags |= ZBX_FLAGS_TRIGGER_CREATE_TRIGGER_EVENT;
107 }
108 else if (TRIGGER_VALUE_OK == new_value)
109 {
110 if (TRIGGER_VALUE_PROBLEM == trigger->value || 0 == trigger->lastchange)
111 event_flags |= ZBX_FLAGS_TRIGGER_CREATE_TRIGGER_EVENT;
112 }
113 }
114
115 /* check if there is something to be updated */
116 if (0 == (flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE) && 0 == (event_flags & ZBX_FLAGS_TRIGGER_CREATE_EVENT))
117 goto out;
118
119 if (0 != (event_flags & ZBX_FLAGS_TRIGGER_CREATE_TRIGGER_EVENT))
120 {
121 zbx_add_event(EVENT_SOURCE_TRIGGERS, EVENT_OBJECT_TRIGGER, trigger->triggerid,
122 &trigger->timespec, new_value, trigger->description,
123 trigger->expression_orig, trigger->recovery_expression_orig,
124 trigger->priority, trigger->type, &trigger->tags,
125 trigger->correlation_mode, trigger->correlation_tag, trigger->value, NULL);
126 }
127
128 if (0 != (event_flags & ZBX_FLAGS_TRIGGER_CREATE_INTERNAL_EVENT))
129 {
130 zbx_add_event(EVENT_SOURCE_INTERNAL, EVENT_OBJECT_TRIGGER, trigger->triggerid,
131 &trigger->timespec, new_state, NULL, NULL, NULL, 0, 0, NULL, 0, NULL, 0, new_error);
132 }
133
134 zbx_append_trigger_diff(diffs, trigger->triggerid, trigger->priority, flags, trigger->value, new_state,
135 trigger->timespec.sec, new_error);
136
137 ret = SUCCEED;
138 out:
139 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s flags:" ZBX_FS_UI64, __function_name, zbx_result_string(ret),
140 flags);
141
142 return ret;
143 }
144
145 /******************************************************************************
146 * *
147 * Function: zbx_db_save_trigger_changes *
148 * *
149 * Purpose: save the trigger changes to database *
150 * *
151 * Parameters: trigger_diff - [IN] the trigger changeset *
152 * *
153 ******************************************************************************/
zbx_db_save_trigger_changes(const zbx_vector_ptr_t * trigger_diff)154 void zbx_db_save_trigger_changes(const zbx_vector_ptr_t *trigger_diff)
155 {
156 const char *__function_name = "zbx_db_save_trigger_changes";
157
158 int i;
159 char *sql = NULL;
160 size_t sql_alloc = 0, sql_offset = 0;
161 const zbx_trigger_diff_t *diff;
162
163 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
164
165 DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
166
167 for (i = 0; i < trigger_diff->values_num; i++)
168 {
169 char delim = ' ';
170 diff = (const zbx_trigger_diff_t *)trigger_diff->values[i];
171
172 if (0 == (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE))
173 continue;
174
175 zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update triggers set");
176
177 if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_LASTCHANGE))
178 {
179 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%clastchange=%d", delim, diff->lastchange);
180 delim = ',';
181 }
182
183 if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_VALUE))
184 {
185 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cvalue=%d", delim, diff->value);
186 delim = ',';
187 }
188
189 if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_STATE))
190 {
191 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cstate=%d", delim, diff->state);
192 delim = ',';
193 }
194
195 if (0 != (diff->flags & ZBX_FLAGS_TRIGGER_DIFF_UPDATE_ERROR))
196 {
197 char *error_esc;
198
199 error_esc = DBdyn_escape_field("triggers", "error", diff->error);
200 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%cerror='%s'", delim, error_esc);
201 zbx_free(error_esc);
202 }
203
204 zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where triggerid=" ZBX_FS_UI64 ";\n",
205 diff->triggerid);
206
207 DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset);
208 }
209
210 DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
211
212 if (sql_offset > 16) /* in ORACLE always present begin..end; */
213 DBexecute("%s", sql);
214
215 zbx_free(sql);
216
217 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
218 }
219
220 /******************************************************************************
221 * *
222 * Function: zbx_trigger_diff_free *
223 * *
224 * Purpose: frees trigger changeset *
225 * *
226 ******************************************************************************/
zbx_trigger_diff_free(zbx_trigger_diff_t * diff)227 void zbx_trigger_diff_free(zbx_trigger_diff_t *diff)
228 {
229 zbx_free(diff->error);
230 zbx_free(diff);
231 }
232
233 /******************************************************************************
234 * *
235 * Comments: helper function for zbx_process_triggers() *
236 * *
237 ******************************************************************************/
zbx_trigger_topoindex_compare(const void * d1,const void * d2)238 static int zbx_trigger_topoindex_compare(const void *d1, const void *d2)
239 {
240 const DC_TRIGGER *t1 = *(const DC_TRIGGER **)d1;
241 const DC_TRIGGER *t2 = *(const DC_TRIGGER **)d2;
242
243 ZBX_RETURN_IF_NOT_EQUAL(t1->topoindex, t2->topoindex);
244
245 return 0;
246 }
247
248 /******************************************************************************
249 * *
250 * Function: zbx_process_triggers *
251 * *
252 * Purpose: process triggers - calculates property changeset and generates *
253 * events *
254 * *
255 * Parameters: triggers - [IN] the triggers to process *
256 * trigger_diff - [OUT] the trigger changeset *
257 * *
258 * Comments: The trigger_diff changeset must be cleaned by the caller: *
259 * zbx_vector_ptr_clear_ext(trigger_diff, *
260 * (zbx_clean_func_t)zbx_trigger_diff_free); *
261 * *
262 ******************************************************************************/
zbx_process_triggers(zbx_vector_ptr_t * triggers,zbx_vector_ptr_t * trigger_diff)263 void zbx_process_triggers(zbx_vector_ptr_t *triggers, zbx_vector_ptr_t *trigger_diff)
264 {
265 const char *__function_name = "zbx_process_triggers";
266
267 int i;
268
269 zabbix_log(LOG_LEVEL_DEBUG, "In %s() values_num:%d", __function_name, triggers->values_num);
270
271 if (0 == triggers->values_num)
272 goto out;
273
274 zbx_vector_ptr_sort(triggers, zbx_trigger_topoindex_compare);
275
276 for (i = 0; i < triggers->values_num; i++)
277 zbx_process_trigger((struct _DC_TRIGGER *)triggers->values[i], trigger_diff);
278
279 zbx_vector_ptr_sort(trigger_diff, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
280 out:
281 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
282 }
283
284 /******************************************************************************
285 * *
286 * Function: zbx_append_trigger_diff *
287 * *
288 * Purpose: Adds a new trigger diff to trigger changeset vector *
289 * *
290 ******************************************************************************/
zbx_append_trigger_diff(zbx_vector_ptr_t * trigger_diff,zbx_uint64_t triggerid,unsigned char priority,zbx_uint64_t flags,unsigned char value,unsigned char state,int lastchange,const char * error)291 void zbx_append_trigger_diff(zbx_vector_ptr_t *trigger_diff, zbx_uint64_t triggerid, unsigned char priority,
292 zbx_uint64_t flags, unsigned char value, unsigned char state, int lastchange, const char *error)
293 {
294 zbx_trigger_diff_t *diff;
295
296 diff = (zbx_trigger_diff_t *)zbx_malloc(NULL, sizeof(zbx_trigger_diff_t));
297 diff->triggerid = triggerid;
298 diff->priority = priority;
299 diff->flags = flags;
300 diff->value = value;
301 diff->state = state;
302 diff->lastchange = lastchange;
303 diff->error = (NULL != error ? zbx_strdup(NULL, error) : NULL);
304
305 diff->problem_count = 0;
306
307 zbx_vector_ptr_append(trigger_diff, diff);
308 }
309