minor refactoring
[public/netxms.git] / src / server / core / epp.cpp
CommitLineData
6f33021d 1/*
5039dede 2** NetXMS - Network Management System
6b29839d 3** Copyright (C) 2003-2014 Victor Kirhenshtein
5039dede
AK
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
480e036b
VK
25/**
26 * Default event policy rule constructor
27 */
c42b4551 28EPRule::EPRule(UINT32 id)
5039dede 29{
c42b4551 30 m_id = id;
de4af576 31 m_guid = uuid::generate();
5039dede
AK
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;
2292ff1d
VK
41 m_szAlarmKey[0] = 0;
42 m_szAlarmMessage[0] = 0;
5039dede
AK
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
2292ff1d
VK
51/**
52 * Create rule from config entry
53 */
54EPRule::EPRule(ConfigEntry *config)
55{
c42b4551 56 m_id = 0;
de4af576 57 m_guid = config->getSubEntryValueAsUUID(_T("guid"));
31b0f68b 58 m_dwFlags = config->getSubEntryValueAsUInt(_T("flags"));
2292ff1d
VK
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 {
8b7ae7eb 67 ObjectArray<ConfigEntry> *events = eventsRoot->getSubEntries(_T("event#*"));
2292ff1d 68 m_dwNumEvents = 0;
8b7ae7eb
VK
69 m_pdwEventList = (UINT32 *)malloc(sizeof(UINT32) * events->size());
70 for(int i = 0; i < events->size(); i++)
2292ff1d 71 {
8b7ae7eb 72 EVENT_TEMPLATE *e = FindEventTemplateByName(events->get(i)->getSubEntryValue(_T("name"), 0, _T("<unknown>")));
2292ff1d
VK
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("")));
31b0f68b
VK
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);
2292ff1d
VK
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
6b29839d 95 m_pScript = NXSLCompileAndCreateVM(m_pszScript, szError, 256, new NXSL_ServerEnv);
2292ff1d
VK
96 if (m_pScript != NULL)
97 {
98 m_pScript->setGlobalVariable(_T("CUSTOM_MESSAGE"), new NXSL_Value(_T("")));
99 }
100 else
101 {
c42b4551 102 nxlog_write(MSG_EPRULE_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "ds", m_id, szError);
2292ff1d
VK
103 }
104 }
105 else
106 {
107 m_pScript = NULL;
108 }
109}
110
480e036b
VK
111/**
112 * Construct event policy rule from database record
113 * Assuming the following field order:
badf9a95 114 * rule_id,rule_guid,flags,comments,alarm_message,alarm_severity,alarm_key,script,
480e036b
VK
115 * alarm_timeout,alarm_timeout_event,situation_id,situation_instance
116 */
c42b4551 117EPRule::EPRule(DB_RESULT hResult, int row)
5039dede 118{
c42b4551 119 m_id = DBGetFieldULong(hResult, row, 0);
de4af576 120 m_guid = DBGetFieldGUID(hResult, row, 1);
c42b4551
VK
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);
5039dede
AK
127 if ((m_pszScript != NULL) && (*m_pszScript != 0))
128 {
129 TCHAR szError[256];
130
6b29839d 131 m_pScript = NXSLCompileAndCreateVM(m_pszScript, szError, 256, new NXSL_ServerEnv);
5039dede
AK
132 if (m_pScript != NULL)
133 {
bb5365ed 134 m_pScript->setGlobalVariable(_T("CUSTOM_MESSAGE"), new NXSL_Value(_T("")));
5039dede
AK
135 }
136 else
137 {
138 nxlog_write(MSG_EPRULE_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE,
c42b4551 139 "ds", m_id, szError);
5039dede
AK
140 }
141 }
142 else
143 {
144 m_pScript = NULL;
145 }
c42b4551
VK
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);
5039dede
AK
150}
151
480e036b
VK
152/**
153 * Construct event policy rule from NXCP message
154 */
b368969c 155EPRule::EPRule(NXCPMessage *msg)
5039dede 156{
967893bb 157 UINT32 i, id, count;
5039dede 158 TCHAR *name, *value;
6f33021d 159
b368969c
VK
160 m_dwFlags = msg->getFieldAsUInt32(VID_FLAGS);
161 m_id = msg->getFieldAsUInt32(VID_RULE_ID);
de4af576 162 m_guid = msg->getFieldAsGUID(VID_GUID);
b368969c 163 m_pszComment = msg->getFieldAsString(VID_COMMENTS);
5039dede 164
b368969c 165 m_dwNumActions = msg->getFieldAsUInt32(VID_NUM_ACTIONS);
967893bb 166 m_pdwActionList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumActions);
c42b4551 167 msg->getFieldAsInt32Array(VID_RULE_ACTIONS, m_dwNumActions, m_pdwActionList);
5039dede 168
b368969c 169 m_dwNumEvents = msg->getFieldAsUInt32(VID_NUM_EVENTS);
967893bb 170 m_pdwEventList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumEvents);
c42b4551 171 msg->getFieldAsInt32Array(VID_RULE_EVENTS, m_dwNumEvents, m_pdwEventList);
5039dede 172
b368969c 173 m_dwNumSources = msg->getFieldAsUInt32(VID_NUM_SOURCES);
967893bb 174 m_pdwSourceList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumSources);
c42b4551 175 msg->getFieldAsInt32Array(VID_RULE_SOURCES, m_dwNumSources, m_pdwSourceList);
5039dede 176
b368969c
VK
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);
5039dede 182
b368969c
VK
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);
5039dede
AK
186 for(i = 0, id = VID_SITUATION_ATTR_LIST_BASE; i < count; i++)
187 {
b368969c
VK
188 name = msg->getFieldAsString(id++);
189 value = msg->getFieldAsString(id++);
fb986055 190 m_situationAttrList.setPreallocated(name, value);
5039dede
AK
191 }
192
b368969c 193 m_pszScript = msg->getFieldAsString(VID_SCRIPT);
5039dede
AK
194 if ((m_pszScript != NULL) && (*m_pszScript != 0))
195 {
196 TCHAR szError[256];
197
6b29839d 198 m_pScript = NXSLCompileAndCreateVM(m_pszScript, szError, 256, new NXSL_ServerEnv);
5039dede
AK
199 if (m_pScript != NULL)
200 {
bb5365ed 201 m_pScript->setGlobalVariable(_T("CUSTOM_MESSAGE"), new NXSL_Value(_T("")));
5039dede
AK
202 }
203 else
204 {
c42b4551 205 nxlog_write(MSG_EPRULE_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "ds", m_id, szError);
5039dede
AK
206 }
207 }
208 else
209 {
210 m_pScript = NULL;
211 }
212}
213
480e036b
VK
214/**
215 * Event policy rule destructor
216 */
5039dede
AK
217EPRule::~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
badf9a95
VK
227/**
228 * Create management pack record
229 */
230void EPRule::createNXMPRecord(String &str)
231{
4e0e77e6 232 str.appendFormattedString(_T("\t\t<rule id=\"%d\">\n")
2f431c19
VK
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"),
c42b4551 244 m_id, m_dwFlags,
2f431c19
VK
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 {
2f431c19 257 TCHAR guidText[128];
4e0e77e6 258 str.appendFormattedString(_T("\t\t\t\t<source id=\"%d\">\n")
2f431c19
VK
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"),
c42b4551
VK
263 object->getId(),
264 (const TCHAR *)EscapeStringForXML2(object->getName()),
de4af576 265 object->getGuid().toString(guidText), object->getObjectClass());
2f431c19
VK
266 }
267 }
6f33021d 268
2f431c19 269 str += _T("\t\t\t</sources>\n\t\t\t<events>\n");
badf9a95 270
2f431c19
VK
271 for(UINT32 i = 0; i < m_dwNumEvents; i++)
272 {
273 TCHAR eventName[MAX_EVENT_NAME];
274 EventNameFromCode(m_pdwEventList[i], eventName);
4e0e77e6 275 str.appendFormattedString(_T("\t\t\t\t<event id=\"%d\">\n")
2f431c19
VK
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 {
4e0e77e6 285 str.appendFormattedString(_T("\t\t\t\t<action id=\"%d\">\n")
2f431c19
VK
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");
badf9a95
VK
291}
292
480e036b
VK
293/**
294 * Check if source object's id match to the rule
295 */
967893bb 296bool EPRule::matchSource(UINT32 dwObjectId)
5039dede 297{
967893bb 298 UINT32 i;
5039dede 299 NetObj *pObject;
0688e29b 300 bool bMatch = FALSE;
5039dede
AK
301
302 if (m_dwNumSources == 0) // No sources in list means "any"
303 {
0688e29b 304 bMatch = true;
5039dede
AK
305 }
306 else
307 {
308 for(i = 0; i < m_dwNumSources; i++)
309 if (m_pdwSourceList[i] == dwObjectId)
310 {
0688e29b 311 bMatch = true;
5039dede
AK
312 break;
313 }
314 else
315 {
316 pObject = FindObjectById(m_pdwSourceList[i]);
317 if (pObject != NULL)
318 {
21c9acce 319 if (pObject->isChild(dwObjectId))
5039dede 320 {
0688e29b 321 bMatch = true;
5039dede
AK
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
0688e29b
VK
334/**
335 * Check if event's id match to the rule
336 */
967893bb 337bool EPRule::matchEvent(UINT32 dwEventCode)
5039dede 338{
967893bb 339 UINT32 i;
0688e29b 340 bool bMatch = false;
5039dede
AK
341
342 if (m_dwNumEvents == 0) // No sources in list means "any"
343 {
0688e29b 344 bMatch = true;
5039dede
AK
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 {
0688e29b 357 bMatch = true;
5039dede
AK
358 break;
359 }
360 }
361 }
362 return (m_dwFlags & RF_NEGATED_EVENTS) ? !bMatch : bMatch;
363}
364
0688e29b
VK
365/**
366 * Check if event's severity match to the rule
367 */
967893bb 368bool EPRule::matchSeverity(UINT32 dwSeverity)
5039dede 369{
967893bb 370 static UINT32 dwSeverityFlag[] = { RF_SEVERITY_INFO, RF_SEVERITY_WARNING,
5039dede
AK
371 RF_SEVERITY_MINOR, RF_SEVERITY_MAJOR,
372 RF_SEVERITY_CRITICAL };
0688e29b 373 return (dwSeverityFlag[dwSeverity] & m_dwFlags) ? true : false;
5039dede
AK
374}
375
0688e29b
VK
376/**
377 * Check if event match to the script
378 */
379bool EPRule::matchScript(Event *pEvent)
5039dede 380{
5039dede
AK
381 NXSL_Value **ppValueList, *pValue;
382 NXSL_VariableSystem *pLocals, *pGlobals = NULL;
0688e29b 383 bool bRet = true;
967893bb 384 UINT32 i;
5039dede
AK
385 NetObj *pObject;
386
387 if (m_pScript == NULL)
0688e29b 388 return true;
5039dede 389
5039dede
AK
390 // Pass event's parameters as arguments and
391 // other information as variables
210642a1
VK
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));
5039dede
AK
396
397 pLocals = new NXSL_VariableSystem;
bb5365ed
VK
398 pLocals->create(_T("EVENT_CODE"), new NXSL_Value(pEvent->getCode()));
399 pLocals->create(_T("SEVERITY"), new NXSL_Value(pEvent->getSeverity()));
6fec127d 400 pLocals->create(_T("SEVERITY_TEXT"), new NXSL_Value(GetStatusAsText(pEvent->getSeverity(), true)));
bb5365ed
VK
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()));
210642a1 404 pObject = FindObjectById(pEvent->getSourceId());
5039dede
AK
405 if (pObject != NULL)
406 {
c42b4551 407 if (pObject->getObjectClass() == OBJECT_NODE)
bb5365ed 408 m_pScript->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, pObject)));
5039dede 409 }
bb5365ed
VK
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);
5039dede
AK
412
413 // Run script
6b29839d 414 if (m_pScript->run(pEvent->getParametersCount(), ppValueList, pLocals, &pGlobals))
5039dede 415 {
bb5365ed 416 pValue = m_pScript->getResult();
5039dede
AK
417 if (pValue != NULL)
418 {
0688e29b 419 bRet = pValue->getValueAsInt32() ? true : false;
5039dede
AK
420 if (bRet)
421 {
422 NXSL_Variable *var;
6f33021d 423
bb5365ed 424 var = pGlobals->find(_T("CUSTOM_MESSAGE"));
5039dede
AK
425 if (var != NULL)
426 {
427 // Update custom message in event
bb5365ed 428 pEvent->setCustomMessage(CHECK_NULL_EX(var->getValue()->getValueAsCString()));
5039dede
AK
429 }
430 }
431 }
432 }
433 else
434 {
c42b4551 435 nxlog_write(MSG_EPRULE_SCRIPT_EXECUTION_ERROR, EVENTLOG_ERROR_TYPE, "ds", m_id + 1, m_pScript->getErrorText());
5039dede
AK
436 }
437 free(ppValueList);
438 delete pGlobals;
439
440 return bRet;
441}
442
400e55c4
VK
443/**
444 * Situation update callback data
445 */
446struct SituationUpdateCallbackData
447{
448 Situation *s;
449 TCHAR *text;
450 Event *evt;
451};
452
453/**
454 * Situation update callback
455 */
53c3d1e7 456static EnumerationCallbackResult SituationUpdateCallback(const TCHAR *key, const void *value, void *data)
400e55c4
VK
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);
53c3d1e7 463 return _CONTINUE;
400e55c4
VK
464}
465
0688e29b
VK
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 */
470bool EPRule::processEvent(Event *pEvent)
5039dede 471{
0688e29b 472 bool bStopProcessing = false;
5039dede
AK
473
474 // Check disable flag
475 if (!(m_dwFlags & RF_DISABLED))
476 {
477 // Check if event match
0688e29b
VK
478 if (matchSource(pEvent->getSourceId()) && matchEvent(pEvent->getCode()) &&
479 matchSeverity(pEvent->getSeverity()) && matchScript(pEvent))
5039dede 480 {
c42b4551 481 DbgPrintf(6, _T("Event ") UINT64_FMT _T(" match EPP rule %d"), pEvent->getId(), (int)m_id);
c0b3992a 482
5039dede
AK
483 // Generate alarm if requested
484 if (m_dwFlags & RF_GENERATE_ALARM)
0688e29b 485 generateAlarm(pEvent);
5039dede
AK
486
487 // Event matched, perform actions
488 if (m_dwNumActions > 0)
489 {
ca0e18d2
VK
490 TCHAR *alarmMessage = pEvent->expandText(m_szAlarmMessage);
491 TCHAR *alarmKey = pEvent->expandText(m_szAlarmKey);
a6312bd6 492 for(UINT32 i = 0; i < m_dwNumActions; i++)
ca0e18d2
VK
493 ExecuteAction(m_pdwActionList[i], pEvent, alarmMessage, alarmKey);
494 free(alarmMessage);
495 free(alarmKey);
5039dede
AK
496 }
497
498 // Update situation of needed
499 if (m_dwSituationId != 0)
500 {
400e55c4 501 Situation *pSituation = FindSituationById(m_dwSituationId);
5039dede
AK
502 if (pSituation != NULL)
503 {
400e55c4
VK
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);
5039dede
AK
510 }
511 else
512 {
513 DbgPrintf(3, _T("Event Policy: unable to find situation with ID=%d"), m_dwSituationId);
514 }
515 }
516
0688e29b 517 bStopProcessing = (m_dwFlags & RF_STOP_PROCESSING) ? true : false;
5039dede
AK
518 }
519 }
520
521 return bStopProcessing;
522}
523
480e036b
VK
524/**
525 * Generate alarm from event
526 */
0688e29b 527void EPRule::generateAlarm(Event *pEvent)
5039dede 528{
5039dede 529 // Terminate alarms with key == our ack_key
5f6bc78c 530 if ((m_iAlarmSeverity == SEVERITY_RESOLVE) || (m_iAlarmSeverity == SEVERITY_TERMINATE))
5039dede 531 {
c0b3992a 532 TCHAR *pszAckKey = pEvent->expandText(m_szAlarmKey);
5039dede 533 if (pszAckKey[0] != 0)
da84c57a 534 ResolveAlarmByKey(pszAckKey, (m_dwFlags & RF_TERMINATE_BY_REGEXP) ? true : false, m_iAlarmSeverity == SEVERITY_TERMINATE, pEvent);
5039dede
AK
535 free(pszAckKey);
536 }
537 else // Generate new alarm
538 {
da84c57a
VK
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);
5039dede
AK
542 }
543}
544
480e036b
VK
545/**
546 * Load rule from database
547 */
0688e29b 548bool EPRule::loadFromDB()
5039dede
AK
549{
550 DB_RESULT hResult;
35f836fe 551 TCHAR szQuery[256], name[MAX_DB_STRING], value[MAX_DB_STRING];
0688e29b 552 bool bSuccess = true;
967893bb 553 UINT32 i, count;
6f33021d 554
5039dede 555 // Load rule's sources
c42b4551 556 _sntprintf(szQuery, 256, _T("SELECT object_id FROM policy_source_list WHERE rule_id=%d"), m_id);
5039dede
AK
557 hResult = DBSelect(g_hCoreDB, szQuery);
558 if (hResult != NULL)
559 {
560 m_dwNumSources = DBGetNumRows(hResult);
967893bb 561 m_pdwSourceList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumSources);
5039dede
AK
562 for(i = 0; i < m_dwNumSources; i++)
563 m_pdwSourceList[i] = DBGetFieldULong(hResult, i, 0);
564 DBFreeResult(hResult);
565 }
566 else
567 {
0688e29b 568 bSuccess = false;
5039dede
AK
569 }
570
571 // Load rule's events
c42b4551 572 _sntprintf(szQuery, 256, _T("SELECT event_code FROM policy_event_list WHERE rule_id=%d"), m_id);
5039dede
AK
573 hResult = DBSelect(g_hCoreDB, szQuery);
574 if (hResult != NULL)
575 {
576 m_dwNumEvents = DBGetNumRows(hResult);
967893bb 577 m_pdwEventList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumEvents);
5039dede
AK
578 for(i = 0; i < m_dwNumEvents; i++)
579 m_pdwEventList[i] = DBGetFieldULong(hResult, i, 0);
580 DBFreeResult(hResult);
581 }
582 else
583 {
0688e29b 584 bSuccess = false;
5039dede
AK
585 }
586
587 // Load rule's actions
c42b4551 588 _sntprintf(szQuery, 256, _T("SELECT action_id FROM policy_action_list WHERE rule_id=%d"), m_id);
5039dede
AK
589 hResult = DBSelect(g_hCoreDB, szQuery);
590 if (hResult != NULL)
591 {
592 m_dwNumActions = DBGetNumRows(hResult);
967893bb 593 m_pdwActionList = (UINT32 *)malloc(sizeof(UINT32) * m_dwNumActions);
5039dede
AK
594 for(i = 0; i < m_dwNumActions; i++)
595 m_pdwActionList[i] = DBGetFieldULong(hResult, i, 0);
596 DBFreeResult(hResult);
597 }
598 else
599 {
0688e29b 600 bSuccess = false;
5039dede 601 }
6f33021d 602
5039dede 603 // Load situation attributes
c42b4551 604 _sntprintf(szQuery, 256, _T("SELECT attr_name,attr_value FROM policy_situation_attr_list WHERE rule_id=%d"), m_id);
5039dede
AK
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);
5039dede 612 DBGetField(hResult, i, 1, value, MAX_DB_STRING);
fb986055 613 m_situationAttrList.set(name, value);
5039dede
AK
614 }
615 DBFreeResult(hResult);
616 }
617 else
618 {
0688e29b 619 bSuccess = false;
5039dede
AK
620 }
621
622 return bSuccess;
623}
624
400e55c4
VK
625/**
626 * Callback for saving situation attributes
627 */
53c3d1e7 628static EnumerationCallbackResult SaveSituationAttribute(const TCHAR *key, const void *value, void *data)
400e55c4
VK
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);
53c3d1e7 634 return _CONTINUE;
400e55c4
VK
635}
636
480e036b
VK
637/**
638 * Save rule to database
639 */
0688e29b 640void EPRule::saveToDB(DB_HANDLE hdb)
5039dede 641{
967893bb 642 UINT32 len = (UINT32)(_tcslen(CHECK_NULL(m_pszComment)) + _tcslen(CHECK_NULL(m_pszScript)) + 4096);
480e036b 643 TCHAR *pszQuery = (TCHAR *)malloc(len * sizeof(TCHAR));
5039dede
AK
644
645 // General attributes
badf9a95
VK
646 TCHAR guidText[128];
647 _sntprintf(pszQuery, len, _T("INSERT INTO event_policy (rule_id,rule_guid,flags,comments,alarm_message,")
5039dede
AK
648 _T("alarm_severity,alarm_key,script,alarm_timeout,alarm_timeout_event,")
649 _T("situation_id,situation_instance) ")
badf9a95 650 _T("VALUES (%d,'%s',%d,%s,%s,%d,%s,%s,%d,%d,%d,%s)"),
de4af576 651 m_id, m_guid.toString(guidText), m_dwFlags, (const TCHAR *)DBPrepareString(hdb, m_pszComment),
480e036b
VK
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);
5039dede
AK
657
658 // Actions
a6312bd6
VK
659 int i;
660 for(i = 0; i < (int)m_dwNumActions; i++)
5039dede 661 {
35f836fe 662 _sntprintf(pszQuery, len, _T("INSERT INTO policy_action_list (rule_id,action_id) VALUES (%d,%d)"),
c42b4551 663 m_id, m_pdwActionList[i]);
480e036b 664 DBQuery(hdb, pszQuery);
5039dede
AK
665 }
666
667 // Events
a6312bd6 668 for(i = 0; i < (int)m_dwNumEvents; i++)
5039dede 669 {
35f836fe 670 _sntprintf(pszQuery, len, _T("INSERT INTO policy_event_list (rule_id,event_code) VALUES (%d,%d)"),
c42b4551 671 m_id, m_pdwEventList[i]);
480e036b 672 DBQuery(hdb, pszQuery);
5039dede
AK
673 }
674
675 // Sources
a6312bd6 676 for(i = 0; i < (int)m_dwNumSources; i++)
5039dede 677 {
35f836fe 678 _sntprintf(pszQuery, len, _T("INSERT INTO policy_source_list (rule_id,object_id) VALUES (%d,%d)"),
c42b4551 679 m_id, m_pdwSourceList[i]);
480e036b 680 DBQuery(hdb, pszQuery);
5039dede
AK
681 }
682
683 // Situation attributes
400e55c4
VK
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 {
c42b4551 689 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_id);
400e55c4
VK
690 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_dwSituationId);
691 m_situationAttrList.forEach(SaveSituationAttribute, hStmt);
692 DBFreeStatement(hStmt);
693 }
694 }
5039dede
AK
695
696 free(pszQuery);
697}
698
480e036b
VK
699/**
700 * Create NXCP message with rule's data
701 */
b368969c 702void EPRule::createMessage(NXCPMessage *msg)
5039dede 703{
b368969c
VK
704 msg->setField(VID_FLAGS, m_dwFlags);
705 msg->setField(VID_RULE_ID, m_id);
de4af576 706 msg->setField(VID_GUID, m_guid);
b368969c
VK
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);
c42b4551 722 m_situationAttrList.fillMessage(msg, VID_SITUATION_NUM_ATTRS, VID_SITUATION_ATTR_LIST_BASE);
5039dede
AK
723}
724
0688e29b
VK
725/**
726 * Check if given action is used within rule
727 */
967893bb 728bool EPRule::isActionInUse(UINT32 dwActionId)
5039dede 729{
967893bb 730 UINT32 i;
5039dede
AK
731
732 for(i = 0; i < m_dwNumActions; i++)
733 if (m_pdwActionList[i] == dwActionId)
0688e29b
VK
734 return true;
735 return false;
5039dede
AK
736}
737
0688e29b
VK
738/**
739 * Event processing policy constructor
740 */
5039dede
AK
741EventPolicy::EventPolicy()
742{
743 m_dwNumRules = 0;
744 m_ppRuleList = NULL;
745 m_rwlock = RWLockCreate();
746}
747
0688e29b
VK
748/**
749 * Event processing policy destructor
750 */
5039dede
AK
751EventPolicy::~EventPolicy()
752{
0688e29b 753 clear();
5039dede
AK
754 RWLockDestroy(m_rwlock);
755}
756
0688e29b
VK
757/**
758 * Clear existing policy
759 */
760void EventPolicy::clear()
5039dede 761{
967893bb 762 UINT32 i;
5039dede
AK
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
480e036b
VK
770/**
771 * Load event processing policy from database
772 */
0688e29b 773bool EventPolicy::loadFromDB()
5039dede
AK
774{
775 DB_RESULT hResult;
0688e29b 776 bool bSuccess = false;
5039dede 777
badf9a95 778 hResult = DBSelect(g_hCoreDB, _T("SELECT rule_id,rule_guid,flags,comments,alarm_message,")
5039dede
AK
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 {
967893bb 784 UINT32 i;
5039dede 785
0688e29b 786 bSuccess = true;
5039dede
AK
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);
0688e29b 792 bSuccess = bSuccess && m_ppRuleList[i]->loadFromDB();
5039dede
AK
793 }
794 DBFreeResult(hResult);
795 }
796
797 return bSuccess;
798}
799
480e036b
VK
800/**
801 * Save event processing policy to database
802 */
0688e29b 803void EventPolicy::saveToDB()
5039dede 804{
967893bb 805 UINT32 i;
5039dede 806
480e036b
VK
807 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
808
0688e29b 809 readLock();
480e036b
VK
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"));
5039dede 816 for(i = 0; i < m_dwNumRules; i++)
0688e29b 817 m_ppRuleList[i]->saveToDB(hdb);
480e036b 818 DBCommit(hdb);
0688e29b 819 unlock();
480e036b 820 DBConnectionPoolReleaseConnection(hdb);
5039dede
AK
821}
822
0688e29b
VK
823/**
824 * Pass event through policy
825 */
826void EventPolicy::processEvent(Event *pEvent)
5039dede 827{
967893bb 828 UINT32 i;
5039dede 829
c0b3992a 830 DbgPrintf(7, _T("EPP: processing event ") UINT64_FMT, pEvent->getId());
0688e29b 831 readLock();
5039dede 832 for(i = 0; i < m_dwNumRules; i++)
0688e29b 833 if (m_ppRuleList[i]->processEvent(pEvent))
c0b3992a
VK
834 {
835 DbgPrintf(7, _T("EPP: got \"stop processing\" flag for event ") UINT64_FMT _T(" at rule %d"), pEvent->getId(), i + 1);
5039dede 836 break; // EPRule::ProcessEvent() return TRUE if we should stop processing this event
c0b3992a 837 }
0688e29b 838 unlock();
5039dede
AK
839}
840
0688e29b
VK
841/**
842 * Send event policy to client
843 */
967893bb 844void EventPolicy::sendToClient(ClientSession *pSession, UINT32 dwRqId)
5039dede 845{
967893bb 846 UINT32 i;
b368969c 847 NXCPMessage msg;
5039dede 848
0688e29b 849 readLock();
b368969c
VK
850 msg.setCode(CMD_EPP_RECORD);
851 msg.setId(dwRqId);
5039dede
AK
852 for(i = 0; i < m_dwNumRules; i++)
853 {
0688e29b 854 m_ppRuleList[i]->createMessage(&msg);
e05b1945 855 pSession->sendMessage(&msg);
b368969c 856 msg.deleteAllFields();
5039dede 857 }
0688e29b 858 unlock();
5039dede
AK
859}
860
0688e29b
VK
861/**
862 * Replace policy with new one
863 */
967893bb 864void EventPolicy::replacePolicy(UINT32 dwNumRules, EPRule **ppRuleList)
5039dede 865{
967893bb 866 UINT32 i;
5039dede 867
0688e29b 868 writeLock();
5039dede
AK
869
870 // Replace rule list
0688e29b 871 clear();
5039dede
AK
872 m_dwNumRules = dwNumRules;
873 m_ppRuleList = ppRuleList;
874
875 // Replace id's in rules
876 for(i = 0; i < m_dwNumRules; i++)
0688e29b 877 m_ppRuleList[i]->setId(i);
6f33021d 878
0688e29b 879 unlock();
5039dede
AK
880}
881
0688e29b
VK
882/**
883 * Check if given action is used in policy
884 */
967893bb 885bool EventPolicy::isActionInUse(UINT32 dwActionId)
5039dede 886{
0688e29b 887 bool bResult = false;
5039dede 888
0688e29b 889 readLock();
5039dede 890
2f431c19 891 for(UINT32 i = 0; i < m_dwNumRules; i++)
0688e29b 892 if (m_ppRuleList[i]->isActionInUse(dwActionId))
5039dede 893 {
0688e29b 894 bResult = true;
5039dede
AK
895 break;
896 }
897
0688e29b 898 unlock();
5039dede
AK
899 return bResult;
900}
2f431c19
VK
901
902/**
903 * Export rule
904 */
de4af576 905void EventPolicy::exportRule(String& str, const uuid& guid)
2f431c19
VK
906{
907 readLock();
908 for(UINT32 i = 0; i < m_dwNumRules; i++)
909 {
4e5e861c 910 if (guid.equals(m_ppRuleList[i]->getGuid()))
2f431c19
VK
911 {
912 m_ppRuleList[i]->createNXMPRecord(str);
913 break;
914 }
915 }
916 unlock();
917}
2292ff1d
VK
918
919/**
c4a6167c 920 * Import rule
2292ff1d 921 */
c4a6167c 922void EventPolicy::importRule(EPRule *rule)
2292ff1d
VK
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 {
4e5e861c 930 if (rule->getGuid().equals(m_ppRuleList[i]->getGuid()))
2292ff1d
VK
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}