fixed bug in instance discovery DCI deletion
[public/netxms.git] / src / server / core / dctarget.cpp
CommitLineData
1babf64d 1/*
6fd6de0a 2** NetXMS - Network Management System
6b29839d 3** Copyright (C) 2003-2014 Victor Kirhenshtein
6fd6de0a
VK
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: dctarget.cpp
20**
21**/
22
23#include "nxcore.h"
24
25/**
26 * Default constructor
27 */
28DataCollectionTarget::DataCollectionTarget() : Template()
29{
ebb2dc70
VK
30 m_pingLastTimeStamp = 0;
31 m_pingTime = PING_TIME_TIMEOUT;
6fd6de0a
VK
32}
33
34/**
35 * Constructor for creating new data collection capable objects
36 */
37DataCollectionTarget::DataCollectionTarget(const TCHAR *name) : Template(name)
38{
ebb2dc70
VK
39 m_pingLastTimeStamp = 0;
40 m_pingTime = PING_TIME_TIMEOUT;
6fd6de0a
VK
41}
42
43/**
44 * Destructor
45 */
46DataCollectionTarget::~DataCollectionTarget()
47{
ebb2dc70
VK
48 m_pingLastTimeStamp = 0;
49 m_pingTime = PING_TIME_TIMEOUT;
6fd6de0a
VK
50}
51
52/**
53 * Delete object from database
54 */
c42b4551 55bool DataCollectionTarget::deleteFromDatabase(DB_HANDLE hdb)
6fd6de0a 56{
c42b4551 57 bool success = Template::deleteFromDatabase(hdb);
22ee6d97 58 if (success)
6fd6de0a 59 {
b6aff59d
VK
60 const TCHAR *cascade = _T("");
61 switch(g_dbSyntax)
22aaa779 62 {
b6aff59d
VK
63 case DB_SYNTAX_ORACLE:
64 cascade = _T("CASCADE CONSTRAINTS PURGE");
65 break;
66 case DB_SYNTAX_PGSQL:
67 cascade = _T("CASCADE");
68 break;
22aaa779 69 }
b6aff59d
VK
70
71 TCHAR query[256];
72 _sntprintf(query, 256, _T("DROP TABLE idata_%d"), (int)m_id);
73 QueueSQLRequest(query);
74
75 _sntprintf(query, 256, _T("DROP TABLE tdata_rows_%d %s"), (int)m_id, cascade);
76 QueueSQLRequest(query);
77
78 _sntprintf(query, 256, _T("DROP TABLE tdata_records_%d %s"), (int)m_id, cascade);
79 QueueSQLRequest(query);
80
81 _sntprintf(query, 256, _T("DROP TABLE tdata_%d %s"), (int)m_id, cascade);
82 QueueSQLRequest(query);
6fd6de0a 83 }
22ee6d97 84 return success;
6fd6de0a
VK
85}
86
87/**
88 * Create NXCP message with object's data
89 */
8fe90adb 90void DataCollectionTarget::fillMessageInternal(NXCPMessage *msg)
6fd6de0a 91{
8fe90adb 92 Template::fillMessageInternal(msg);
9289a3bb
VK
93}
94
95/**
96 * Create NXCP message with object's data - stage 2
97 */
98void DataCollectionTarget::fillMessageInternalStage2(NXCPMessage *msg)
99{
100 Template::fillMessageInternalStage2(msg);
1fa2ca0e 101
928fca65
VK
102 // Sent all DCIs marked for display on overview page or in tooltips
103 UINT32 fieldIdOverview = VID_OVERVIEW_DCI_LIST_BASE;
104 UINT32 countOverview = 0;
105 UINT32 fieldIdTooltip = VID_TOOLTIP_DCI_LIST_BASE;
106 UINT32 countTooltip = 0;
1fa2ca0e
VK
107 lockDciAccess(false);
108 for(int i = 0; i < m_dcObjects->size(); i++)
109 {
110 DCObject *dci = m_dcObjects->get(i);
928fca65
VK
111 if ((dci->getType() == DCO_TYPE_ITEM) &&
112 (dci->getStatus() == ITEM_STATUS_ACTIVE) &&
113 (((DCItem *)dci)->getInstanceDiscoveryMethod() == IDM_NONE))
1fa2ca0e 114 {
928fca65
VK
115 if (dci->isShowInObjectOverview())
116 {
117 countOverview++;
118 ((DCItem *)dci)->fillLastValueMessage(msg, fieldIdOverview);
119 fieldIdOverview += 50;
120 }
121 if (dci->isShowOnObjectTooltip())
122 {
123 countTooltip++;
124 ((DCItem *)dci)->fillLastValueMessage(msg, fieldIdTooltip);
125 fieldIdTooltip += 50;
126 }
1fa2ca0e
VK
127 }
128 }
129 unlockDciAccess();
928fca65
VK
130 msg->setField(VID_OVERVIEW_DCI_COUNT, countOverview);
131 msg->setField(VID_TOOLTIP_DCI_COUNT, countTooltip);
6fd6de0a
VK
132}
133
134/**
135 * Modify object from message
136 */
8fe90adb 137UINT32 DataCollectionTarget::modifyFromMessageInternal(NXCPMessage *pRequest)
6fd6de0a 138{
8fe90adb 139 return Template::modifyFromMessageInternal(pRequest);
6fd6de0a
VK
140}
141
142/**
143 * Update cache for all DCI's
144 */
145void DataCollectionTarget::updateDciCache()
146{
b06436f4 147 lockDciAccess(false);
6fd6de0a
VK
148 for(int i = 0; i < m_dcObjects->size(); i++)
149 {
150 if (m_dcObjects->get(i)->getType() == DCO_TYPE_ITEM)
151 {
152 ((DCItem *)m_dcObjects->get(i))->updateCacheSize();
153 }
154 }
155 unlockDciAccess();
156}
157
158/**
159 * Clean expired DCI data
160 */
5f648670 161void DataCollectionTarget::cleanDCIData(DB_HANDLE hdb)
6fd6de0a 162{
5f648670
VK
163 String queryItems = _T("DELETE FROM idata_");
164 queryItems.append(m_id);
165 queryItems.append(_T(" WHERE "));
166
167 String queryTables = _T("DELETE FROM tdata_");
168 queryTables.append(m_id);
169 queryTables.append(_T(" WHERE "));
170
171 int itemCount = 0;
172 int tableCount = 0;
173 time_t now = time(NULL);
174
b06436f4 175 lockDciAccess(false);
6fd6de0a 176 for(int i = 0; i < m_dcObjects->size(); i++)
5f648670
VK
177 {
178 DCObject *o = m_dcObjects->get(i);
179 if (o->getType() == DCO_TYPE_ITEM)
180 {
181 if (itemCount > 0)
182 queryItems.append(_T(" OR "));
183 queryItems.append(_T("(item_id="));
184 queryItems.append(o->getId());
185 queryItems.append(_T(" AND idata_timestamp<"));
90e3031f 186 queryItems.append((INT64)(now - o->getEffectiveRetentionTime() * 86400));
5f648670
VK
187 queryItems.append(_T(')'));
188 itemCount++;
189 }
190 else if (o->getType() == DCO_TYPE_TABLE)
191 {
192 if (tableCount > 0)
193 queryTables.append(_T(" OR "));
194 queryTables.append(_T("(item_id="));
195 queryTables.append(o->getId());
196 queryTables.append(_T(" AND tdata_timestamp<"));
90e3031f 197 queryTables.append((INT64)(now - o->getEffectiveRetentionTime() * 86400));
5f648670
VK
198 queryTables.append(_T(')'));
199 tableCount++;
200 }
201 }
6fd6de0a 202 unlockDciAccess();
5f648670
VK
203
204 if (itemCount > 0)
205 {
206 DbgPrintf(6, _T("DataCollectionTarget::cleanDCIData(%s [%d]): running query \"%s\""), m_name, m_id, (const TCHAR *)queryItems);
207 DBQuery(hdb, queryItems);
208 }
209
210 if (tableCount > 0)
211 {
212 DbgPrintf(6, _T("DataCollectionTarget::cleanDCIData(%s [%d]): running query \"%s\""), m_name, m_id, (const TCHAR *)queryTables);
213 DBQuery(hdb, queryTables);
214 }
6fd6de0a
VK
215}
216
6fd6de0a
VK
217/**
218 * Get last collected values of given table
219 */
b368969c 220UINT32 DataCollectionTarget::getTableLastValues(UINT32 dciId, NXCPMessage *msg)
6fd6de0a 221{
967893bb 222 UINT32 rcc = RCC_INVALID_DCI_ID;
6fd6de0a 223
b06436f4 224 lockDciAccess(false);
6fd6de0a
VK
225
226 for(int i = 0; i < m_dcObjects->size(); i++)
227 {
228 DCObject *object = m_dcObjects->get(i);
229 if ((object->getId() == dciId) && (object->getType() == DCO_TYPE_TABLE))
230 {
4a435beb 231 ((DCTable *)object)->fillLastValueMessage(msg);
6fd6de0a
VK
232 rcc = RCC_SUCCESS;
233 break;
234 }
235 }
236
237 unlockDciAccess();
238 return rcc;
239}
240
241/**
242 * Apply DCI from template
76b42c1e 243 * dcObject passed to this method should be a template's DCI
6fd6de0a 244 */
967893bb 245bool DataCollectionTarget::applyTemplateItem(UINT32 dwTemplateId, DCObject *dcObject)
6fd6de0a
VK
246{
247 bool bResult = true;
248
b06436f4 249 lockDciAccess(true); // write lock
6fd6de0a 250
c42b4551 251 DbgPrintf(5, _T("Applying DCO \"%s\" to target \"%s\""), dcObject->getName(), m_name);
6fd6de0a
VK
252
253 // Check if that template item exists
254 int i;
255 for(i = 0; i < m_dcObjects->size(); i++)
256 if ((m_dcObjects->get(i)->getTemplateId() == dwTemplateId) &&
257 (m_dcObjects->get(i)->getTemplateItemId() == dcObject->getId()))
258 break; // Item with specified id already exist
259
260 if (i == m_dcObjects->size())
261 {
262 // New item from template, just add it
263 DCObject *newObject;
264 switch(dcObject->getType())
265 {
266 case DCO_TYPE_ITEM:
267 newObject = new DCItem((DCItem *)dcObject);
268 break;
269 case DCO_TYPE_TABLE:
270 newObject = new DCTable((DCTable *)dcObject);
271 break;
272 default:
273 newObject = NULL;
274 break;
275 }
276 if (newObject != NULL)
277 {
278 newObject->setTemplateId(dwTemplateId, dcObject->getId());
279 newObject->changeBinding(CreateUniqueId(IDG_ITEM), this, TRUE);
280 bResult = addDCObject(newObject, true);
281 }
282 }
283 else
284 {
285 // Update existing item unless it is disabled
e46d6c36 286 DCObject *curr = m_dcObjects->get(i);
0719f017 287 if ((curr->getStatus() != ITEM_STATUS_DISABLED) || (g_flags & AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE))
6fd6de0a 288 {
e46d6c36 289 curr->updateFromTemplate(dcObject);
1babf64d 290 DbgPrintf(9, _T("DCO \"%s\" NOT disabled or ApplyDCIFromTemplateToDisabledDCI set, updated (%d)"),
e46d6c36
VK
291 dcObject->getName(), curr->getStatus());
292 if ((curr->getType() == DCO_TYPE_ITEM) && (((DCItem *)curr)->getInstanceDiscoveryMethod() != IDM_NONE))
293 {
294 updateInstanceDiscoveryItems((DCItem *)curr);
295 }
6fd6de0a
VK
296 }
297 else
298 {
1babf64d 299 DbgPrintf(9, _T("DCO \"%s\" is disabled and ApplyDCIFromTemplateToDisabledDCI not set, no update (%d)"),
e46d6c36 300 dcObject->getName(), curr->getStatus());
6fd6de0a
VK
301 }
302 }
303
304 unlockDciAccess();
305
306 if (bResult)
307 {
c42b4551 308 lockProperties();
01152a54 309 m_isModified = true;
c42b4551 310 unlockProperties();
6fd6de0a
VK
311 }
312 return bResult;
313}
314
315/**
316 * Clean deleted template items from target's DCI list
317 * Arguments is template id and list of valid template item ids.
318 * all items related to given template and not presented in list should be deleted.
319 */
967893bb 320void DataCollectionTarget::cleanDeletedTemplateItems(UINT32 dwTemplateId, UINT32 dwNumItems, UINT32 *pdwItemList)
6fd6de0a 321{
967893bb 322 UINT32 i, j, dwNumDeleted, *pdwDeleteList;
6fd6de0a 323
b06436f4 324 lockDciAccess(true); // write lock
6fd6de0a 325
967893bb 326 pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
6fd6de0a
VK
327 dwNumDeleted = 0;
328
967893bb 329 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
6fd6de0a
VK
330 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
331 {
332 for(j = 0; j < dwNumItems; j++)
333 if (m_dcObjects->get(i)->getTemplateItemId() == pdwItemList[j])
334 break;
335
336 // Delete DCI if it's not in list
337 if (j == dwNumItems)
338 pdwDeleteList[dwNumDeleted++] = m_dcObjects->get(i)->getId();
339 }
340
341 for(i = 0; i < dwNumDeleted; i++)
342 deleteDCObject(pdwDeleteList[i], false);
343
344 unlockDciAccess();
345 free(pdwDeleteList);
346}
347
348/**
1babf64d 349 * Unbind data collection target from template, i.e either remove DCI
6fd6de0a
VK
350 * association with template or remove these DCIs at all
351 */
d140955e 352void DataCollectionTarget::unbindFromTemplate(UINT32 dwTemplateId, bool removeDCI)
6fd6de0a 353{
d140955e 354 if (removeDCI)
6fd6de0a 355 {
b06436f4 356 lockDciAccess(true); // write lock
6fd6de0a 357
cd6447b6
VK
358 UINT32 *deleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
359 int numDeleted = 0;
6fd6de0a 360
cd6447b6
VK
361 int i;
362 for(i = 0; i < m_dcObjects->size(); i++)
6fd6de0a
VK
363 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
364 {
cd6447b6 365 deleteList[numDeleted++] = m_dcObjects->get(i)->getId();
6fd6de0a
VK
366 }
367
cd6447b6
VK
368 for(i = 0; i < numDeleted; i++)
369 deleteDCObject(deleteList[i], false);
6fd6de0a
VK
370
371 unlockDciAccess();
cd6447b6 372 free(deleteList);
6fd6de0a
VK
373 }
374 else
375 {
b06436f4 376 lockDciAccess(false);
6fd6de0a
VK
377
378 for(int i = 0; i < m_dcObjects->size(); i++)
379 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
380 {
381 m_dcObjects->get(i)->setTemplateId(0, 0);
382 }
383
384 unlockDciAccess();
385 }
386}
387
388/**
389 * Get list of DCIs to be shown on performance tab
390 */
b368969c 391UINT32 DataCollectionTarget::getPerfTabDCIList(NXCPMessage *pMsg)
6fd6de0a 392{
b06436f4 393 lockDciAccess(false);
6fd6de0a 394
967893bb 395 UINT32 dwId = VID_SYSDCI_LIST_BASE, dwCount = 0;
6fd6de0a
VK
396 for(int i = 0; i < m_dcObjects->size(); i++)
397 {
398 DCObject *object = m_dcObjects->get(i);
1babf64d 399 if ((object->getPerfTabSettings() != NULL) &&
400 object->hasValue() &&
7e39d641
VK
401 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
402 object->matchClusterResource())
6fd6de0a 403 {
b368969c
VK
404 pMsg->setField(dwId++, object->getId());
405 pMsg->setField(dwId++, object->getDescription());
406 pMsg->setField(dwId++, (WORD)object->getStatus());
407 pMsg->setField(dwId++, object->getPerfTabSettings());
408 pMsg->setField(dwId++, (WORD)object->getType());
409 pMsg->setField(dwId++, object->getTemplateItemId());
6d6599dc
VK
410 if (object->getType() == DCO_TYPE_ITEM)
411 {
b368969c 412 pMsg->setField(dwId++, ((DCItem *)object)->getInstance());
0719f017
VK
413 if ((object->getTemplateItemId() != 0) && (object->getTemplateId() == m_id))
414 {
415 // DCI created via instance discovery - send ID of root template item
416 // to allow UI to resolve double template case
417 // (template -> instance discovery item on node -> actual item on node)
418 DCObject *src = getDCObjectById(object->getTemplateItemId(), false);
419 pMsg->setField(dwId++, (src != NULL) ? src->getTemplateItemId() : 0);
420 dwId += 2;
421 }
422 else
423 {
424 dwId += 3;
425 }
6d6599dc
VK
426 }
427 else
428 {
429 dwId += 4;
430 }
6fd6de0a
VK
431 dwCount++;
432 }
433 }
b368969c 434 pMsg->setField(VID_NUM_ITEMS, dwCount);
6fd6de0a
VK
435
436 unlockDciAccess();
437 return RCC_SUCCESS;
438}
439
440/**
441 * Get threshold violation summary into NXCP message
442 */
b368969c 443UINT32 DataCollectionTarget::getThresholdSummary(NXCPMessage *msg, UINT32 baseId)
6fd6de0a 444{
967893bb 445 UINT32 varId = baseId;
6fd6de0a 446
b368969c 447 msg->setField(varId++, m_id);
967893bb
VK
448 UINT32 countId = varId++;
449 UINT32 count = 0;
6fd6de0a 450
b06436f4 451 lockDciAccess(false);
6fd6de0a
VK
452 for(int i = 0; i < m_dcObjects->size(); i++)
453 {
454 DCObject *object = m_dcObjects->get(i);
db091a1f 455 if (object->hasValue() && (object->getType() == DCO_TYPE_ITEM) && (object->getStatus() == ITEM_STATUS_ACTIVE))
6fd6de0a
VK
456 {
457 if (((DCItem *)object)->hasActiveThreshold())
458 {
4a435beb 459 ((DCItem *)object)->fillLastValueMessage(msg, varId);
6fd6de0a
VK
460 varId += 50;
461 count++;
462 }
463 }
464 }
465 unlockDciAccess();
b368969c 466 msg->setField(countId, count);
6fd6de0a
VK
467 return varId;
468}
469
470/**
471 * Process new DCI value
472 */
e63fca40 473bool DataCollectionTarget::processNewDCValue(DCObject *dco, time_t currTime, const void *value)
6fd6de0a 474{
76b42c1e 475 bool updateStatus;
76b42c1e 476 bool result = dco->processNewValue(currTime, value, &updateStatus);
76b42c1e 477 if (updateStatus)
cd68963b 478 {
479 calculateCompoundStatus(FALSE);
480 }
0156d6b2 481 return result;
6fd6de0a
VK
482}
483
484/**
485 * Check if data collection is disabled
486 */
487bool DataCollectionTarget::isDataCollectionDisabled()
488{
489 return false;
490}
491
492/**
493 * Put items which requires polling into the queue
494 */
495void DataCollectionTarget::queueItemsForPolling(Queue *pPollerQueue)
496{
db091a1f 497 if ((m_status == STATUS_UNMANAGED) || isDataCollectionDisabled() || m_isDeleted)
6fd6de0a
VK
498 return; // Do not collect data for unmanaged objects or if data collection is disabled
499
500 time_t currTime = time(NULL);
501
b06436f4 502 lockDciAccess(false);
6fd6de0a
VK
503 for(int i = 0; i < m_dcObjects->size(); i++)
504 {
505 DCObject *object = m_dcObjects->get(i);
506 if (object->isReadyForPolling(currTime))
507 {
508 object->setBusyFlag(TRUE);
21c9acce 509 incRefCount(); // Increment reference count for each queued DCI
19dbc8ef 510 pPollerQueue->put(object);
c42b4551 511 DbgPrintf(8, _T("DataCollectionTarget(%s)->QueueItemsForPolling(): item %d \"%s\" added to queue"), m_name, object->getId(), object->getName());
6fd6de0a
VK
512 }
513 }
514 unlockDciAccess();
515}
516
b8014eee
VK
517/**
518 * Get object from parameter
519 */
520NetObj *DataCollectionTarget::objectFromParameter(const TCHAR *param)
521{
522 TCHAR *eptr, arg[256];
523 AgentGetParameterArg(param, 1, arg, 256);
524 UINT32 objectId = _tcstoul(arg, &eptr, 0);
525 if (*eptr != 0)
526 {
527 // Argument is object's name
528 objectId = 0;
529 }
530
531 // Find child object with requested ID or name
532 NetObj *object = NULL;
db091a1f
VK
533 lockChildList(false);
534 for(int i = 0; i < m_childList->size(); i++)
b8014eee 535 {
db091a1f
VK
536 NetObj *curr = m_childList->get(i);
537 if (((objectId == 0) && (!_tcsicmp(curr->getName(), arg))) ||
538 (objectId == curr->getId()))
b8014eee 539 {
db091a1f 540 object = curr;
b8014eee
VK
541 break;
542 }
543 }
db091a1f 544 unlockChildList();
b8014eee
VK
545 return object;
546}
547
6fd6de0a
VK
548/**
549 * Get value for server's internal parameter
550 */
17b1ab4a 551UINT32 DataCollectionTarget::getInternalItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
6fd6de0a 552{
967893bb 553 UINT32 dwError = DCE_SUCCESS;
6fd6de0a 554
17b1ab4a 555 if (!_tcsicmp(param, _T("Status")))
6fd6de0a 556 {
db091a1f 557 _sntprintf(buffer, bufSize, _T("%d"), m_status);
6fd6de0a 558 }
1f925ee9 559 else if (!_tcsicmp(param, _T("Dummy")) || MatchString(_T("Dummy(*)"), param, FALSE))
6fd6de0a 560 {
17b1ab4a 561 _tcscpy(buffer, _T("0"));
6fd6de0a 562 }
17b1ab4a 563 else if (MatchString(_T("ChildStatus(*)"), param, FALSE))
6fd6de0a 564 {
b8014eee
VK
565 NetObj *object = objectFromParameter(param);
566 if (object != NULL)
6fd6de0a 567 {
db091a1f 568 _sntprintf(buffer, bufSize, _T("%d"), object->getStatus());
6fd6de0a
VK
569 }
570 else
571 {
572 dwError = DCE_NOT_SUPPORTED;
573 }
574 }
17b1ab4a 575 else if (MatchString(_T("ConditionStatus(*)"), param, FALSE))
6fd6de0a
VK
576 {
577 TCHAR *pEnd, szArg[256];
967893bb 578 UINT32 dwId;
6fd6de0a
VK
579 NetObj *pObject = NULL;
580
17b1ab4a 581 AgentGetParameterArg(param, 1, szArg, 256);
6fd6de0a
VK
582 dwId = _tcstoul(szArg, &pEnd, 0);
583 if (*pEnd == 0)
584 {
585 pObject = FindObjectById(dwId);
586 if (pObject != NULL)
c42b4551 587 if (pObject->getObjectClass() != OBJECT_CONDITION)
6fd6de0a
VK
588 pObject = NULL;
589 }
590 else
591 {
592 // Argument is object's name
593 pObject = FindObjectByName(szArg, OBJECT_CONDITION);
594 }
595
596 if (pObject != NULL)
597 {
c42b4551 598 if (pObject->isTrustedNode(m_id))
6fd6de0a 599 {
db091a1f 600 _sntprintf(buffer, bufSize, _T("%d"), pObject->getStatus());
6fd6de0a
VK
601 }
602 else
603 {
604 dwError = DCE_NOT_SUPPORTED;
605 }
606 }
607 else
608 {
609 dwError = DCE_NOT_SUPPORTED;
610 }
611 }
612 else
613 {
614 dwError = DCE_NOT_SUPPORTED;
615 }
616
617 return dwError;
618}
4a435beb 619
17b1ab4a
VK
620/**
621 * Get parameter value from NXSL script
622 */
623UINT32 DataCollectionTarget::getScriptItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
624{
625 TCHAR name[256];
626 nx_strncpy(name, param, 256);
627 Trim(name);
628
629 ObjectArray<NXSL_Value> args(16, 16, false);
630
631 // Can be in form parameter(arg1, arg2, ... argN)
632 TCHAR *p = _tcschr(name, _T('('));
633 if (p != NULL)
634 {
635 if (name[_tcslen(name) - 1] != _T(')'))
636 return DCE_NOT_SUPPORTED;
637 name[_tcslen(name) - 1] = 0;
638
8dd5537c 639 if (!ParseValueList(&p, args))
17b1ab4a 640 {
30b8d6c7 641 // argument parsing error
8dd5537c 642 args.clear();
30b8d6c7
VK
643 return DCE_NOT_SUPPORTED;
644 }
17b1ab4a
VK
645 }
646
647 UINT32 rc = DCE_NOT_SUPPORTED;
648 NXSL_VM *vm = g_pScriptLibrary->createVM(name, new NXSL_ServerEnv);
649 if (vm != NULL)
650 {
297a88eb 651 vm->setGlobalVariable(_T("$object"), createNXSLObject());
c42b4551 652 if (getObjectClass() == OBJECT_NODE)
17b1ab4a
VK
653 {
654 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
655 }
c42b4551 656 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
17b1ab4a
VK
657 if (vm->run(&args))
658 {
659 NXSL_Value *value = vm->getResult();
8fff1d39
VK
660 if (value->isNull())
661 {
662 // NULL value is an error indicator
663 rc = DCE_COMM_ERROR;
664 }
665 else
666 {
667 const TCHAR *dciValue = value->getValueAsCString();
668 nx_strncpy(buffer, CHECK_NULL_EX(dciValue), bufSize);
669 rc = DCE_SUCCESS;
670 }
17b1ab4a
VK
671 }
672 else
673 {
c42b4551
VK
674 DbgPrintf(4, _T("DataCollectionTarget(%s)->getScriptItem(%s): Script execution error: %s"), m_name, param, vm->getErrorText());
675 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", name, vm->getErrorText(), m_id);
17b1ab4a
VK
676 rc = DCE_COMM_ERROR;
677 }
678 delete vm;
679 }
680 else
681 {
682 args.setOwner(true);
683 }
c42b4551 684 DbgPrintf(7, _T("DataCollectionTarget(%s)->getScriptItem(%s): rc=%d"), m_name, param, rc);
17b1ab4a
VK
685 return rc;
686}
687
d32e7ef1
VK
688/**
689 * Get list from library script
690 */
691UINT32 DataCollectionTarget::getListFromScript(const TCHAR *param, StringList **list)
692{
693 TCHAR name[256];
694 nx_strncpy(name, param, 256);
695 Trim(name);
696
697 ObjectArray<NXSL_Value> args(16, 16, false);
698
699 // Can be in form parameter(arg1, arg2, ... argN)
700 TCHAR *p = _tcschr(name, _T('('));
701 if (p != NULL)
702 {
703 if (name[_tcslen(name) - 1] != _T(')'))
704 return DCE_NOT_SUPPORTED;
705 name[_tcslen(name) - 1] = 0;
706
707 if (!ParseValueList(&p, args))
708 {
709 // argument parsing error
710 args.clear();
711 return DCE_NOT_SUPPORTED;
712 }
713 }
714
715 UINT32 rc = DCE_NOT_SUPPORTED;
716 NXSL_VM *vm = g_pScriptLibrary->createVM(name, new NXSL_ServerEnv);
717 if (vm != NULL)
718 {
297a88eb 719 vm->setGlobalVariable(_T("$object"), createNXSLObject());
d32e7ef1
VK
720 if (getObjectClass() == OBJECT_NODE)
721 {
722 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
723 }
724 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
725 if (vm->run(&args))
726 {
8fff1d39 727 rc = DCE_SUCCESS;
d32e7ef1
VK
728 NXSL_Value *value = vm->getResult();
729 if (value->isArray())
730 {
731 *list = value->getValueAsArray()->toStringList();
732 }
733 else if (value->isString())
734 {
735 *list = new StringList;
736 (*list)->add(value->getValueAsCString());
737 }
8fff1d39
VK
738 else if (value->isNull())
739 {
740 rc = DCE_COMM_ERROR;
741 }
d32e7ef1
VK
742 else
743 {
744 *list = new StringList;
745 }
d32e7ef1
VK
746 }
747 else
748 {
749 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): Script execution error: %s"), m_name, param, vm->getErrorText());
750 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", name, vm->getErrorText(), m_id);
751 rc = DCE_COMM_ERROR;
752 }
753 delete vm;
754 }
755 else
756 {
757 args.setOwner(true);
758 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): script \"%s\" not found"), m_name, param, name);
759 }
760 DbgPrintf(7, _T("DataCollectionTarget(%s)->getListFromScript(%s): rc=%d"), m_name, param, rc);
761 return rc;
762}
763
4a435beb
VK
764/**
765 * Get last (current) DCI values for summary table.
766 */
2852ef09 767void DataCollectionTarget::getDciValuesSummary(SummaryTable *tableDefinition, Table *tableData)
4a435beb 768{
914580f5
VK
769 int offset = tableDefinition->isMultiInstance() ? 2 : 1;
770 int baseRow = tableData->getNumRows();
4a435beb 771 bool rowAdded = false;
b06436f4 772 lockDciAccess(false);
4a435beb
VK
773 for(int i = 0; i < tableDefinition->getNumColumns(); i++)
774 {
775 SummaryTableColumn *tc = tableDefinition->getColumn(i);
776 for(int j = 0; j < m_dcObjects->size(); j++)
777 {
778 DCObject *object = m_dcObjects->get(j);
1babf64d 779 if ((object->getType() == DCO_TYPE_ITEM) && object->hasValue() &&
c83f6449 780 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
1babf64d 781 ((tc->m_flags & COLUMN_DEFINITION_REGEXP_MATCH) ?
2da939ac
VK
782 RegexpMatch(object->getName(), tc->m_dciName, FALSE) :
783 !_tcsicmp(object->getName(), tc->m_dciName)
784 ))
4a435beb 785 {
914580f5
VK
786 int row;
787 if (tableDefinition->isMultiInstance())
4a435beb 788 {
914580f5
VK
789 // Find instance
790 const TCHAR *instance = ((DCItem *)object)->getInstance();
791 for(row = baseRow; row < tableData->getNumRows(); row++)
792 {
793 const TCHAR *v = tableData->getAsString(row, 1);
794 if (!_tcscmp(CHECK_NULL_EX(v), instance))
795 break;
796 }
797 if (row == tableData->getNumRows())
798 {
799 tableData->addRow();
800 tableData->set(0, m_name);
801 tableData->set(1, instance);
802 tableData->setObjectId(tableData->getNumRows() - 1, m_id);
803 }
4a435beb 804 }
914580f5
VK
805 else
806 {
807 if (!rowAdded)
808 {
809 tableData->addRow();
810 tableData->set(0, m_name);
811 tableData->setObjectId(tableData->getNumRows() - 1, m_id);
812 rowAdded = true;
813 }
814 row = tableData->getNumRows() - 1;
815 }
816 tableData->setStatusAt(row, i + offset, ((DCItem *)object)->getThresholdSeverity());
43666be9 817 tableData->setCellObjectIdAt(row, i + offset, object->getId());
914580f5 818 tableData->getColumnDefinitions()->get(i + offset)->setDataType(((DCItem *)object)->getDataType());
2852ef09
VK
819 if (tableDefinition->getAggregationFunction() == F_LAST)
820 {
914580f5 821 tableData->setAt(row, i + offset, ((DCItem *)object)->getLastValue());
2852ef09
VK
822 }
823 else
824 {
e83d726c 825 tableData->setAt(row, i + offset,
2852ef09 826 ((DCItem *)object)->getAggregateValue(
e83d726c 827 tableDefinition->getAggregationFunction(),
828 tableDefinition->getPeriodStart(),
2852ef09
VK
829 tableDefinition->getPeriodEnd()));
830 }
914580f5
VK
831
832 if (!tableDefinition->isMultiInstance())
833 break;
4a435beb
VK
834 }
835 }
836 }
837 unlockDciAccess();
838}
d1730ccf
VK
839
840/**
841 * Must return true if object is a possible event source
842 */
843bool DataCollectionTarget::isEventSource()
844{
845 return true;
846}
cd68963b 847
848/**
849 * Returns most critical status of DCI used for
850 * status calculation
851 */
852int DataCollectionTarget::getMostCriticalDCIStatus()
853{
854 int status = -1;
855 lockDciAccess(false);
cd68963b 856 for(int i = 0; i < m_dcObjects->size(); i++)
857 {
858 DCObject *curr = m_dcObjects->get(i);
859 if (curr->isStatusDCO() && (curr->getType() == DCO_TYPE_ITEM) &&
860 curr->hasValue() && (curr->getStatus() == ITEM_STATUS_ACTIVE))
861 {
c42b4551 862 if (getObjectClass() == OBJECT_CLUSTER && !curr->isAggregateOnCluster())
c2aa1707 863 continue; // Calculated only on those that are agregated on cluster
cd68963b 864
865 ItemValue *value = ((DCItem *)curr)->getInternalLastValue();
c2aa1707 866 if (value != NULL && (INT32)*value >= STATUS_NORMAL && (INT32)*value <= STATUS_CRITICAL)
cd68963b 867 status = max(status, (INT32)*value);
868 delete value;
869 }
870 }
871 unlockDciAccess();
c2aa1707 872 return (status == -1) ? STATUS_UNKNOWN : status;
cd68963b 873}
f94d5259
VK
874
875/**
876 * Calculate compound status
877 */
878void DataCollectionTarget::calculateCompoundStatus(BOOL bForcedRecalc)
879{
880 NetObj::calculateCompoundStatus(bForcedRecalc);
881}
ebb2dc70
VK
882
883/**
884 * Returns last ping time
885 */
886UINT32 DataCollectionTarget::getPingTime()
887{
888 if ((time(NULL) - m_pingLastTimeStamp) > g_dwStatusPollingInterval)
889 {
890 updatePingData();
891 DbgPrintf(7, _T("DataCollectionTarget::getPingTime: update ping time is required! Last ping time %d."), m_pingLastTimeStamp);
892 }
893 return m_pingTime;
894}
895
896/**
897 * Update ping data
898 */
899void DataCollectionTarget::updatePingData()
900{
901 m_pingLastTimeStamp = 0;
902 m_pingTime = PING_TIME_TIMEOUT;
903}
7e18667a
VK
904
905/**
906 * Enter maintenance mode
907 */
908void DataCollectionTarget::enterMaintenanceMode()
909{
910 DbgPrintf(4, _T("Entering maintenance mode for %s [%d]"), m_name, m_id);
911 UINT64 eventId = PostEvent2(EVENT_MAINTENANCE_MODE_ENTERED, m_id, NULL);
912 lockProperties();
913 m_maintenanceMode = true;
914 m_maintenanceEventId = eventId;
01be5c8b 915 setModified();
7e18667a
VK
916 unlockProperties();
917}
918
919/**
920 * Leave maintenance mode
921 */
922void DataCollectionTarget::leaveMaintenanceMode()
923{
924 DbgPrintf(4, _T("Leaving maintenance mode for %s [%d]"), m_name, m_id);
925 PostEvent(EVENT_MAINTENANCE_MODE_LEFT, m_id, NULL);
926 lockProperties();
927 m_maintenanceMode = false;
928 m_maintenanceEventId = 0;
01be5c8b 929 setModified();
7e18667a
VK
930 unlockProperties();
931}
77b2c6de
VK
932
933/**
934 * Update cache size for given data collection item
935 */
936void DataCollectionTarget::updateDCItemCacheSize(UINT32 dciId, UINT32 conditionId)
937{
938 lockDciAccess(false);
939 DCObject *dci = getDCObjectById(dciId, false);
940 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
941 {
942 ((DCItem *)dci)->updateCacheSize(conditionId);
943 }
944 unlockDciAccess();
945}
db091a1f
VK
946
947/**
948 * Returns true if object is data collection target
949 */
950bool DataCollectionTarget::isDataCollectionTarget()
951{
952 return true;
953}