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