Added new status for collection error. Communication error does not reset status...
[public/netxms.git] / src / server / core / dctarget.cpp
CommitLineData
1babf64d 1/*
6fd6de0a 2** NetXMS - Network Management System
46e2b370 3** Copyright (C) 2003-2016 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 TCHAR query[256];
61 _sntprintf(query, 256, _T("DROP TABLE idata_%d"), (int)m_id);
62 QueueSQLRequest(query);
63
89e5f052 64 _sntprintf(query, 256, _T("DROP TABLE tdata_%d"), (int)m_id);
b6aff59d 65 QueueSQLRequest(query);
6fd6de0a 66 }
22ee6d97 67 return success;
6fd6de0a
VK
68}
69
70/**
71 * Create NXCP message with object's data
72 */
8fe90adb 73void DataCollectionTarget::fillMessageInternal(NXCPMessage *msg)
6fd6de0a 74{
8fe90adb 75 Template::fillMessageInternal(msg);
9289a3bb
VK
76}
77
78/**
79 * Create NXCP message with object's data - stage 2
80 */
81void DataCollectionTarget::fillMessageInternalStage2(NXCPMessage *msg)
82{
83 Template::fillMessageInternalStage2(msg);
1fa2ca0e 84
928fca65
VK
85 // Sent all DCIs marked for display on overview page or in tooltips
86 UINT32 fieldIdOverview = VID_OVERVIEW_DCI_LIST_BASE;
87 UINT32 countOverview = 0;
88 UINT32 fieldIdTooltip = VID_TOOLTIP_DCI_LIST_BASE;
89 UINT32 countTooltip = 0;
1fa2ca0e
VK
90 lockDciAccess(false);
91 for(int i = 0; i < m_dcObjects->size(); i++)
92 {
93 DCObject *dci = m_dcObjects->get(i);
928fca65
VK
94 if ((dci->getType() == DCO_TYPE_ITEM) &&
95 (dci->getStatus() == ITEM_STATUS_ACTIVE) &&
96 (((DCItem *)dci)->getInstanceDiscoveryMethod() == IDM_NONE))
1fa2ca0e 97 {
928fca65
VK
98 if (dci->isShowInObjectOverview())
99 {
100 countOverview++;
101 ((DCItem *)dci)->fillLastValueMessage(msg, fieldIdOverview);
102 fieldIdOverview += 50;
103 }
104 if (dci->isShowOnObjectTooltip())
105 {
106 countTooltip++;
107 ((DCItem *)dci)->fillLastValueMessage(msg, fieldIdTooltip);
108 fieldIdTooltip += 50;
109 }
1fa2ca0e
VK
110 }
111 }
112 unlockDciAccess();
928fca65
VK
113 msg->setField(VID_OVERVIEW_DCI_COUNT, countOverview);
114 msg->setField(VID_TOOLTIP_DCI_COUNT, countTooltip);
6fd6de0a
VK
115}
116
117/**
118 * Modify object from message
119 */
8fe90adb 120UINT32 DataCollectionTarget::modifyFromMessageInternal(NXCPMessage *pRequest)
6fd6de0a 121{
8fe90adb 122 return Template::modifyFromMessageInternal(pRequest);
6fd6de0a
VK
123}
124
125/**
126 * Update cache for all DCI's
127 */
128void DataCollectionTarget::updateDciCache()
129{
b06436f4 130 lockDciAccess(false);
6fd6de0a
VK
131 for(int i = 0; i < m_dcObjects->size(); i++)
132 {
133 if (m_dcObjects->get(i)->getType() == DCO_TYPE_ITEM)
134 {
135 ((DCItem *)m_dcObjects->get(i))->updateCacheSize();
136 }
137 }
138 unlockDciAccess();
139}
140
141/**
142 * Clean expired DCI data
143 */
5f648670 144void DataCollectionTarget::cleanDCIData(DB_HANDLE hdb)
6fd6de0a 145{
5f648670
VK
146 String queryItems = _T("DELETE FROM idata_");
147 queryItems.append(m_id);
148 queryItems.append(_T(" WHERE "));
149
150 String queryTables = _T("DELETE FROM tdata_");
151 queryTables.append(m_id);
152 queryTables.append(_T(" WHERE "));
153
154 int itemCount = 0;
155 int tableCount = 0;
156 time_t now = time(NULL);
157
b06436f4 158 lockDciAccess(false);
6fd6de0a 159 for(int i = 0; i < m_dcObjects->size(); i++)
5f648670
VK
160 {
161 DCObject *o = m_dcObjects->get(i);
162 if (o->getType() == DCO_TYPE_ITEM)
163 {
164 if (itemCount > 0)
165 queryItems.append(_T(" OR "));
166 queryItems.append(_T("(item_id="));
167 queryItems.append(o->getId());
168 queryItems.append(_T(" AND idata_timestamp<"));
90e3031f 169 queryItems.append((INT64)(now - o->getEffectiveRetentionTime() * 86400));
5f648670
VK
170 queryItems.append(_T(')'));
171 itemCount++;
172 }
173 else if (o->getType() == DCO_TYPE_TABLE)
174 {
175 if (tableCount > 0)
176 queryTables.append(_T(" OR "));
177 queryTables.append(_T("(item_id="));
178 queryTables.append(o->getId());
179 queryTables.append(_T(" AND tdata_timestamp<"));
90e3031f 180 queryTables.append((INT64)(now - o->getEffectiveRetentionTime() * 86400));
5f648670
VK
181 queryTables.append(_T(')'));
182 tableCount++;
183 }
184 }
6fd6de0a 185 unlockDciAccess();
5f648670
VK
186
187 if (itemCount > 0)
188 {
189 DbgPrintf(6, _T("DataCollectionTarget::cleanDCIData(%s [%d]): running query \"%s\""), m_name, m_id, (const TCHAR *)queryItems);
190 DBQuery(hdb, queryItems);
191 }
192
193 if (tableCount > 0)
194 {
195 DbgPrintf(6, _T("DataCollectionTarget::cleanDCIData(%s [%d]): running query \"%s\""), m_name, m_id, (const TCHAR *)queryTables);
196 DBQuery(hdb, queryTables);
197 }
6fd6de0a
VK
198}
199
6fd6de0a
VK
200/**
201 * Get last collected values of given table
202 */
b368969c 203UINT32 DataCollectionTarget::getTableLastValues(UINT32 dciId, NXCPMessage *msg)
6fd6de0a 204{
967893bb 205 UINT32 rcc = RCC_INVALID_DCI_ID;
6fd6de0a 206
b06436f4 207 lockDciAccess(false);
6fd6de0a
VK
208
209 for(int i = 0; i < m_dcObjects->size(); i++)
210 {
211 DCObject *object = m_dcObjects->get(i);
212 if ((object->getId() == dciId) && (object->getType() == DCO_TYPE_TABLE))
213 {
4a435beb 214 ((DCTable *)object)->fillLastValueMessage(msg);
6fd6de0a
VK
215 rcc = RCC_SUCCESS;
216 break;
217 }
218 }
219
220 unlockDciAccess();
221 return rcc;
222}
223
224/**
225 * Apply DCI from template
76b42c1e 226 * dcObject passed to this method should be a template's DCI
6fd6de0a 227 */
967893bb 228bool DataCollectionTarget::applyTemplateItem(UINT32 dwTemplateId, DCObject *dcObject)
6fd6de0a
VK
229{
230 bool bResult = true;
231
b06436f4 232 lockDciAccess(true); // write lock
6fd6de0a 233
c42b4551 234 DbgPrintf(5, _T("Applying DCO \"%s\" to target \"%s\""), dcObject->getName(), m_name);
6fd6de0a
VK
235
236 // Check if that template item exists
237 int i;
238 for(i = 0; i < m_dcObjects->size(); i++)
239 if ((m_dcObjects->get(i)->getTemplateId() == dwTemplateId) &&
240 (m_dcObjects->get(i)->getTemplateItemId() == dcObject->getId()))
241 break; // Item with specified id already exist
242
243 if (i == m_dcObjects->size())
244 {
245 // New item from template, just add it
246 DCObject *newObject;
247 switch(dcObject->getType())
248 {
249 case DCO_TYPE_ITEM:
250 newObject = new DCItem((DCItem *)dcObject);
251 break;
252 case DCO_TYPE_TABLE:
253 newObject = new DCTable((DCTable *)dcObject);
254 break;
255 default:
256 newObject = NULL;
257 break;
258 }
259 if (newObject != NULL)
260 {
261 newObject->setTemplateId(dwTemplateId, dcObject->getId());
262 newObject->changeBinding(CreateUniqueId(IDG_ITEM), this, TRUE);
263 bResult = addDCObject(newObject, true);
264 }
265 }
266 else
267 {
268 // Update existing item unless it is disabled
e46d6c36 269 DCObject *curr = m_dcObjects->get(i);
0719f017 270 if ((curr->getStatus() != ITEM_STATUS_DISABLED) || (g_flags & AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE))
6fd6de0a 271 {
e46d6c36 272 curr->updateFromTemplate(dcObject);
1babf64d 273 DbgPrintf(9, _T("DCO \"%s\" NOT disabled or ApplyDCIFromTemplateToDisabledDCI set, updated (%d)"),
e46d6c36
VK
274 dcObject->getName(), curr->getStatus());
275 if ((curr->getType() == DCO_TYPE_ITEM) && (((DCItem *)curr)->getInstanceDiscoveryMethod() != IDM_NONE))
276 {
277 updateInstanceDiscoveryItems((DCItem *)curr);
278 }
6fd6de0a
VK
279 }
280 else
281 {
1babf64d 282 DbgPrintf(9, _T("DCO \"%s\" is disabled and ApplyDCIFromTemplateToDisabledDCI not set, no update (%d)"),
e46d6c36 283 dcObject->getName(), curr->getStatus());
6fd6de0a
VK
284 }
285 }
286
287 unlockDciAccess();
288
289 if (bResult)
290 {
c42b4551 291 lockProperties();
01152a54 292 m_isModified = true;
c42b4551 293 unlockProperties();
6fd6de0a
VK
294 }
295 return bResult;
296}
297
298/**
299 * Clean deleted template items from target's DCI list
300 * Arguments is template id and list of valid template item ids.
301 * all items related to given template and not presented in list should be deleted.
302 */
967893bb 303void DataCollectionTarget::cleanDeletedTemplateItems(UINT32 dwTemplateId, UINT32 dwNumItems, UINT32 *pdwItemList)
6fd6de0a 304{
967893bb 305 UINT32 i, j, dwNumDeleted, *pdwDeleteList;
6fd6de0a 306
b06436f4 307 lockDciAccess(true); // write lock
6fd6de0a 308
967893bb 309 pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
6fd6de0a
VK
310 dwNumDeleted = 0;
311
967893bb 312 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
6fd6de0a
VK
313 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
314 {
315 for(j = 0; j < dwNumItems; j++)
316 if (m_dcObjects->get(i)->getTemplateItemId() == pdwItemList[j])
317 break;
318
319 // Delete DCI if it's not in list
320 if (j == dwNumItems)
321 pdwDeleteList[dwNumDeleted++] = m_dcObjects->get(i)->getId();
322 }
323
324 for(i = 0; i < dwNumDeleted; i++)
325 deleteDCObject(pdwDeleteList[i], false);
326
327 unlockDciAccess();
328 free(pdwDeleteList);
329}
330
331/**
1babf64d 332 * Unbind data collection target from template, i.e either remove DCI
6fd6de0a
VK
333 * association with template or remove these DCIs at all
334 */
d140955e 335void DataCollectionTarget::unbindFromTemplate(UINT32 dwTemplateId, bool removeDCI)
6fd6de0a 336{
d140955e 337 if (removeDCI)
6fd6de0a 338 {
b06436f4 339 lockDciAccess(true); // write lock
6fd6de0a 340
cd6447b6
VK
341 UINT32 *deleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
342 int numDeleted = 0;
6fd6de0a 343
cd6447b6
VK
344 int i;
345 for(i = 0; i < m_dcObjects->size(); i++)
6fd6de0a
VK
346 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
347 {
cd6447b6 348 deleteList[numDeleted++] = m_dcObjects->get(i)->getId();
6fd6de0a
VK
349 }
350
cd6447b6
VK
351 for(i = 0; i < numDeleted; i++)
352 deleteDCObject(deleteList[i], false);
6fd6de0a
VK
353
354 unlockDciAccess();
cd6447b6 355 free(deleteList);
6fd6de0a
VK
356 }
357 else
358 {
b06436f4 359 lockDciAccess(false);
6fd6de0a
VK
360
361 for(int i = 0; i < m_dcObjects->size(); i++)
362 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
363 {
364 m_dcObjects->get(i)->setTemplateId(0, 0);
365 }
366
367 unlockDciAccess();
368 }
369}
370
371/**
372 * Get list of DCIs to be shown on performance tab
373 */
b368969c 374UINT32 DataCollectionTarget::getPerfTabDCIList(NXCPMessage *pMsg)
6fd6de0a 375{
b06436f4 376 lockDciAccess(false);
6fd6de0a 377
967893bb 378 UINT32 dwId = VID_SYSDCI_LIST_BASE, dwCount = 0;
6fd6de0a
VK
379 for(int i = 0; i < m_dcObjects->size(); i++)
380 {
381 DCObject *object = m_dcObjects->get(i);
1babf64d 382 if ((object->getPerfTabSettings() != NULL) &&
383 object->hasValue() &&
7e39d641
VK
384 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
385 object->matchClusterResource())
6fd6de0a 386 {
b368969c
VK
387 pMsg->setField(dwId++, object->getId());
388 pMsg->setField(dwId++, object->getDescription());
389 pMsg->setField(dwId++, (WORD)object->getStatus());
390 pMsg->setField(dwId++, object->getPerfTabSettings());
391 pMsg->setField(dwId++, (WORD)object->getType());
392 pMsg->setField(dwId++, object->getTemplateItemId());
6d6599dc
VK
393 if (object->getType() == DCO_TYPE_ITEM)
394 {
b368969c 395 pMsg->setField(dwId++, ((DCItem *)object)->getInstance());
0719f017
VK
396 if ((object->getTemplateItemId() != 0) && (object->getTemplateId() == m_id))
397 {
398 // DCI created via instance discovery - send ID of root template item
399 // to allow UI to resolve double template case
400 // (template -> instance discovery item on node -> actual item on node)
401 DCObject *src = getDCObjectById(object->getTemplateItemId(), false);
402 pMsg->setField(dwId++, (src != NULL) ? src->getTemplateItemId() : 0);
403 dwId += 2;
404 }
405 else
406 {
407 dwId += 3;
408 }
6d6599dc
VK
409 }
410 else
411 {
412 dwId += 4;
413 }
6fd6de0a
VK
414 dwCount++;
415 }
416 }
b368969c 417 pMsg->setField(VID_NUM_ITEMS, dwCount);
6fd6de0a
VK
418
419 unlockDciAccess();
420 return RCC_SUCCESS;
421}
422
423/**
424 * Get threshold violation summary into NXCP message
425 */
b368969c 426UINT32 DataCollectionTarget::getThresholdSummary(NXCPMessage *msg, UINT32 baseId)
6fd6de0a 427{
967893bb 428 UINT32 varId = baseId;
6fd6de0a 429
b368969c 430 msg->setField(varId++, m_id);
967893bb
VK
431 UINT32 countId = varId++;
432 UINT32 count = 0;
6fd6de0a 433
b06436f4 434 lockDciAccess(false);
6fd6de0a
VK
435 for(int i = 0; i < m_dcObjects->size(); i++)
436 {
437 DCObject *object = m_dcObjects->get(i);
db091a1f 438 if (object->hasValue() && (object->getType() == DCO_TYPE_ITEM) && (object->getStatus() == ITEM_STATUS_ACTIVE))
6fd6de0a
VK
439 {
440 if (((DCItem *)object)->hasActiveThreshold())
441 {
4a435beb 442 ((DCItem *)object)->fillLastValueMessage(msg, varId);
6fd6de0a
VK
443 varId += 50;
444 count++;
445 }
446 }
447 }
448 unlockDciAccess();
b368969c 449 msg->setField(countId, count);
6fd6de0a
VK
450 return varId;
451}
452
453/**
454 * Process new DCI value
455 */
e63fca40 456bool DataCollectionTarget::processNewDCValue(DCObject *dco, time_t currTime, const void *value)
6fd6de0a 457{
76b42c1e 458 bool updateStatus;
76b42c1e 459 bool result = dco->processNewValue(currTime, value, &updateStatus);
76b42c1e 460 if (updateStatus)
cd68963b 461 {
462 calculateCompoundStatus(FALSE);
463 }
0156d6b2 464 return result;
6fd6de0a
VK
465}
466
467/**
468 * Check if data collection is disabled
469 */
470bool DataCollectionTarget::isDataCollectionDisabled()
471{
472 return false;
473}
474
475/**
476 * Put items which requires polling into the queue
477 */
478void DataCollectionTarget::queueItemsForPolling(Queue *pPollerQueue)
479{
db091a1f 480 if ((m_status == STATUS_UNMANAGED) || isDataCollectionDisabled() || m_isDeleted)
6fd6de0a
VK
481 return; // Do not collect data for unmanaged objects or if data collection is disabled
482
483 time_t currTime = time(NULL);
484
b06436f4 485 lockDciAccess(false);
6fd6de0a
VK
486 for(int i = 0; i < m_dcObjects->size(); i++)
487 {
488 DCObject *object = m_dcObjects->get(i);
489 if (object->isReadyForPolling(currTime))
490 {
491 object->setBusyFlag(TRUE);
21c9acce 492 incRefCount(); // Increment reference count for each queued DCI
19dbc8ef 493 pPollerQueue->put(object);
c42b4551 494 DbgPrintf(8, _T("DataCollectionTarget(%s)->QueueItemsForPolling(): item %d \"%s\" added to queue"), m_name, object->getId(), object->getName());
6fd6de0a
VK
495 }
496 }
497 unlockDciAccess();
498}
499
b8014eee
VK
500/**
501 * Get object from parameter
502 */
503NetObj *DataCollectionTarget::objectFromParameter(const TCHAR *param)
504{
505 TCHAR *eptr, arg[256];
506 AgentGetParameterArg(param, 1, arg, 256);
507 UINT32 objectId = _tcstoul(arg, &eptr, 0);
508 if (*eptr != 0)
509 {
510 // Argument is object's name
511 objectId = 0;
512 }
513
514 // Find child object with requested ID or name
515 NetObj *object = NULL;
db091a1f
VK
516 lockChildList(false);
517 for(int i = 0; i < m_childList->size(); i++)
b8014eee 518 {
db091a1f
VK
519 NetObj *curr = m_childList->get(i);
520 if (((objectId == 0) && (!_tcsicmp(curr->getName(), arg))) ||
521 (objectId == curr->getId()))
b8014eee 522 {
db091a1f 523 object = curr;
b8014eee
VK
524 break;
525 }
526 }
db091a1f 527 unlockChildList();
b8014eee
VK
528 return object;
529}
530
6fd6de0a
VK
531/**
532 * Get value for server's internal parameter
533 */
17b1ab4a 534UINT32 DataCollectionTarget::getInternalItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
6fd6de0a 535{
967893bb 536 UINT32 dwError = DCE_SUCCESS;
6fd6de0a 537
17b1ab4a 538 if (!_tcsicmp(param, _T("Status")))
6fd6de0a 539 {
db091a1f 540 _sntprintf(buffer, bufSize, _T("%d"), m_status);
6fd6de0a 541 }
1f925ee9 542 else if (!_tcsicmp(param, _T("Dummy")) || MatchString(_T("Dummy(*)"), param, FALSE))
6fd6de0a 543 {
17b1ab4a 544 _tcscpy(buffer, _T("0"));
6fd6de0a 545 }
17b1ab4a 546 else if (MatchString(_T("ChildStatus(*)"), param, FALSE))
6fd6de0a 547 {
b8014eee
VK
548 NetObj *object = objectFromParameter(param);
549 if (object != NULL)
6fd6de0a 550 {
db091a1f 551 _sntprintf(buffer, bufSize, _T("%d"), object->getStatus());
6fd6de0a
VK
552 }
553 else
554 {
555 dwError = DCE_NOT_SUPPORTED;
556 }
557 }
17b1ab4a 558 else if (MatchString(_T("ConditionStatus(*)"), param, FALSE))
6fd6de0a
VK
559 {
560 TCHAR *pEnd, szArg[256];
967893bb 561 UINT32 dwId;
6fd6de0a
VK
562 NetObj *pObject = NULL;
563
17b1ab4a 564 AgentGetParameterArg(param, 1, szArg, 256);
6fd6de0a
VK
565 dwId = _tcstoul(szArg, &pEnd, 0);
566 if (*pEnd == 0)
567 {
568 pObject = FindObjectById(dwId);
569 if (pObject != NULL)
c42b4551 570 if (pObject->getObjectClass() != OBJECT_CONDITION)
6fd6de0a
VK
571 pObject = NULL;
572 }
573 else
574 {
575 // Argument is object's name
576 pObject = FindObjectByName(szArg, OBJECT_CONDITION);
577 }
578
579 if (pObject != NULL)
580 {
c42b4551 581 if (pObject->isTrustedNode(m_id))
6fd6de0a 582 {
db091a1f 583 _sntprintf(buffer, bufSize, _T("%d"), pObject->getStatus());
6fd6de0a
VK
584 }
585 else
586 {
587 dwError = DCE_NOT_SUPPORTED;
588 }
589 }
590 else
591 {
592 dwError = DCE_NOT_SUPPORTED;
593 }
594 }
595 else
596 {
597 dwError = DCE_NOT_SUPPORTED;
598 }
599
600 return dwError;
601}
4a435beb 602
17b1ab4a
VK
603/**
604 * Get parameter value from NXSL script
605 */
606UINT32 DataCollectionTarget::getScriptItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
607{
608 TCHAR name[256];
609 nx_strncpy(name, param, 256);
610 Trim(name);
611
612 ObjectArray<NXSL_Value> args(16, 16, false);
613
614 // Can be in form parameter(arg1, arg2, ... argN)
615 TCHAR *p = _tcschr(name, _T('('));
616 if (p != NULL)
617 {
618 if (name[_tcslen(name) - 1] != _T(')'))
619 return DCE_NOT_SUPPORTED;
620 name[_tcslen(name) - 1] = 0;
621
8dd5537c 622 if (!ParseValueList(&p, args))
17b1ab4a 623 {
30b8d6c7 624 // argument parsing error
8dd5537c 625 args.clear();
30b8d6c7
VK
626 return DCE_NOT_SUPPORTED;
627 }
17b1ab4a
VK
628 }
629
630 UINT32 rc = DCE_NOT_SUPPORTED;
631 NXSL_VM *vm = g_pScriptLibrary->createVM(name, new NXSL_ServerEnv);
632 if (vm != NULL)
633 {
297a88eb 634 vm->setGlobalVariable(_T("$object"), createNXSLObject());
c42b4551 635 if (getObjectClass() == OBJECT_NODE)
17b1ab4a
VK
636 {
637 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
638 }
c42b4551 639 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
17b1ab4a
VK
640 if (vm->run(&args))
641 {
642 NXSL_Value *value = vm->getResult();
8fff1d39
VK
643 if (value->isNull())
644 {
645 // NULL value is an error indicator
a8164c20 646 rc = DCE_COLLECTION_ERROR;
8fff1d39
VK
647 }
648 else
649 {
650 const TCHAR *dciValue = value->getValueAsCString();
651 nx_strncpy(buffer, CHECK_NULL_EX(dciValue), bufSize);
652 rc = DCE_SUCCESS;
653 }
17b1ab4a
VK
654 }
655 else
656 {
c42b4551
VK
657 DbgPrintf(4, _T("DataCollectionTarget(%s)->getScriptItem(%s): Script execution error: %s"), m_name, param, vm->getErrorText());
658 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", name, vm->getErrorText(), m_id);
a8164c20 659 rc = DCE_COLLECTION_ERROR;
17b1ab4a
VK
660 }
661 delete vm;
662 }
663 else
664 {
665 args.setOwner(true);
666 }
c42b4551 667 DbgPrintf(7, _T("DataCollectionTarget(%s)->getScriptItem(%s): rc=%d"), m_name, param, rc);
17b1ab4a
VK
668 return rc;
669}
670
d32e7ef1
VK
671/**
672 * Get list from library script
673 */
674UINT32 DataCollectionTarget::getListFromScript(const TCHAR *param, StringList **list)
675{
676 TCHAR name[256];
677 nx_strncpy(name, param, 256);
678 Trim(name);
679
680 ObjectArray<NXSL_Value> args(16, 16, false);
681
682 // Can be in form parameter(arg1, arg2, ... argN)
683 TCHAR *p = _tcschr(name, _T('('));
684 if (p != NULL)
685 {
686 if (name[_tcslen(name) - 1] != _T(')'))
687 return DCE_NOT_SUPPORTED;
688 name[_tcslen(name) - 1] = 0;
689
690 if (!ParseValueList(&p, args))
691 {
692 // argument parsing error
693 args.clear();
694 return DCE_NOT_SUPPORTED;
695 }
696 }
697
698 UINT32 rc = DCE_NOT_SUPPORTED;
699 NXSL_VM *vm = g_pScriptLibrary->createVM(name, new NXSL_ServerEnv);
700 if (vm != NULL)
701 {
297a88eb 702 vm->setGlobalVariable(_T("$object"), createNXSLObject());
d32e7ef1
VK
703 if (getObjectClass() == OBJECT_NODE)
704 {
705 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
706 }
707 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
708 if (vm->run(&args))
709 {
8fff1d39 710 rc = DCE_SUCCESS;
d32e7ef1
VK
711 NXSL_Value *value = vm->getResult();
712 if (value->isArray())
713 {
714 *list = value->getValueAsArray()->toStringList();
715 }
716 else if (value->isString())
717 {
718 *list = new StringList;
719 (*list)->add(value->getValueAsCString());
720 }
8fff1d39
VK
721 else if (value->isNull())
722 {
a8164c20 723 rc = DCE_COLLECTION_ERROR;
8fff1d39 724 }
d32e7ef1
VK
725 else
726 {
727 *list = new StringList;
728 }
d32e7ef1
VK
729 }
730 else
731 {
732 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): Script execution error: %s"), m_name, param, vm->getErrorText());
733 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", name, vm->getErrorText(), m_id);
a8164c20 734 rc = DCE_COLLECTION_ERROR;
24bfa28b
VK
735 }
736 delete vm;
737 }
738 else
739 {
740 args.setOwner(true);
741 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): script \"%s\" not found"), m_name, param, name);
742 }
743 DbgPrintf(7, _T("DataCollectionTarget(%s)->getListFromScript(%s): rc=%d"), m_name, param, rc);
744 return rc;
745}
746
747/**
748 * Get string map from library script
749 */
750UINT32 DataCollectionTarget::getStringMapFromScript(const TCHAR *param, StringMap **map)
751{
752 TCHAR name[256];
753 nx_strncpy(name, param, 256);
754 Trim(name);
755
756 ObjectArray<NXSL_Value> args(16, 16, false);
757
758 // Can be in form parameter(arg1, arg2, ... argN)
759 TCHAR *p = _tcschr(name, _T('('));
760 if (p != NULL)
761 {
762 if (name[_tcslen(name) - 1] != _T(')'))
763 return DCE_NOT_SUPPORTED;
764 name[_tcslen(name) - 1] = 0;
765
766 if (!ParseValueList(&p, args))
767 {
768 // argument parsing error
769 args.clear();
770 return DCE_NOT_SUPPORTED;
771 }
772 }
773
774 UINT32 rc = DCE_NOT_SUPPORTED;
775 NXSL_VM *vm = g_pScriptLibrary->createVM(name, new NXSL_ServerEnv);
776 if (vm != NULL)
777 {
778 vm->setGlobalVariable(_T("$object"), createNXSLObject());
779 if (getObjectClass() == OBJECT_NODE)
780 {
781 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
782 }
783 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
784 if (vm->run(&args))
785 {
786 rc = DCE_SUCCESS;
787 NXSL_Value *value = vm->getResult();
788 if (value->isHashMap())
789 {
790 *map = value->getValueAsHashMap()->toStringMap();
791 }
792 else if (value->isArray())
793 {
794 *map = new StringMap();
795 NXSL_Array *a = value->getValueAsArray();
796 for(int i = 0; i < a->size(); i++)
797 {
798 NXSL_Value *v = a->getByPosition(i);
799 if (v->isString())
800 {
801 (*map)->set(v->getValueAsCString(), v->getValueAsCString());
802 }
803 }
804 }
805 else if (value->isString())
806 {
807 *map = new StringMap();
808 (*map)->set(value->getValueAsCString(), value->getValueAsCString());
809 }
810 else if (value->isNull())
811 {
a8164c20 812 rc = DCE_COLLECTION_ERROR;
24bfa28b
VK
813 }
814 else
815 {
816 *map = new StringMap();
817 }
818 }
819 else
820 {
821 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): Script execution error: %s"), m_name, param, vm->getErrorText());
822 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", name, vm->getErrorText(), m_id);
a8164c20 823 rc = DCE_COLLECTION_ERROR;
d32e7ef1
VK
824 }
825 delete vm;
826 }
827 else
828 {
829 args.setOwner(true);
830 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): script \"%s\" not found"), m_name, param, name);
831 }
832 DbgPrintf(7, _T("DataCollectionTarget(%s)->getListFromScript(%s): rc=%d"), m_name, param, rc);
833 return rc;
834}
835
4a435beb
VK
836/**
837 * Get last (current) DCI values for summary table.
838 */
2852ef09 839void DataCollectionTarget::getDciValuesSummary(SummaryTable *tableDefinition, Table *tableData)
4a435beb 840{
914580f5
VK
841 int offset = tableDefinition->isMultiInstance() ? 2 : 1;
842 int baseRow = tableData->getNumRows();
4a435beb 843 bool rowAdded = false;
b06436f4 844 lockDciAccess(false);
4a435beb
VK
845 for(int i = 0; i < tableDefinition->getNumColumns(); i++)
846 {
847 SummaryTableColumn *tc = tableDefinition->getColumn(i);
848 for(int j = 0; j < m_dcObjects->size(); j++)
849 {
850 DCObject *object = m_dcObjects->get(j);
1babf64d 851 if ((object->getType() == DCO_TYPE_ITEM) && object->hasValue() &&
c83f6449 852 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
1babf64d 853 ((tc->m_flags & COLUMN_DEFINITION_REGEXP_MATCH) ?
2da939ac
VK
854 RegexpMatch(object->getName(), tc->m_dciName, FALSE) :
855 !_tcsicmp(object->getName(), tc->m_dciName)
856 ))
4a435beb 857 {
914580f5
VK
858 int row;
859 if (tableDefinition->isMultiInstance())
4a435beb 860 {
914580f5
VK
861 // Find instance
862 const TCHAR *instance = ((DCItem *)object)->getInstance();
863 for(row = baseRow; row < tableData->getNumRows(); row++)
864 {
865 const TCHAR *v = tableData->getAsString(row, 1);
866 if (!_tcscmp(CHECK_NULL_EX(v), instance))
867 break;
868 }
869 if (row == tableData->getNumRows())
870 {
871 tableData->addRow();
872 tableData->set(0, m_name);
873 tableData->set(1, instance);
874 tableData->setObjectId(tableData->getNumRows() - 1, m_id);
875 }
4a435beb 876 }
914580f5
VK
877 else
878 {
879 if (!rowAdded)
880 {
881 tableData->addRow();
882 tableData->set(0, m_name);
883 tableData->setObjectId(tableData->getNumRows() - 1, m_id);
884 rowAdded = true;
885 }
886 row = tableData->getNumRows() - 1;
887 }
888 tableData->setStatusAt(row, i + offset, ((DCItem *)object)->getThresholdSeverity());
43666be9 889 tableData->setCellObjectIdAt(row, i + offset, object->getId());
914580f5 890 tableData->getColumnDefinitions()->get(i + offset)->setDataType(((DCItem *)object)->getDataType());
2852ef09
VK
891 if (tableDefinition->getAggregationFunction() == F_LAST)
892 {
914580f5 893 tableData->setAt(row, i + offset, ((DCItem *)object)->getLastValue());
2852ef09
VK
894 }
895 else
896 {
e83d726c 897 tableData->setAt(row, i + offset,
2852ef09 898 ((DCItem *)object)->getAggregateValue(
e83d726c 899 tableDefinition->getAggregationFunction(),
900 tableDefinition->getPeriodStart(),
2852ef09
VK
901 tableDefinition->getPeriodEnd()));
902 }
914580f5
VK
903
904 if (!tableDefinition->isMultiInstance())
905 break;
4a435beb
VK
906 }
907 }
908 }
909 unlockDciAccess();
910}
d1730ccf
VK
911
912/**
913 * Must return true if object is a possible event source
914 */
915bool DataCollectionTarget::isEventSource()
916{
917 return true;
918}
cd68963b 919
920/**
921 * Returns most critical status of DCI used for
922 * status calculation
923 */
924int DataCollectionTarget::getMostCriticalDCIStatus()
925{
926 int status = -1;
927 lockDciAccess(false);
cd68963b 928 for(int i = 0; i < m_dcObjects->size(); i++)
929 {
930 DCObject *curr = m_dcObjects->get(i);
931 if (curr->isStatusDCO() && (curr->getType() == DCO_TYPE_ITEM) &&
932 curr->hasValue() && (curr->getStatus() == ITEM_STATUS_ACTIVE))
933 {
c42b4551 934 if (getObjectClass() == OBJECT_CLUSTER && !curr->isAggregateOnCluster())
c2aa1707 935 continue; // Calculated only on those that are agregated on cluster
cd68963b 936
937 ItemValue *value = ((DCItem *)curr)->getInternalLastValue();
c2aa1707 938 if (value != NULL && (INT32)*value >= STATUS_NORMAL && (INT32)*value <= STATUS_CRITICAL)
cd68963b 939 status = max(status, (INT32)*value);
940 delete value;
941 }
942 }
943 unlockDciAccess();
c2aa1707 944 return (status == -1) ? STATUS_UNKNOWN : status;
cd68963b 945}
f94d5259
VK
946
947/**
948 * Calculate compound status
949 */
950void DataCollectionTarget::calculateCompoundStatus(BOOL bForcedRecalc)
951{
952 NetObj::calculateCompoundStatus(bForcedRecalc);
953}
ebb2dc70
VK
954
955/**
956 * Returns last ping time
957 */
958UINT32 DataCollectionTarget::getPingTime()
959{
960 if ((time(NULL) - m_pingLastTimeStamp) > g_dwStatusPollingInterval)
961 {
962 updatePingData();
963 DbgPrintf(7, _T("DataCollectionTarget::getPingTime: update ping time is required! Last ping time %d."), m_pingLastTimeStamp);
964 }
965 return m_pingTime;
966}
967
968/**
969 * Update ping data
970 */
971void DataCollectionTarget::updatePingData()
972{
973 m_pingLastTimeStamp = 0;
974 m_pingTime = PING_TIME_TIMEOUT;
975}
7e18667a
VK
976
977/**
978 * Enter maintenance mode
979 */
980void DataCollectionTarget::enterMaintenanceMode()
981{
982 DbgPrintf(4, _T("Entering maintenance mode for %s [%d]"), m_name, m_id);
983 UINT64 eventId = PostEvent2(EVENT_MAINTENANCE_MODE_ENTERED, m_id, NULL);
984 lockProperties();
985 m_maintenanceMode = true;
986 m_maintenanceEventId = eventId;
01be5c8b 987 setModified();
7e18667a
VK
988 unlockProperties();
989}
990
991/**
992 * Leave maintenance mode
993 */
994void DataCollectionTarget::leaveMaintenanceMode()
995{
996 DbgPrintf(4, _T("Leaving maintenance mode for %s [%d]"), m_name, m_id);
997 PostEvent(EVENT_MAINTENANCE_MODE_LEFT, m_id, NULL);
998 lockProperties();
999 m_maintenanceMode = false;
1000 m_maintenanceEventId = 0;
01be5c8b 1001 setModified();
7e18667a
VK
1002 unlockProperties();
1003}
77b2c6de
VK
1004
1005/**
1006 * Update cache size for given data collection item
1007 */
1008void DataCollectionTarget::updateDCItemCacheSize(UINT32 dciId, UINT32 conditionId)
1009{
1010 lockDciAccess(false);
1011 DCObject *dci = getDCObjectById(dciId, false);
1012 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
1013 {
1014 ((DCItem *)dci)->updateCacheSize(conditionId);
1015 }
1016 unlockDciAccess();
1017}
db091a1f
VK
1018
1019/**
1020 * Returns true if object is data collection target
1021 */
1022bool DataCollectionTarget::isDataCollectionTarget()
1023{
1024 return true;
1025}
46e2b370
VK
1026
1027/**
1028 * Add data collection element to proxy info structure
1029 */
1030void DataCollectionTarget::addProxyDataCollectionElement(ProxyInfo *info, const DCObject *dco)
1031{
1032 info->msg->setField(info->fieldId++, dco->getId());
1033 info->msg->setField(info->fieldId++, (INT16)dco->getType());
1034 info->msg->setField(info->fieldId++, (INT16)dco->getDataSource());
1035 info->msg->setField(info->fieldId++, dco->getName());
1036 info->msg->setField(info->fieldId++, (INT32)dco->getEffectivePollingInterval());
1037 info->msg->setFieldFromTime(info->fieldId++, dco->getLastPollTime());
1038 info->msg->setField(info->fieldId++, m_guid);
1039 info->msg->setField(info->fieldId++, dco->getSnmpPort());
1040 if (dco->getType() == DCO_TYPE_ITEM)
1041 info->msg->setField(info->fieldId++, ((DCItem *)dco)->getSnmpRawValueType());
1042 else
1043 info->msg->setField(info->fieldId++, (INT16)0);
1044 info->fieldId += 1;
1045 info->count++;
1046}
1047
1048/**
1049 * Add SNMP target to proxy info structure
1050 */
1051void DataCollectionTarget::addProxySnmpTarget(ProxyInfo *info, const Node *node)
1052{
1053 info->msg->setField(info->nodeInfoFieldId++, m_guid);
1054 info->msg->setField(info->nodeInfoFieldId++, node->getIpAddress());
1055 info->msg->setField(info->nodeInfoFieldId++, node->getSNMPVersion());
1056 info->msg->setField(info->nodeInfoFieldId++, node->getSNMPPort());
1057 SNMP_SecurityContext *snmpSecurity = node->getSnmpSecurityContext();
1058 info->msg->setField(info->nodeInfoFieldId++, (INT16)snmpSecurity->getAuthMethod());
1059 info->msg->setField(info->nodeInfoFieldId++, (INT16)snmpSecurity->getPrivMethod());
1060 info->msg->setFieldFromMBString(info->nodeInfoFieldId++, snmpSecurity->getUser());
1061 info->msg->setFieldFromMBString(info->nodeInfoFieldId++, snmpSecurity->getAuthPassword());
1062 info->msg->setFieldFromMBString(info->nodeInfoFieldId++, snmpSecurity->getPrivPassword());
1063 delete snmpSecurity;
1064 info->nodeInfoFieldId += 41;
1065 info->nodeInfoCount++;
1066}
1067
1068/**
1069 * Collect info for SNMP proxy and DCI source (proxy) nodes
1070 * Default implementation adds only agent based DCIs with source node set to requesting node
1071 */
1072void DataCollectionTarget::collectProxyInfo(ProxyInfo *info)
1073{
1074 lockDciAccess(false);
1075 for(int i = 0; i < m_dcObjects->size(); i++)
1076 {
1077 DCObject *dco = m_dcObjects->get(i);
1078 if (dco->getStatus() == ITEM_STATUS_DISABLED)
1079 continue;
1080
1081 if ((dco->getDataSource() == DS_NATIVE_AGENT) && (dco->getSourceNode() == info->proxyId) &&
1082 dco->hasValue() && (dco->getAgentCacheMode() == AGENT_CACHE_ON))
1083 {
1084 addProxyDataCollectionElement(info, dco);
1085 }
1086 }
1087 unlockDciAccess();
1088}
1089
1090/**
1091 * Callback for colecting proxied SNMP DCIs
1092 */
1093void DataCollectionTarget::collectProxyInfoCallback(NetObj *object, void *data)
1094{
1095 ((DataCollectionTarget *)object)->collectProxyInfo((ProxyInfo *)data);
1096}
1097
1098/**
1099 * Get effective source node for given data collection object
1100 */
1101UINT32 DataCollectionTarget::getEffectiveSourceNode(DCObject *dco)
1102{
1103 return dco->getSourceNode();
1104}
fcfb317c
VK
1105
1106/**
1107 * Filter for selecting templates from objects
1108 */
1109static bool TemplateSelectionFilter(NetObj *object, void *userData)
1110{
1111 return (object->getObjectClass() == OBJECT_TEMPLATE) && !object->isDeleted() && ((Template *)object)->isAutoApplyEnabled();
1112}
1113
1114/**
1115 * Apply user templates
1116 */
1117void DataCollectionTarget::applyUserTemplates()
1118{
1119 if (IsShutdownInProgress())
1120 return;
1121
1122 ObjectArray<NetObj> *templates = g_idxObjectById.getObjects(true, TemplateSelectionFilter);
1123 for(int i = 0; i < templates->size(); i++)
1124 {
1125 Template *pTemplate = (Template *)templates->get(i);
1126 AutoBindDecision decision = pTemplate->isApplicable(this);
1127 if (decision == AutoBindDecision_Bind)
1128 {
1129 if (!pTemplate->isChild(m_id))
1130 {
1131 DbgPrintf(4, _T("DataCollectionTarget::applyUserTemplates(): applying template %d \"%s\" to object %d \"%s\""),
1132 pTemplate->getId(), pTemplate->getName(), m_id, m_name);
1133 pTemplate->applyToTarget(this);
1134 PostEvent(EVENT_TEMPLATE_AUTOAPPLY, g_dwMgmtNode, "isis", m_id, m_name, pTemplate->getId(), pTemplate->getName());
1135 }
1136 }
1137 else if (decision == AutoBindDecision_Unbind)
1138 {
1139 if (pTemplate->isAutoRemoveEnabled() && pTemplate->isChild(m_id))
1140 {
1141 DbgPrintf(4, _T("DataCollectionTarget::applyUserTemplates(): removing template %d \"%s\" from object %d \"%s\""),
1142 pTemplate->getId(), pTemplate->getName(), m_id, m_name);
1143 pTemplate->deleteChild(this);
1144 deleteParent(pTemplate);
1145 pTemplate->queueRemoveFromTarget(m_id, true);
1146 PostEvent(EVENT_TEMPLATE_AUTOREMOVE, g_dwMgmtNode, "isis", m_id, m_name, pTemplate->getId(), pTemplate->getName());
1147 }
1148 }
1149 pTemplate->decRefCount();
1150 }
1151 delete templates;
1152}
1153
1154/**
1155 * Filter for selecting containers from objects
1156 */
1157static bool ContainerSelectionFilter(NetObj *object, void *userData)
1158{
1159 return (object->getObjectClass() == OBJECT_CONTAINER) && !object->isDeleted() && ((Container *)object)->isAutoBindEnabled();
1160}
1161
1162/**
1163 * Update container membership
1164 */
1165void DataCollectionTarget::updateContainerMembership()
1166{
1167 if (IsShutdownInProgress())
1168 return;
1169
1170 ObjectArray<NetObj> *containers = g_idxObjectById.getObjects(true, ContainerSelectionFilter);
1171 for(int i = 0; i < containers->size(); i++)
1172 {
1173 Container *pContainer = (Container *)containers->get(i);
1174 AutoBindDecision decision = pContainer->isSuitableForObject(this);
1175 if (decision == AutoBindDecision_Bind)
1176 {
1177 if (!pContainer->isChild(m_id))
1178 {
1179 DbgPrintf(4, _T("DataCollectionTarget::updateContainerMembership(): binding object %d \"%s\" to container %d \"%s\""),
1180 m_id, m_name, pContainer->getId(), pContainer->getName());
1181 pContainer->addChild(this);
1182 addParent(pContainer);
1183 PostEvent(EVENT_CONTAINER_AUTOBIND, g_dwMgmtNode, "isis", m_id, m_name, pContainer->getId(), pContainer->getName());
1184 pContainer->calculateCompoundStatus();
1185 }
1186 }
1187 else if (decision == AutoBindDecision_Unbind)
1188 {
1189 if (pContainer->isAutoUnbindEnabled() && pContainer->isChild(m_id))
1190 {
1191 DbgPrintf(4, _T("DataCollectionTarget::updateContainerMembership(): removing object %d \"%s\" from container %d \"%s\""),
1192 m_id, m_name, pContainer->getId(), pContainer->getName());
1193 pContainer->deleteChild(this);
1194 deleteParent(pContainer);
1195 PostEvent(EVENT_CONTAINER_AUTOUNBIND, g_dwMgmtNode, "isis", m_id, m_name, pContainer->getId(), pContainer->getName());
1196 pContainer->calculateCompoundStatus();
1197 }
1198 }
1199 pContainer->decRefCount();
1200 }
1201 delete containers;
1202}