added uuid class; code rerfactoring
[public/netxms.git] / src / server / core / epp.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2014 Victor Kirhenshtein
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: epp.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Default event policy rule constructor
27 */
28 EPRule::EPRule(UINT32 id)
29 {
30 m_id = id;
31 m_guid = uuid::generate();
32 m_dwFlags = 0;
33 m_dwNumSources = 0;
34 m_pdwSourceList = NULL;
35 m_dwNumEvents = 0;
36 m_pdwEventList = NULL;
37 m_dwNumActions = 0;
38 m_pdwActionList = NULL;
39 m_pszComment = NULL;
40 m_iAlarmSeverity = 0;
41 m_szAlarmKey[0] = 0;
42 m_szAlarmMessage[0] = 0;
43 m_pszScript = NULL;
44 m_pScript = NULL;
45 m_dwAlarmTimeout = 0;
46 m_dwAlarmTimeoutEvent = EVENT_ALARM_TIMEOUT;
47 m_dwSituationId = 0;
48 m_szSituationInstance[0] = 0;
49 }
50
51 /**
52 * Create rule from config entry
53 */
54 EPRule::EPRule(ConfigEntry *config)
55 {
56 m_id = 0;
57 m_guid = config->getSubEntryValueAsUUID(_T("guid"));
58 m_dwFlags = config->getSubEntryValueAsUInt(_T("flags"));
59 m_dwNumSources = 0;
60 m_pdwSourceList = NULL;
61 m_dwNumActions = 0;
62 m_pdwActionList = NULL;
63
64 ConfigEntry *eventsRoot = config->findEntry(_T("events"));
65 if (eventsRoot != NULL)
66 {
67 ObjectArray<ConfigEntry> *events = eventsRoot->getSubEntries(_T("event#*"));
68 m_dwNumEvents = 0;
69 m_pdwEventList = (UINT32 *)malloc(sizeof(UINT32) * events->size());
70 for(int i = 0; i < events->size(); i++)
71 {
72 EVENT_TEMPLATE *e = FindEventTemplateByName(events->get(i)->getSubEntryValue(_T("name"), 0, _T("<unknown>")));
73 if (e != NULL)
74 {
75 m_pdwEventList[m_dwNumEvents++] = e->dwCode;
76 }
77 }
78 }
79
80 m_pszComment = _tcsdup(config->getSubEntryValue(_T("comments"), 0, _T("")));
81 m_iAlarmSeverity = config->getSubEntryValueAsInt(_T("alarmSeverity"));
82 m_dwAlarmTimeout = config->getSubEntryValueAsUInt(_T("alarmTimeout"));
83 m_dwAlarmTimeoutEvent = config->getSubEntryValueAsUInt(_T("alarmTimeout"), 0, EVENT_ALARM_TIMEOUT);
84 nx_strncpy(m_szAlarmKey, config->getSubEntryValue(_T("alarmKey"), 0, _T("")), MAX_DB_STRING);
85 nx_strncpy(m_szAlarmMessage, config->getSubEntryValue(_T("alarmMessage"), 0, _T("")), MAX_DB_STRING);
86
87 m_dwSituationId = 0;
88 m_szSituationInstance[0] = 0;
89
90 m_pszScript = _tcsdup(config->getSubEntryValue(_T("script"), 0, _T("")));
91 if ((m_pszScript != NULL) && (*m_pszScript != 0))
92 {
93 TCHAR szError[256];
94
95 m_pScript = NXSLCompileAndCreateVM(m_pszScript, szError, 256, new NXSL_ServerEnv);
96 if (m_pScript != NULL)
97 {
98 m_pScript->setGlobalVariable(_T("CUSTOM_MESSAGE"), new NXSL_Value(_T("")));
99 }
100 else
101 {
102 nxlog_write(MSG_EPRULE_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "ds", m_id, szError);
103 }
104 }
105 else
106 {
107 m_pScript = NULL;
108 }
109 }
110
111 /**
112 * Construct event policy rule from database record
113 * Assuming the following field order:
114 * rule_id,rule_guid,flags,comments,alarm_message,alarm_severity,alarm_key,script,
115 * alarm_timeout,alarm_timeout_event,situation_id,situation_instance
116 */
117 EPRule::EPRule(DB_RESULT hResult, int row)
118 {
119 m_id = DBGetFieldULong(hResult, row, 0);
120 m_guid = DBGetFieldGUID(hResult, row, 1);
121 m_dwFlags = DBGetFieldULong(hResult, row, 2);
122 m_pszComment = DBGetField(hResult, row, 3, NULL, 0);
123 DBGetField(hResult, row, 4, m_szAlarmMessage, MAX_EVENT_MSG_LENGTH);
124 m_iAlarmSeverity = DBGetFieldLong(hResult, row, 5);
125 DBGetField(hResult, row, 6, m_szAlarmKey, MAX_DB_STRING);
126 m_pszScript = DBGetField(hResult, row, 7, NULL, 0);
127 if ((m_pszScript != NULL) && (*m_pszScript != 0))
128 {
129 TCHAR szError[256];
130
131 m_pScript = NXSLCompileAndCreateVM(m_pszScript, szError, 256, new NXSL_ServerEnv);
132 if (m_pScript != NULL)
133 {
134 m_pScript->setGlobalVariable(_T("CUSTOM_MESSAGE"), new NXSL_Value(_T("")));
135 }
136 else
137 {
138 nxlog_write(MSG_EPRULE_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE,
139 "ds", m_id, szError);
140 }
141 }
142 else
143 {
144 m_pScript = NULL;
145 }
146 m_dwAlarmTimeout = DBGetFieldULong(hResult, row, 8);
147 m_dwAlarmTimeoutEvent = DBGetFieldULong(hResult, row, 9);
148 m_dwSituationId = DBGetFieldULong(hResult, row, 10);
149 DBGetField(hResult, row, 11, m_szSituationInstance, MAX_DB_STRING);
150 }
151
152 /**
153 * Construct event policy rule from NXCP message
154 */
155 EPRule::EPRule(NXCPMessage *msg)
156 {
157 UINT32 i, id, count;
158 TCHAR *name, *value;
159
160 m_dwFlags = msg->getFieldAsUInt32(VID_FLAGS);
161 m_id = msg->getFieldAsUInt32(VID_RULE_ID);
162 m_guid = msg->getFieldAsGUID(VID_GUID);
163 m_pszComment = msg->getFieldAsString(VID_COMMENTS);
164
165 m_dwNumActions = msg->getFieldAsUInt32(VID_NUM_ACTIONS);
166 m_pdwActionList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumActions);
167 msg->getFieldAsInt32Array(VID_RULE_ACTIONS, m_dwNumActions, m_pdwActionList);
168
169 m_dwNumEvents = msg->getFieldAsUInt32(VID_NUM_EVENTS);
170 m_pdwEventList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumEvents);
171 msg->getFieldAsInt32Array(VID_RULE_EVENTS, m_dwNumEvents, m_pdwEventList);
172
173 m_dwNumSources = msg->getFieldAsUInt32(VID_NUM_SOURCES);
174 m_pdwSourceList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumSources);
175 msg->getFieldAsInt32Array(VID_RULE_SOURCES, m_dwNumSources, m_pdwSourceList);
176
177 msg->getFieldAsString(VID_ALARM_KEY, m_szAlarmKey, MAX_DB_STRING);
178 msg->getFieldAsString(VID_ALARM_MESSAGE, m_szAlarmMessage, MAX_DB_STRING);
179 m_iAlarmSeverity = msg->getFieldAsUInt16(VID_ALARM_SEVERITY);
180 m_dwAlarmTimeout = msg->getFieldAsUInt32(VID_ALARM_TIMEOUT);
181 m_dwAlarmTimeoutEvent = msg->getFieldAsUInt32(VID_ALARM_TIMEOUT_EVENT);
182
183 m_dwSituationId = msg->getFieldAsUInt32(VID_SITUATION_ID);
184 msg->getFieldAsString(VID_SITUATION_INSTANCE, m_szSituationInstance, MAX_DB_STRING);
185 count = msg->getFieldAsUInt32(VID_SITUATION_NUM_ATTRS);
186 for(i = 0, id = VID_SITUATION_ATTR_LIST_BASE; i < count; i++)
187 {
188 name = msg->getFieldAsString(id++);
189 value = msg->getFieldAsString(id++);
190 m_situationAttrList.setPreallocated(name, value);
191 }
192
193 m_pszScript = msg->getFieldAsString(VID_SCRIPT);
194 if ((m_pszScript != NULL) && (*m_pszScript != 0))
195 {
196 TCHAR szError[256];
197
198 m_pScript = NXSLCompileAndCreateVM(m_pszScript, szError, 256, new NXSL_ServerEnv);
199 if (m_pScript != NULL)
200 {
201 m_pScript->setGlobalVariable(_T("CUSTOM_MESSAGE"), new NXSL_Value(_T("")));
202 }
203 else
204 {
205 nxlog_write(MSG_EPRULE_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "ds", m_id, szError);
206 }
207 }
208 else
209 {
210 m_pScript = NULL;
211 }
212 }
213
214 /**
215 * Event policy rule destructor
216 */
217 EPRule::~EPRule()
218 {
219 safe_free(m_pdwSourceList);
220 safe_free(m_pdwEventList);
221 safe_free(m_pdwActionList);
222 safe_free(m_pszComment);
223 safe_free(m_pszScript);
224 delete m_pScript;
225 }
226
227 /**
228 * Create management pack record
229 */
230 void EPRule::createNXMPRecord(String &str)
231 {
232 str.appendFormattedString(_T("\t\t<rule id=\"%d\">\n")
233 _T("\t\t\t<flags>%d</flags>\n")
234 _T("\t\t\t<alarmMessage>%s</alarmMessage>\n")
235 _T("\t\t\t<alarmKey>%s</alarmKey>\n")
236 _T("\t\t\t<alarmSeverity>%d</alarmSeverity>\n")
237 _T("\t\t\t<alarmTimeout>%d</alarmTimeout>\n")
238 _T("\t\t\t<alarmTimeoutEvent>%d</alarmTimeoutEvent>\n")
239 _T("\t\t\t<situation>%d</situation>\n")
240 _T("\t\t\t<situationInstance>%s</situationInstance>\n")
241 _T("\t\t\t<script>%s</script>\n")
242 _T("\t\t\t<comments>%s</comments>\n")
243 _T("\t\t\t<sources>\n"),
244 m_id, m_dwFlags,
245 (const TCHAR *)EscapeStringForXML2(m_szAlarmMessage),
246 (const TCHAR *)EscapeStringForXML2(m_szAlarmKey),
247 m_iAlarmSeverity, m_dwAlarmTimeout, m_dwAlarmTimeoutEvent,
248 m_dwSituationId, (const TCHAR *)EscapeStringForXML2(m_szSituationInstance),
249 (const TCHAR *)EscapeStringForXML2(m_pszScript),
250 (const TCHAR *)EscapeStringForXML2(m_pszComment));
251
252 for(UINT32 i = 0; i < m_dwNumSources; i++)
253 {
254 NetObj *object = FindObjectById(m_pdwSourceList[i]);
255 if (object != NULL)
256 {
257 TCHAR guidText[128];
258 str.appendFormattedString(_T("\t\t\t\t<source id=\"%d\">\n")
259 _T("\t\t\t\t\t<name>%s</name>\n")
260 _T("\t\t\t\t\t<guid>%s</guid>\n")
261 _T("\t\t\t\t\t<class>%d</class>\n")
262 _T("\t\t\t\t</source>\n"),
263 object->getId(),
264 (const TCHAR *)EscapeStringForXML2(object->getName()),
265 object->getGuid().toString(guidText), object->getObjectClass());
266 }
267 }
268
269 str += _T("\t\t\t</sources>\n\t\t\t<events>\n");
270
271 for(UINT32 i = 0; i < m_dwNumEvents; i++)
272 {
273 TCHAR eventName[MAX_EVENT_NAME];
274 EventNameFromCode(m_pdwEventList[i], eventName);
275 str.appendFormattedString(_T("\t\t\t\t<event id=\"%d\">\n")
276 _T("\t\t\t\t\t<name>%s</name>\n")
277 _T("\t\t\t\t</event>\n"),
278 m_pdwEventList[i], (const TCHAR *)EscapeStringForXML2(eventName));
279 }
280
281 str += _T("\t\t\t</events>\n\t\t\t<actions>\n");
282
283 for(UINT32 i = 0; i < m_dwNumActions; i++)
284 {
285 str.appendFormattedString(_T("\t\t\t\t<action id=\"%d\">\n")
286 _T("\t\t\t\t</action>\n"),
287 m_pdwActionList[i]);
288 }
289
290 str += _T("\t\t\t</actions>\n\t\t</rule>\n");
291 }
292
293 /**
294 * Check if source object's id match to the rule
295 */
296 bool EPRule::matchSource(UINT32 dwObjectId)
297 {
298 UINT32 i;
299 NetObj *pObject;
300 bool bMatch = FALSE;
301
302 if (m_dwNumSources == 0) // No sources in list means "any"
303 {
304 bMatch = true;
305 }
306 else
307 {
308 for(i = 0; i < m_dwNumSources; i++)
309 if (m_pdwSourceList[i] == dwObjectId)
310 {
311 bMatch = true;
312 break;
313 }
314 else
315 {
316 pObject = FindObjectById(m_pdwSourceList[i]);
317 if (pObject != NULL)
318 {
319 if (pObject->isChild(dwObjectId))
320 {
321 bMatch = true;
322 break;
323 }
324 }
325 else
326 {
327 nxlog_write(MSG_INVALID_EPP_OBJECT, EVENTLOG_ERROR_TYPE, "d", m_pdwSourceList[i]);
328 }
329 }
330 }
331 return (m_dwFlags & RF_NEGATED_SOURCE) ? !bMatch : bMatch;
332 }
333
334 /**
335 * Check if event's id match to the rule
336 */
337 bool EPRule::matchEvent(UINT32 dwEventCode)
338 {
339 UINT32 i;
340 bool bMatch = false;
341
342 if (m_dwNumEvents == 0) // No sources in list means "any"
343 {
344 bMatch = true;
345 }
346 else
347 {
348 for(i = 0; i < m_dwNumEvents; i++)
349 if (m_pdwEventList[i] & GROUP_FLAG_BIT)
350 {
351 /* TODO: check group membership */
352 }
353 else
354 {
355 if (m_pdwEventList[i] == dwEventCode)
356 {
357 bMatch = true;
358 break;
359 }
360 }
361 }
362 return (m_dwFlags & RF_NEGATED_EVENTS) ? !bMatch : bMatch;
363 }
364
365 /**
366 * Check if event's severity match to the rule
367 */
368 bool EPRule::matchSeverity(UINT32 dwSeverity)
369 {
370 static UINT32 dwSeverityFlag[] = { RF_SEVERITY_INFO, RF_SEVERITY_WARNING,
371 RF_SEVERITY_MINOR, RF_SEVERITY_MAJOR,
372 RF_SEVERITY_CRITICAL };
373 return (dwSeverityFlag[dwSeverity] & m_dwFlags) ? true : false;
374 }
375
376 /**
377 * Check if event match to the script
378 */
379 bool EPRule::matchScript(Event *pEvent)
380 {
381 NXSL_Value **ppValueList, *pValue;
382 NXSL_VariableSystem *pLocals, *pGlobals = NULL;
383 bool bRet = true;
384 UINT32 i;
385 NetObj *pObject;
386
387 if (m_pScript == NULL)
388 return true;
389
390 // Pass event's parameters as arguments and
391 // other information as variables
392 ppValueList = (NXSL_Value **)malloc(sizeof(NXSL_Value *) * pEvent->getParametersCount());
393 memset(ppValueList, 0, sizeof(NXSL_Value *) * pEvent->getParametersCount());
394 for(i = 0; i < pEvent->getParametersCount(); i++)
395 ppValueList[i] = new NXSL_Value(pEvent->getParameter(i));
396
397 pLocals = new NXSL_VariableSystem;
398 pLocals->create(_T("EVENT_CODE"), new NXSL_Value(pEvent->getCode()));
399 pLocals->create(_T("SEVERITY"), new NXSL_Value(pEvent->getSeverity()));
400 pLocals->create(_T("SEVERITY_TEXT"), new NXSL_Value(GetStatusAsText(pEvent->getSeverity(), true)));
401 pLocals->create(_T("OBJECT_ID"), new NXSL_Value(pEvent->getSourceId()));
402 pLocals->create(_T("EVENT_TEXT"), new NXSL_Value((TCHAR *)pEvent->getMessage()));
403 pLocals->create(_T("USER_TAG"), new NXSL_Value((TCHAR *)pEvent->getUserTag()));
404 pObject = FindObjectById(pEvent->getSourceId());
405 if (pObject != NULL)
406 {
407 if (pObject->getObjectClass() == OBJECT_NODE)
408 m_pScript->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, pObject)));
409 }
410 m_pScript->setGlobalVariable(_T("$event"), new NXSL_Value(new NXSL_Object(&g_nxslEventClass, pEvent)));
411 m_pScript->setGlobalVariable(_T("CUSTOM_MESSAGE"), new NXSL_Value);
412
413 // Run script
414 if (m_pScript->run(pEvent->getParametersCount(), ppValueList, pLocals, &pGlobals))
415 {
416 pValue = m_pScript->getResult();
417 if (pValue != NULL)
418 {
419 bRet = pValue->getValueAsInt32() ? true : false;
420 if (bRet)
421 {
422 NXSL_Variable *var;
423
424 var = pGlobals->find(_T("CUSTOM_MESSAGE"));
425 if (var != NULL)
426 {
427 // Update custom message in event
428 pEvent->setCustomMessage(CHECK_NULL_EX(var->getValue()->getValueAsCString()));
429 }
430 }
431 }
432 }
433 else
434 {
435 nxlog_write(MSG_EPRULE_SCRIPT_EXECUTION_ERROR, EVENTLOG_ERROR_TYPE, "ds", m_id + 1, m_pScript->getErrorText());
436 }
437 free(ppValueList);
438 delete pGlobals;
439
440 return bRet;
441 }
442
443 /**
444 * Situation update callback data
445 */
446 struct SituationUpdateCallbackData
447 {
448 Situation *s;
449 TCHAR *text;
450 Event *evt;
451 };
452
453 /**
454 * Situation update callback
455 */
456 static EnumerationCallbackResult SituationUpdateCallback(const TCHAR *key, const void *value, void *data)
457 {
458 TCHAR *attrName = ((SituationUpdateCallbackData *)data)->evt->expandText(key);
459 TCHAR *attrValue = ((SituationUpdateCallbackData *)data)->evt->expandText((const TCHAR *)value);
460 ((SituationUpdateCallbackData *)data)->s->UpdateSituation(((SituationUpdateCallbackData *)data)->text, attrName, attrValue);
461 free(attrName);
462 free(attrValue);
463 return _CONTINUE;
464 }
465
466 /**
467 * Check if event match to rule and perform required actions if yes
468 * Method will return TRUE if event matched and RF_STOP_PROCESSING flag is set
469 */
470 bool EPRule::processEvent(Event *pEvent)
471 {
472 bool bStopProcessing = false;
473
474 // Check disable flag
475 if (!(m_dwFlags & RF_DISABLED))
476 {
477 // Check if event match
478 if (matchSource(pEvent->getSourceId()) && matchEvent(pEvent->getCode()) &&
479 matchSeverity(pEvent->getSeverity()) && matchScript(pEvent))
480 {
481 DbgPrintf(6, _T("Event ") UINT64_FMT _T(" match EPP rule %d"), pEvent->getId(), (int)m_id);
482
483 // Generate alarm if requested
484 if (m_dwFlags & RF_GENERATE_ALARM)
485 generateAlarm(pEvent);
486
487 // Event matched, perform actions
488 if (m_dwNumActions > 0)
489 {
490 TCHAR *alarmMessage = pEvent->expandText(m_szAlarmMessage);
491 TCHAR *alarmKey = pEvent->expandText(m_szAlarmKey);
492 for(UINT32 i = 0; i < m_dwNumActions; i++)
493 ExecuteAction(m_pdwActionList[i], pEvent, alarmMessage, alarmKey);
494 free(alarmMessage);
495 free(alarmKey);
496 }
497
498 // Update situation of needed
499 if (m_dwSituationId != 0)
500 {
501 Situation *pSituation = FindSituationById(m_dwSituationId);
502 if (pSituation != NULL)
503 {
504 SituationUpdateCallbackData data;
505 data.text = pEvent->expandText(m_szSituationInstance);
506 data.s = pSituation;
507 data.evt = pEvent;
508 m_situationAttrList.forEach(SituationUpdateCallback, &data);
509 free(data.text);
510 }
511 else
512 {
513 DbgPrintf(3, _T("Event Policy: unable to find situation with ID=%d"), m_dwSituationId);
514 }
515 }
516
517 bStopProcessing = (m_dwFlags & RF_STOP_PROCESSING) ? true : false;
518 }
519 }
520
521 return bStopProcessing;
522 }
523
524 /**
525 * Generate alarm from event
526 */
527 void EPRule::generateAlarm(Event *pEvent)
528 {
529 // Terminate alarms with key == our ack_key
530 if ((m_iAlarmSeverity == SEVERITY_RESOLVE) || (m_iAlarmSeverity == SEVERITY_TERMINATE))
531 {
532 TCHAR *pszAckKey = pEvent->expandText(m_szAlarmKey);
533 if (pszAckKey[0] != 0)
534 ResolveAlarmByKey(pszAckKey, (m_dwFlags & RF_TERMINATE_BY_REGEXP) ? true : false, m_iAlarmSeverity == SEVERITY_TERMINATE, pEvent);
535 free(pszAckKey);
536 }
537 else // Generate new alarm
538 {
539 CreateNewAlarm(m_szAlarmMessage, m_szAlarmKey, ALARM_STATE_OUTSTANDING,
540 (m_iAlarmSeverity == SEVERITY_FROM_EVENT) ? pEvent->getSeverity() : m_iAlarmSeverity,
541 m_dwAlarmTimeout, m_dwAlarmTimeoutEvent, pEvent, 0);
542 }
543 }
544
545 /**
546 * Load rule from database
547 */
548 bool EPRule::loadFromDB()
549 {
550 DB_RESULT hResult;
551 TCHAR szQuery[256], name[MAX_DB_STRING], value[MAX_DB_STRING];
552 bool bSuccess = true;
553 UINT32 i, count;
554
555 // Load rule's sources
556 _sntprintf(szQuery, 256, _T("SELECT object_id FROM policy_source_list WHERE rule_id=%d"), m_id);
557 hResult = DBSelect(g_hCoreDB, szQuery);
558 if (hResult != NULL)
559 {
560 m_dwNumSources = DBGetNumRows(hResult);
561 m_pdwSourceList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumSources);
562 for(i = 0; i < m_dwNumSources; i++)
563 m_pdwSourceList[i] = DBGetFieldULong(hResult, i, 0);
564 DBFreeResult(hResult);
565 }
566 else
567 {
568 bSuccess = false;
569 }
570
571 // Load rule's events
572 _sntprintf(szQuery, 256, _T("SELECT event_code FROM policy_event_list WHERE rule_id=%d"), m_id);
573 hResult = DBSelect(g_hCoreDB, szQuery);
574 if (hResult != NULL)
575 {
576 m_dwNumEvents = DBGetNumRows(hResult);
577 m_pdwEventList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumEvents);
578 for(i = 0; i < m_dwNumEvents; i++)
579 m_pdwEventList[i] = DBGetFieldULong(hResult, i, 0);
580 DBFreeResult(hResult);
581 }
582 else
583 {
584 bSuccess = false;
585 }
586
587 // Load rule's actions
588 _sntprintf(szQuery, 256, _T("SELECT action_id FROM policy_action_list WHERE rule_id=%d"), m_id);
589 hResult = DBSelect(g_hCoreDB, szQuery);
590 if (hResult != NULL)
591 {
592 m_dwNumActions = DBGetNumRows(hResult);
593 m_pdwActionList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumActions);
594 for(i = 0; i < m_dwNumActions; i++)
595 m_pdwActionList[i] = DBGetFieldULong(hResult, i, 0);
596 DBFreeResult(hResult);
597 }
598 else
599 {
600 bSuccess = false;
601 }
602
603 // Load situation attributes
604 _sntprintf(szQuery, 256, _T("SELECT attr_name,attr_value FROM policy_situation_attr_list WHERE rule_id=%d"), m_id);
605 hResult = DBSelect(g_hCoreDB, szQuery);
606 if (hResult != NULL)
607 {
608 count = DBGetNumRows(hResult);
609 for(i = 0; i < count; i++)
610 {
611 DBGetField(hResult, i, 0, name, MAX_DB_STRING);
612 DBGetField(hResult, i, 1, value, MAX_DB_STRING);
613 m_situationAttrList.set(name, value);
614 }
615 DBFreeResult(hResult);
616 }
617 else
618 {
619 bSuccess = false;
620 }
621
622 return bSuccess;
623 }
624
625 /**
626 * Callback for saving situation attributes
627 */
628 static EnumerationCallbackResult SaveSituationAttribute(const TCHAR *key, const void *value, void *data)
629 {
630 DB_STATEMENT hStmt = (DB_STATEMENT)data;
631 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, key, DB_BIND_STATIC);
632 DBBind(hStmt, 4, DB_SQLTYPE_VARCHAR, (const TCHAR *)value, DB_BIND_STATIC);
633 DBExecute(hStmt);
634 return _CONTINUE;
635 }
636
637 /**
638 * Save rule to database
639 */
640 void EPRule::saveToDB(DB_HANDLE hdb)
641 {
642 UINT32 len = (UINT32)(_tcslen(CHECK_NULL(m_pszComment)) + _tcslen(CHECK_NULL(m_pszScript)) + 4096);
643 TCHAR *pszQuery = (TCHAR *)malloc(len * sizeof(TCHAR));
644
645 // General attributes
646 TCHAR guidText[128];
647 _sntprintf(pszQuery, len, _T("INSERT INTO event_policy (rule_id,rule_guid,flags,comments,alarm_message,")
648 _T("alarm_severity,alarm_key,script,alarm_timeout,alarm_timeout_event,")
649 _T("situation_id,situation_instance) ")
650 _T("VALUES (%d,'%s',%d,%s,%s,%d,%s,%s,%d,%d,%d,%s)"),
651 m_id, m_guid.toString(guidText), m_dwFlags, (const TCHAR *)DBPrepareString(hdb, m_pszComment),
652 (const TCHAR *)DBPrepareString(hdb, m_szAlarmMessage), m_iAlarmSeverity,
653 (const TCHAR *)DBPrepareString(hdb, m_szAlarmKey),
654 (const TCHAR *)DBPrepareString(hdb, m_pszScript), m_dwAlarmTimeout, m_dwAlarmTimeoutEvent,
655 m_dwSituationId, (const TCHAR *)DBPrepareString(hdb, m_szSituationInstance));
656 DBQuery(hdb, pszQuery);
657
658 // Actions
659 int i;
660 for(i = 0; i < (int)m_dwNumActions; i++)
661 {
662 _sntprintf(pszQuery, len, _T("INSERT INTO policy_action_list (rule_id,action_id) VALUES (%d,%d)"),
663 m_id, m_pdwActionList[i]);
664 DBQuery(hdb, pszQuery);
665 }
666
667 // Events
668 for(i = 0; i < (int)m_dwNumEvents; i++)
669 {
670 _sntprintf(pszQuery, len, _T("INSERT INTO policy_event_list (rule_id,event_code) VALUES (%d,%d)"),
671 m_id, m_pdwEventList[i]);
672 DBQuery(hdb, pszQuery);
673 }
674
675 // Sources
676 for(i = 0; i < (int)m_dwNumSources; i++)
677 {
678 _sntprintf(pszQuery, len, _T("INSERT INTO policy_source_list (rule_id,object_id) VALUES (%d,%d)"),
679 m_id, m_pdwSourceList[i]);
680 DBQuery(hdb, pszQuery);
681 }
682
683 // Situation attributes
684 if (m_situationAttrList.size() > 0)
685 {
686 DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO policy_situation_attr_list (rule_id,situation_id,attr_name,attr_value) VALUES (?,?,?,?)"));
687 if (hStmt != NULL)
688 {
689 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
690 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_dwSituationId);
691 m_situationAttrList.forEach(SaveSituationAttribute, hStmt);
692 DBFreeStatement(hStmt);
693 }
694 }
695
696 free(pszQuery);
697 }
698
699 /**
700 * Create NXCP message with rule's data
701 */
702 void EPRule::createMessage(NXCPMessage *msg)
703 {
704 msg->setField(VID_FLAGS, m_dwFlags);
705 msg->setField(VID_RULE_ID, m_id);
706 msg->setField(VID_GUID, m_guid);
707 msg->setField(VID_ALARM_SEVERITY, (WORD)m_iAlarmSeverity);
708 msg->setField(VID_ALARM_KEY, m_szAlarmKey);
709 msg->setField(VID_ALARM_MESSAGE, m_szAlarmMessage);
710 msg->setField(VID_ALARM_TIMEOUT, m_dwAlarmTimeout);
711 msg->setField(VID_ALARM_TIMEOUT_EVENT, m_dwAlarmTimeoutEvent);
712 msg->setField(VID_COMMENTS, CHECK_NULL_EX(m_pszComment));
713 msg->setField(VID_NUM_ACTIONS, m_dwNumActions);
714 msg->setFieldFromInt32Array(VID_RULE_ACTIONS, m_dwNumActions, m_pdwActionList);
715 msg->setField(VID_NUM_EVENTS, m_dwNumEvents);
716 msg->setFieldFromInt32Array(VID_RULE_EVENTS, m_dwNumEvents, m_pdwEventList);
717 msg->setField(VID_NUM_SOURCES, m_dwNumSources);
718 msg->setFieldFromInt32Array(VID_RULE_SOURCES, m_dwNumSources, m_pdwSourceList);
719 msg->setField(VID_SCRIPT, CHECK_NULL_EX(m_pszScript));
720 msg->setField(VID_SITUATION_ID, m_dwSituationId);
721 msg->setField(VID_SITUATION_INSTANCE, m_szSituationInstance);
722 m_situationAttrList.fillMessage(msg, VID_SITUATION_NUM_ATTRS, VID_SITUATION_ATTR_LIST_BASE);
723 }
724
725 /**
726 * Check if given action is used within rule
727 */
728 bool EPRule::isActionInUse(UINT32 dwActionId)
729 {
730 UINT32 i;
731
732 for(i = 0; i < m_dwNumActions; i++)
733 if (m_pdwActionList[i] == dwActionId)
734 return true;
735 return false;
736 }
737
738 /**
739 * Event processing policy constructor
740 */
741 EventPolicy::EventPolicy()
742 {
743 m_dwNumRules = 0;
744 m_ppRuleList = NULL;
745 m_rwlock = RWLockCreate();
746 }
747
748 /**
749 * Event processing policy destructor
750 */
751 EventPolicy::~EventPolicy()
752 {
753 clear();
754 RWLockDestroy(m_rwlock);
755 }
756
757 /**
758 * Clear existing policy
759 */
760 void EventPolicy::clear()
761 {
762 UINT32 i;
763
764 for(i = 0; i < m_dwNumRules; i++)
765 delete m_ppRuleList[i];
766 safe_free(m_ppRuleList);
767 m_ppRuleList = NULL;
768 }
769
770 /**
771 * Load event processing policy from database
772 */
773 bool EventPolicy::loadFromDB()
774 {
775 DB_RESULT hResult;
776 bool bSuccess = false;
777
778 hResult = DBSelect(g_hCoreDB, _T("SELECT rule_id,rule_guid,flags,comments,alarm_message,")
779 _T("alarm_severity,alarm_key,script,alarm_timeout,alarm_timeout_event,")
780 _T("situation_id,situation_instance ")
781 _T("FROM event_policy ORDER BY rule_id"));
782 if (hResult != NULL)
783 {
784 UINT32 i;
785
786 bSuccess = true;
787 m_dwNumRules = DBGetNumRows(hResult);
788 m_ppRuleList = (EPRule **)malloc(sizeof(EPRule *) * m_dwNumRules);
789 for(i = 0; i < m_dwNumRules; i++)
790 {
791 m_ppRuleList[i] = new EPRule(hResult, i);
792 bSuccess = bSuccess && m_ppRuleList[i]->loadFromDB();
793 }
794 DBFreeResult(hResult);
795 }
796
797 return bSuccess;
798 }
799
800 /**
801 * Save event processing policy to database
802 */
803 void EventPolicy::saveToDB()
804 {
805 UINT32 i;
806
807 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
808
809 readLock();
810 DBBegin(hdb);
811 DBQuery(hdb, _T("DELETE FROM event_policy"));
812 DBQuery(hdb, _T("DELETE FROM policy_action_list"));
813 DBQuery(hdb, _T("DELETE FROM policy_event_list"));
814 DBQuery(hdb, _T("DELETE FROM policy_source_list"));
815 DBQuery(hdb, _T("DELETE FROM policy_situation_attr_list"));
816 for(i = 0; i < m_dwNumRules; i++)
817 m_ppRuleList[i]->saveToDB(hdb);
818 DBCommit(hdb);
819 unlock();
820 DBConnectionPoolReleaseConnection(hdb);
821 }
822
823 /**
824 * Pass event through policy
825 */
826 void EventPolicy::processEvent(Event *pEvent)
827 {
828 UINT32 i;
829
830 DbgPrintf(7, _T("EPP: processing event ") UINT64_FMT, pEvent->getId());
831 readLock();
832 for(i = 0; i < m_dwNumRules; i++)
833 if (m_ppRuleList[i]->processEvent(pEvent))
834 {
835 DbgPrintf(7, _T("EPP: got \"stop processing\" flag for event ") UINT64_FMT _T(" at rule %d"), pEvent->getId(), i + 1);
836 break; // EPRule::ProcessEvent() return TRUE if we should stop processing this event
837 }
838 unlock();
839 }
840
841 /**
842 * Send event policy to client
843 */
844 void EventPolicy::sendToClient(ClientSession *pSession, UINT32 dwRqId)
845 {
846 UINT32 i;
847 NXCPMessage msg;
848
849 readLock();
850 msg.setCode(CMD_EPP_RECORD);
851 msg.setId(dwRqId);
852 for(i = 0; i < m_dwNumRules; i++)
853 {
854 m_ppRuleList[i]->createMessage(&msg);
855 pSession->sendMessage(&msg);
856 msg.deleteAllFields();
857 }
858 unlock();
859 }
860
861 /**
862 * Replace policy with new one
863 */
864 void EventPolicy::replacePolicy(UINT32 dwNumRules, EPRule **ppRuleList)
865 {
866 UINT32 i;
867
868 writeLock();
869
870 // Replace rule list
871 clear();
872 m_dwNumRules = dwNumRules;
873 m_ppRuleList = ppRuleList;
874
875 // Replace id's in rules
876 for(i = 0; i < m_dwNumRules; i++)
877 m_ppRuleList[i]->setId(i);
878
879 unlock();
880 }
881
882 /**
883 * Check if given action is used in policy
884 */
885 bool EventPolicy::isActionInUse(UINT32 dwActionId)
886 {
887 bool bResult = false;
888
889 readLock();
890
891 for(UINT32 i = 0; i < m_dwNumRules; i++)
892 if (m_ppRuleList[i]->isActionInUse(dwActionId))
893 {
894 bResult = true;
895 break;
896 }
897
898 unlock();
899 return bResult;
900 }
901
902 /**
903 * Export rule
904 */
905 void EventPolicy::exportRule(String& str, const uuid& guid)
906 {
907 readLock();
908 for(UINT32 i = 0; i < m_dwNumRules; i++)
909 {
910 if (!guid.compare(m_ppRuleList[i]->getGuid()))
911 {
912 m_ppRuleList[i]->createNXMPRecord(str);
913 break;
914 }
915 }
916 unlock();
917 }
918
919 /**
920 * Import rule
921 */
922 void EventPolicy::importRule(EPRule *rule)
923 {
924 writeLock();
925
926 // Find rule with same GUID and replace it if found
927 bool newRule = true;
928 for(UINT32 i = 0; i < m_dwNumRules; i++)
929 {
930 if (!rule->getGuid().compare(m_ppRuleList[i]->getGuid()))
931 {
932 delete m_ppRuleList[i];
933 m_ppRuleList[i] = rule;
934 rule->setId(i);
935 newRule = false;
936 break;
937 }
938 }
939
940 // Add new rule at the end
941 if (newRule)
942 {
943 rule->setId(m_dwNumRules);
944 m_dwNumRules++;
945 m_ppRuleList = (EPRule **)realloc(m_ppRuleList, sizeof(EPRule *) * m_dwNumRules);
946 m_ppRuleList[m_dwNumRules - 1] = rule;
947 }
948
949 unlock();
950 }