Legacy console sources removed
[public/netxms.git] / src / server / core / condition.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
9fddfb91 3** Copyright (C) 2003-2013 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: container.cpp
20**
21**/
22
23#include "nxcore.h"
24
21c9acce
VK
25/**
26 * Default constructor
27 */
28Condition::Condition() : NetObj()
5039dede 29{
9fddfb91
VK
30 m_scriptSource = NULL;
31 m_script = NULL;
32 m_dciList = NULL;
33 m_dciCount = 0;
34 m_sourceObject = 0;
35 m_activeStatus = STATUS_MAJOR;
36 m_inactiveStatus = STATUS_NORMAL;
37 m_isActive = false;
38 m_lastPoll = 0;
39 m_queuedForPolling = false;
40 m_activationEventCode = EVENT_CONDITION_ACTIVATED;
41 m_deactivationEventCode = EVENT_CONDITION_DEACTIVATED;
5039dede
AK
42}
43
21c9acce
VK
44/**
45 * Constructor for new objects
46 */
01152a54 47Condition::Condition(bool hidden) : NetObj()
5039dede 48{
9fddfb91
VK
49 m_scriptSource = NULL;
50 m_script = NULL;
51 m_dciList = NULL;
52 m_dciCount = 0;
53 m_sourceObject = 0;
54 m_activeStatus = STATUS_MAJOR;
55 m_inactiveStatus = STATUS_NORMAL;
01152a54 56 m_isHidden = hidden;
9fddfb91
VK
57 m_isActive = false;
58 m_lastPoll = 0;
59 m_queuedForPolling = false;
60 m_activationEventCode = EVENT_CONDITION_ACTIVATED;
61 m_deactivationEventCode = EVENT_CONDITION_DEACTIVATED;
5039dede
AK
62}
63
9fddfb91
VK
64/**
65 * Destructor
66 */
5039dede
AK
67Condition::~Condition()
68{
9fddfb91
VK
69 safe_free(m_dciList);
70 safe_free(m_scriptSource);
71 delete m_script;
5039dede
AK
72}
73
9fddfb91
VK
74/**
75 * Load object from database
76 */
967893bb 77BOOL Condition::CreateFromDB(UINT32 dwId)
5039dede
AK
78{
79 TCHAR szQuery[512];
80 DB_RESULT hResult;
967893bb 81 UINT32 i;
5039dede
AK
82
83 m_dwId = dwId;
84
89135050 85 if (!loadCommonProperties())
5039dede
AK
86 return FALSE;
87
88 // Load properties
89 _sntprintf(szQuery, 512, _T("SELECT activation_event,deactivation_event,")
90 _T("source_object,active_status,inactive_status,")
91 _T("script FROM conditions WHERE id=%d"), dwId);
92 hResult = DBSelect(g_hCoreDB, szQuery);
93 if (hResult == NULL)
94 return FALSE; // Query failed
95
96 if (DBGetNumRows(hResult) == 0)
97 {
98 // No object with given ID in database
99 DBFreeResult(hResult);
100 return FALSE;
101 }
102
9fddfb91
VK
103 m_activationEventCode = DBGetFieldULong(hResult, 0, 0);
104 m_deactivationEventCode = DBGetFieldULong(hResult, 0, 1);
105 m_sourceObject = DBGetFieldULong(hResult, 0, 2);
106 m_activeStatus = DBGetFieldLong(hResult, 0, 3);
107 m_inactiveStatus = DBGetFieldLong(hResult, 0, 4);
108 m_scriptSource = DBGetField(hResult, 0, 5, NULL, 0);
109 DecodeSQLString(m_scriptSource);
5039dede
AK
110
111 DBFreeResult(hResult);
112
113 // Compile script
6b29839d
VK
114 NXSL_Program *p = (NXSL_Program *)NXSLCompile(m_scriptSource, szQuery, 512);
115 if (p != NULL)
116 {
117 m_script = new NXSL_VM(new NXSL_ServerEnv);
118 if (!m_script->load(p))
119 {
120 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "dss", m_dwId, m_szName, m_script->getErrorText());
121 delete_and_null(m_script);
122 }
123 delete p;
124 }
125 else
126 {
127 m_script = NULL;
128 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "dss", m_dwId, m_szName, szQuery);
129 }
5039dede
AK
130
131 // Load DCI map
132 _sntprintf(szQuery, 512, _T("SELECT dci_id,node_id,dci_func,num_polls ")
133 _T("FROM cond_dci_map WHERE condition_id=%d ORDER BY sequence_number"), dwId);
134 hResult = DBSelect(g_hCoreDB, szQuery);
135 if (hResult == NULL)
136 return FALSE; // Query failed
137
9fddfb91
VK
138 m_dciCount = DBGetNumRows(hResult);
139 if (m_dciCount > 0)
5039dede 140 {
9fddfb91
VK
141 m_dciList = (INPUT_DCI *)malloc(sizeof(INPUT_DCI) * m_dciCount);
142 for(i = 0; i < m_dciCount; i++)
5039dede 143 {
9fddfb91
VK
144 m_dciList[i].id = DBGetFieldULong(hResult, i, 0);
145 m_dciList[i].nodeId = DBGetFieldULong(hResult, i, 1);
146 m_dciList[i].function = DBGetFieldLong(hResult, i, 2);
147 m_dciList[i].polls = DBGetFieldLong(hResult, i, 3);
5039dede
AK
148 }
149 }
150 DBFreeResult(hResult);
151
89135050 152 return loadACLFromDB();
5039dede
AK
153}
154
9fddfb91
VK
155/**
156 * Save object to database
157 */
5039dede
AK
158BOOL Condition::SaveToDB(DB_HANDLE hdb)
159{
160 TCHAR *pszEscScript, *pszQuery;
161 DB_RESULT hResult;
162 BOOL bNewObject = TRUE;
967893bb 163 UINT32 i;
5039dede
AK
164
165 LockData();
166
89135050 167 saveCommonProperties(hdb);
5039dede 168
9fddfb91 169 pszEscScript = EncodeSQLString(CHECK_NULL_EX(m_scriptSource));
35f836fe
VK
170 size_t qlen = _tcslen(pszEscScript) + 1024;
171 pszQuery = (TCHAR *)malloc(sizeof(TCHAR) * qlen);
5039dede
AK
172
173 // Check for object's existence in database
35f836fe 174 _sntprintf(pszQuery, qlen, _T("SELECT id FROM conditions WHERE id=%d"), m_dwId);
5039dede
AK
175 hResult = DBSelect(hdb, pszQuery);
176 if (hResult != NULL)
177 {
178 if (DBGetNumRows(hResult) > 0)
179 bNewObject = FALSE;
180 DBFreeResult(hResult);
181 }
182
183 // Form and execute INSERT or UPDATE query
184 if (bNewObject)
185 {
35f836fe
VK
186 _sntprintf(pszQuery, qlen,
187 _T("INSERT INTO conditions (id,activation_event,")
5039dede
AK
188 _T("deactivation_event,source_object,active_status,")
189 _T("inactive_status,script) VALUES (%d,%d,%d,%d,%d,%d,'%s')"),
9fddfb91
VK
190 m_dwId, m_activationEventCode, m_deactivationEventCode,
191 m_sourceObject, m_activeStatus, m_inactiveStatus, pszEscScript);
5039dede
AK
192 }
193 else
194 {
35f836fe
VK
195 _sntprintf(pszQuery, qlen,
196 _T("UPDATE conditions SET activation_event=%d,")
5039dede
AK
197 _T("deactivation_event=%d,source_object=%d,active_status=%d,")
198 _T("inactive_status=%d,script='%s' WHERE id=%d"),
9fddfb91
VK
199 m_activationEventCode, m_deactivationEventCode, m_sourceObject,
200 m_activeStatus, m_inactiveStatus, pszEscScript, m_dwId);
5039dede
AK
201 }
202 free(pszEscScript);
203 DBQuery(hdb, pszQuery);
204
205 // Save DCI mapping
35f836fe 206 _sntprintf(pszQuery, qlen, _T("DELETE FROM cond_dci_map WHERE condition_id=%d"), m_dwId);
5039dede 207 DBQuery(hdb, pszQuery);
9fddfb91 208 for(i = 0; i < m_dciCount; i++)
5039dede 209 {
35f836fe
VK
210 _sntprintf(pszQuery, qlen, _T("INSERT INTO cond_dci_map (condition_id,sequence_number,dci_id,node_id,")
211 _T("dci_func,num_polls) VALUES (%d,%d,%d,%d,%d,%d)"),
9fddfb91
VK
212 m_dwId, i, m_dciList[i].id, m_dciList[i].nodeId,
213 m_dciList[i].function, m_dciList[i].polls);
5039dede
AK
214 DBQuery(hdb, pszQuery);
215 }
216 free(pszQuery);
217
218 // Save access list
89135050 219 saveACLToDB(hdb);
5039dede
AK
220
221 // Unlock object and clear modification flag
01152a54 222 m_isModified = false;
5039dede
AK
223 UnlockData();
224 return TRUE;
225}
226
22ee6d97
VK
227/**
228 * Delete object from database
229 */
230bool Condition::deleteFromDB(DB_HANDLE hdb)
5039dede 231{
22ee6d97
VK
232 bool success = NetObj::deleteFromDB(hdb);
233 if (success)
234 success = executeQueryOnObject(hdb, _T("DELETE FROM conditions WHERE id=?"));
235 if (success)
236 success = executeQueryOnObject(hdb, _T("DELETE FROM cond_dci_map WHERE condition_id=?"));
237 return success;
5039dede
AK
238}
239
22ee6d97
VK
240/**
241 * Create NXCP message from object
242 */
5039dede
AK
243void Condition::CreateMessage(CSCPMessage *pMsg)
244{
967893bb 245 UINT32 i, dwId;
5039dede
AK
246
247 NetObj::CreateMessage(pMsg);
9fddfb91
VK
248 pMsg->SetVariable(VID_SCRIPT, CHECK_NULL_EX(m_scriptSource));
249 pMsg->SetVariable(VID_ACTIVATION_EVENT, m_activationEventCode);
250 pMsg->SetVariable(VID_DEACTIVATION_EVENT, m_deactivationEventCode);
251 pMsg->SetVariable(VID_SOURCE_OBJECT, m_sourceObject);
252 pMsg->SetVariable(VID_ACTIVE_STATUS, (WORD)m_activeStatus);
253 pMsg->SetVariable(VID_INACTIVE_STATUS, (WORD)m_inactiveStatus);
254 pMsg->SetVariable(VID_NUM_ITEMS, m_dciCount);
255 for(i = 0, dwId = VID_DCI_LIST_BASE; (i < m_dciCount) && (dwId < (VID_DCI_LIST_LAST + 1)); i++)
5039dede 256 {
9fddfb91
VK
257 pMsg->SetVariable(dwId++, m_dciList[i].id);
258 pMsg->SetVariable(dwId++, m_dciList[i].nodeId);
259 pMsg->SetVariable(dwId++, (WORD)m_dciList[i].function);
260 pMsg->SetVariable(dwId++, (WORD)m_dciList[i].polls);
261 pMsg->SetVariable(dwId++, (WORD)GetDCObjectType(m_dciList[i].nodeId, m_dciList[i].id));
262 dwId += 5;
5039dede
AK
263 }
264}
265
9fddfb91
VK
266/**
267 * Modify object from NXCP message
268 */
967893bb 269UINT32 Condition::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
5039dede 270{
967893bb 271 UINT32 i, dwId;
5039dede 272 NetObj *pObject;
5039dede
AK
273
274 if (!bAlreadyLocked)
275 LockData();
276
277 // Change script
5c44534b 278 if (pRequest->isFieldExist(VID_SCRIPT))
5039dede
AK
279 {
280 TCHAR szError[1024];
281
9fddfb91
VK
282 safe_free(m_scriptSource);
283 delete m_script;
284 m_scriptSource = pRequest->GetVariableStr(VID_SCRIPT);
6b29839d
VK
285 NXSL_Program *p = (NXSL_Program *)NXSLCompile(m_scriptSource, szError, 1024);
286 if (p != NULL)
287 {
288 m_script = new NXSL_VM(new NXSL_ServerEnv);
289 if (!m_script->load(p))
290 {
291 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "dss", m_dwId, m_szName, m_script->getErrorText());
292 delete_and_null(m_script);
293 }
294 delete p;
295 }
296 else
297 {
298 m_script = NULL;
299 nxlog_write(MSG_COND_SCRIPT_COMPILATION_ERROR, EVENTLOG_ERROR_TYPE, "dss", m_dwId, m_szName, szError);
300 }
5039dede
AK
301 }
302
303 // Change activation event
5c44534b 304 if (pRequest->isFieldExist(VID_ACTIVATION_EVENT))
9fddfb91 305 m_activationEventCode = pRequest->GetVariableLong(VID_ACTIVATION_EVENT);
5039dede
AK
306
307 // Change deactivation event
5c44534b 308 if (pRequest->isFieldExist(VID_DEACTIVATION_EVENT))
9fddfb91 309 m_deactivationEventCode = pRequest->GetVariableLong(VID_DEACTIVATION_EVENT);
5039dede
AK
310
311 // Change source object
5c44534b 312 if (pRequest->isFieldExist(VID_SOURCE_OBJECT))
9fddfb91 313 m_sourceObject = pRequest->GetVariableLong(VID_SOURCE_OBJECT);
5039dede
AK
314
315 // Change active status
5c44534b 316 if (pRequest->isFieldExist(VID_ACTIVE_STATUS))
9fddfb91 317 m_activeStatus = pRequest->GetVariableShort(VID_ACTIVE_STATUS);
5039dede
AK
318
319 // Change inactive status
5c44534b 320 if (pRequest->isFieldExist(VID_INACTIVE_STATUS))
9fddfb91 321 m_inactiveStatus = pRequest->GetVariableShort(VID_INACTIVE_STATUS);
5039dede
AK
322
323 // Change DCI list
5c44534b 324 if (pRequest->isFieldExist(VID_NUM_ITEMS))
5039dede 325 {
9fddfb91
VK
326 safe_free(m_dciList);
327 m_dciCount = pRequest->GetVariableLong(VID_NUM_ITEMS);
328 if (m_dciCount > 0)
5039dede 329 {
9fddfb91
VK
330 m_dciList = (INPUT_DCI *)malloc(sizeof(INPUT_DCI) * m_dciCount);
331 for(i = 0, dwId = VID_DCI_LIST_BASE; (i < m_dciCount) && (dwId < (VID_DCI_LIST_LAST + 1)); i++)
5039dede 332 {
9fddfb91
VK
333 m_dciList[i].id = pRequest->GetVariableLong(dwId++);
334 m_dciList[i].nodeId = pRequest->GetVariableLong(dwId++);
335 m_dciList[i].function = pRequest->GetVariableShort(dwId++);
336 m_dciList[i].polls = pRequest->GetVariableShort(dwId++);
5039dede
AK
337 dwId += 6;
338 }
339
340 // Update cache size of DCIs
9fddfb91 341 for(i = 0; i < m_dciCount; i++)
5039dede 342 {
9fddfb91 343 pObject = FindObjectById(m_dciList[i].nodeId);
5039dede
AK
344 if (pObject != NULL)
345 {
346 if (pObject->Type() == OBJECT_NODE)
347 {
9fddfb91 348 DCObject *pItem = ((Node *)pObject)->getDCObjectById(m_dciList[i].id);
16d6f798 349 if ((pItem != NULL) && (pItem->getType() == DCO_TYPE_ITEM))
5039dede 350 {
16d6f798 351 ((DCItem *)pItem)->updateCacheSize(m_dwId);
5039dede
AK
352 }
353 }
354 }
355 }
356 }
357 else
358 {
9fddfb91 359 m_dciList = NULL;
5039dede
AK
360 }
361 }
362
363 return NetObj::ModifyFromMessage(pRequest, TRUE);
364}
365
21c9acce
VK
366/**
367 * Lock for polling
368 */
9fddfb91 369void Condition::lockForPoll()
5039dede 370{
21c9acce 371 incRefCount();
9fddfb91 372 m_queuedForPolling = TRUE;
5039dede
AK
373}
374
21c9acce
VK
375/**
376 * This method should be called by poller thread when poll finish
377 */
9fddfb91 378void Condition::endPoll()
5039dede
AK
379{
380 LockData();
9fddfb91
VK
381 m_queuedForPolling = FALSE;
382 m_lastPoll = time(NULL);
5039dede 383 UnlockData();
21c9acce 384 decRefCount();
5039dede
AK
385}
386
21c9acce
VK
387/**
388 * Check condition
389 */
3f7c0fe4 390void Condition::check()
5039dede 391{
5039dede
AK
392 NXSL_Value **ppValueList, *pValue;
393 NetObj *pObject;
967893bb 394 UINT32 i, dwNumValues;
5039dede
AK
395 int iOldStatus = m_iStatus;
396
9fddfb91 397 if ((m_script == NULL) || (m_iStatus == STATUS_UNMANAGED))
5039dede
AK
398 return;
399
5039dede 400 LockData();
9fddfb91
VK
401 ppValueList = (NXSL_Value **)malloc(sizeof(NXSL_Value *) * m_dciCount);
402 memset(ppValueList, 0, sizeof(NXSL_Value *) * m_dciCount);
403 for(i = 0; i < m_dciCount; i++)
5039dede 404 {
9fddfb91 405 pObject = FindObjectById(m_dciList[i].nodeId);
5039dede
AK
406 if (pObject != NULL)
407 {
408 if (pObject->Type() == OBJECT_NODE)
409 {
9fddfb91
VK
410 DCObject *pItem = ((Node *)pObject)->getDCObjectById(m_dciList[i].id);
411 if (pItem != NULL)
5039dede 412 {
9fddfb91
VK
413 if (pItem->getType() == DCO_TYPE_ITEM)
414 {
415 ppValueList[i] = ((DCItem *)pItem)->getValueForNXSL(m_dciList[i].function, m_dciList[i].polls);
416 }
417 else if (pItem->getType() == DCO_TYPE_TABLE)
418 {
419 Table *t = ((DCTable *)pItem)->getLastValue();
420 if (t != NULL)
421 {
422 ppValueList[i] = new NXSL_Value(new NXSL_Object(&g_nxslTableClass, t));
423 }
424 }
5039dede
AK
425 }
426 }
427 }
428 if (ppValueList[i] == NULL)
429 ppValueList[i] = new NXSL_Value;
430 }
9fddfb91 431 dwNumValues = m_dciCount;
5039dede
AK
432 UnlockData();
433
22aa5156
VK
434 // Create array from values
435 NXSL_Array *array = new NXSL_Array;
436 for(i = 0; i < dwNumValues; i++)
437 {
438 array->set(i + 1, new NXSL_Value(ppValueList[i]));
439 }
9fddfb91 440 m_script->setGlobalVariable(_T("$values"), new NXSL_Value(array));
22aa5156 441
6b29839d
VK
442 DbgPrintf(6, _T("Running evaluation script for condition %d \"%s\""), m_dwId, m_szName);
443 if (m_script->run(dwNumValues, ppValueList))
5039dede 444 {
9fddfb91 445 pValue = m_script->getResult();
bb5365ed 446 if (pValue->getValueAsInt32() == 0)
5039dede 447 {
9fddfb91 448 if (m_isActive)
5039dede
AK
449 {
450 // Deactivate condition
451 LockData();
9fddfb91
VK
452 m_iStatus = m_inactiveStatus;
453 m_isActive = FALSE;
5039dede
AK
454 Modify();
455 UnlockData();
456
9fddfb91
VK
457 PostEvent(m_deactivationEventCode,
458 (m_sourceObject == 0) ? g_dwMgmtNode : m_sourceObject,
5039dede
AK
459 "dsdd", m_dwId, m_szName, iOldStatus, m_iStatus);
460
461 DbgPrintf(6, _T("Condition %d \"%s\" deactivated"),
462 m_dwId, m_szName);
463 }
464 else
465 {
466 DbgPrintf(6, _T("Condition %d \"%s\" still inactive"),
467 m_dwId, m_szName);
468 LockData();
9fddfb91 469 if (m_iStatus != m_inactiveStatus)
5039dede 470 {
9fddfb91 471 m_iStatus = m_inactiveStatus;
5039dede
AK
472 Modify();
473 }
474 UnlockData();
475 }
476 }
477 else
478 {
9fddfb91 479 if (!m_isActive)
5039dede
AK
480 {
481 // Activate condition
482 LockData();
9fddfb91
VK
483 m_iStatus = m_activeStatus;
484 m_isActive = TRUE;
5039dede
AK
485 Modify();
486 UnlockData();
487
9fddfb91
VK
488 PostEvent(m_activationEventCode,
489 (m_sourceObject == 0) ? g_dwMgmtNode : m_sourceObject,
5039dede
AK
490 "dsdd", m_dwId, m_szName, iOldStatus, m_iStatus);
491
492 DbgPrintf(6, _T("Condition %d \"%s\" activated"),
493 m_dwId, m_szName);
494 }
495 else
496 {
497 DbgPrintf(6, _T("Condition %d \"%s\" still active"),
498 m_dwId, m_szName);
499 LockData();
9fddfb91 500 if (m_iStatus != m_activeStatus)
5039dede 501 {
9fddfb91 502 m_iStatus = m_activeStatus;
5039dede
AK
503 Modify();
504 }
505 UnlockData();
506 }
507 }
508 }
509 else
510 {
511 nxlog_write(MSG_COND_SCRIPT_EXECUTION_ERROR, EVENTLOG_ERROR_TYPE,
9fddfb91 512 "dss", m_dwId, m_szName, m_script->getErrorText());
5039dede
AK
513
514 LockData();
515 if (m_iStatus != STATUS_UNKNOWN)
516 {
517 m_iStatus = STATUS_UNKNOWN;
518 Modify();
519 }
520 UnlockData();
521 }
522 free(ppValueList);
523
524 // Cause parent object(s) to recalculate it's status
525 if (iOldStatus != m_iStatus)
526 {
527 LockParentList(FALSE);
528 for(i = 0; i < m_dwParentCount; i++)
27f9598d 529 m_pParentList[i]->calculateCompoundStatus();
5039dede
AK
530 UnlockParentList();
531 }
532}
533
9fddfb91
VK
534/**
535 * Determine DCI cache size required by condition object
536 */
537int Condition::getCacheSizeForDCI(UINT32 itemId, bool noLock)
5039dede 538{
967893bb 539 UINT32 i;
5039dede
AK
540 int nSize = 0;
541
9fddfb91 542 if (!noLock)
5039dede 543 LockData();
9fddfb91 544 for(i = 0; i < m_dciCount; i++)
5039dede 545 {
9fddfb91 546 if (m_dciList[i].id == itemId)
5039dede 547 {
9fddfb91 548 switch(m_dciList[i].function)
5039dede
AK
549 {
550 case F_LAST:
551 nSize = 1;
552 break;
553 case F_DIFF:
554 nSize = 2;
555 break;
556 default:
9fddfb91 557 nSize = m_dciList[i].polls;
5039dede
AK
558 break;
559 }
560 break;
561 }
562 }
9fddfb91 563 if (!noLock)
5039dede
AK
564 UnlockData();
565 return nSize;
566}