e162b4efc166df7fda0140f1da872043ddddcc57
[public/netxms.git] / src / server / core / dctarget.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2014 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: dctarget.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Default constructor
27 */
28 DataCollectionTarget::DataCollectionTarget() : Template()
29 {
30 m_pingLastTimeStamp = 0;
31 m_pingTime = PING_TIME_TIMEOUT;
32 }
33
34 /**
35 * Constructor for creating new data collection capable objects
36 */
37 DataCollectionTarget::DataCollectionTarget(const TCHAR *name) : Template(name)
38 {
39 m_pingLastTimeStamp = 0;
40 m_pingTime = PING_TIME_TIMEOUT;
41 }
42
43 /**
44 * Destructor
45 */
46 DataCollectionTarget::~DataCollectionTarget()
47 {
48 m_pingLastTimeStamp = 0;
49 m_pingTime = PING_TIME_TIMEOUT;
50 }
51
52 /**
53 * Delete object from database
54 */
55 bool DataCollectionTarget::deleteFromDatabase(DB_HANDLE hdb)
56 {
57 bool success = Template::deleteFromDatabase(hdb);
58 if (success)
59 {
60 const TCHAR *cascade = _T("");
61 switch(g_dbSyntax)
62 {
63 case DB_SYNTAX_ORACLE:
64 cascade = _T("CASCADE CONSTRAINTS PURGE");
65 break;
66 case DB_SYNTAX_PGSQL:
67 cascade = _T("CASCADE");
68 break;
69 }
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);
83 }
84 return success;
85 }
86
87 /**
88 * Create NXCP message with object's data
89 */
90 void DataCollectionTarget::fillMessageInternal(NXCPMessage *msg)
91 {
92 Template::fillMessageInternal(msg);
93 }
94
95 /**
96 * Create NXCP message with object's data - stage 2
97 */
98 void DataCollectionTarget::fillMessageInternalStage2(NXCPMessage *msg)
99 {
100 Template::fillMessageInternalStage2(msg);
101
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;
107 lockDciAccess(false);
108 for(int i = 0; i < m_dcObjects->size(); i++)
109 {
110 DCObject *dci = m_dcObjects->get(i);
111 if ((dci->getType() == DCO_TYPE_ITEM) &&
112 (dci->getStatus() == ITEM_STATUS_ACTIVE) &&
113 (((DCItem *)dci)->getInstanceDiscoveryMethod() == IDM_NONE))
114 {
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 }
127 }
128 }
129 unlockDciAccess();
130 msg->setField(VID_OVERVIEW_DCI_COUNT, countOverview);
131 msg->setField(VID_TOOLTIP_DCI_COUNT, countTooltip);
132 }
133
134 /**
135 * Modify object from message
136 */
137 UINT32 DataCollectionTarget::modifyFromMessageInternal(NXCPMessage *pRequest)
138 {
139 return Template::modifyFromMessageInternal(pRequest);
140 }
141
142 /**
143 * Update cache for all DCI's
144 */
145 void DataCollectionTarget::updateDciCache()
146 {
147 lockDciAccess(false);
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 */
161 void DataCollectionTarget::cleanDCIData(DB_HANDLE hdb)
162 {
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
175 lockDciAccess(false);
176 for(int i = 0; i < m_dcObjects->size(); i++)
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<"));
186 queryItems.append((INT64)(now - o->getEffectiveRetentionTime() * 86400));
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<"));
197 queryTables.append((INT64)(now - o->getEffectiveRetentionTime() * 86400));
198 queryTables.append(_T(')'));
199 tableCount++;
200 }
201 }
202 unlockDciAccess();
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 }
215 }
216
217 /**
218 * Get last collected values of given table
219 */
220 UINT32 DataCollectionTarget::getTableLastValues(UINT32 dciId, NXCPMessage *msg)
221 {
222 UINT32 rcc = RCC_INVALID_DCI_ID;
223
224 lockDciAccess(false);
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 {
231 ((DCTable *)object)->fillLastValueMessage(msg);
232 rcc = RCC_SUCCESS;
233 break;
234 }
235 }
236
237 unlockDciAccess();
238 return rcc;
239 }
240
241 /**
242 * Apply DCI from template
243 * dcObject passed to this method should be a template's DCI
244 */
245 bool DataCollectionTarget::applyTemplateItem(UINT32 dwTemplateId, DCObject *dcObject)
246 {
247 bool bResult = true;
248
249 lockDciAccess(true); // write lock
250
251 DbgPrintf(5, _T("Applying DCO \"%s\" to target \"%s\""), dcObject->getName(), m_name);
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
286 DCObject *curr = m_dcObjects->get(i);
287 if ((curr->getStatus() != ITEM_STATUS_DISABLED) || (g_flags & AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE))
288 {
289 curr->updateFromTemplate(dcObject);
290 DbgPrintf(9, _T("DCO \"%s\" NOT disabled or ApplyDCIFromTemplateToDisabledDCI set, updated (%d)"),
291 dcObject->getName(), curr->getStatus());
292 if ((curr->getType() == DCO_TYPE_ITEM) && (((DCItem *)curr)->getInstanceDiscoveryMethod() != IDM_NONE))
293 {
294 updateInstanceDiscoveryItems((DCItem *)curr);
295 }
296 }
297 else
298 {
299 DbgPrintf(9, _T("DCO \"%s\" is disabled and ApplyDCIFromTemplateToDisabledDCI not set, no update (%d)"),
300 dcObject->getName(), curr->getStatus());
301 }
302 }
303
304 unlockDciAccess();
305
306 if (bResult)
307 {
308 lockProperties();
309 m_isModified = true;
310 unlockProperties();
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 */
320 void DataCollectionTarget::cleanDeletedTemplateItems(UINT32 dwTemplateId, UINT32 dwNumItems, UINT32 *pdwItemList)
321 {
322 UINT32 i, j, dwNumDeleted, *pdwDeleteList;
323
324 lockDciAccess(true); // write lock
325
326 pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
327 dwNumDeleted = 0;
328
329 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
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 /**
349 * Unbind data collection target from template, i.e either remove DCI
350 * association with template or remove these DCIs at all
351 */
352 void DataCollectionTarget::unbindFromTemplate(UINT32 dwTemplateId, bool removeDCI)
353 {
354 UINT32 i;
355
356 if (removeDCI)
357 {
358 lockDciAccess(true); // write lock
359
360 UINT32 *pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
361 UINT32 dwNumDeleted = 0;
362
363 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
364 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
365 {
366 pdwDeleteList[dwNumDeleted++] = m_dcObjects->get(i)->getId();
367 }
368
369 for(i = 0; i < dwNumDeleted; i++)
370 deleteDCObject(pdwDeleteList[i], false);
371
372 unlockDciAccess();
373
374 safe_free(pdwDeleteList);
375 }
376 else
377 {
378 lockDciAccess(false);
379
380 for(int i = 0; i < m_dcObjects->size(); i++)
381 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
382 {
383 m_dcObjects->get(i)->setTemplateId(0, 0);
384 }
385
386 unlockDciAccess();
387 }
388 }
389
390 /**
391 * Get list of DCIs to be shown on performance tab
392 */
393 UINT32 DataCollectionTarget::getPerfTabDCIList(NXCPMessage *pMsg)
394 {
395 lockDciAccess(false);
396
397 UINT32 dwId = VID_SYSDCI_LIST_BASE, dwCount = 0;
398 for(int i = 0; i < m_dcObjects->size(); i++)
399 {
400 DCObject *object = m_dcObjects->get(i);
401 if ((object->getPerfTabSettings() != NULL) &&
402 object->hasValue() &&
403 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
404 object->matchClusterResource())
405 {
406 pMsg->setField(dwId++, object->getId());
407 pMsg->setField(dwId++, object->getDescription());
408 pMsg->setField(dwId++, (WORD)object->getStatus());
409 pMsg->setField(dwId++, object->getPerfTabSettings());
410 pMsg->setField(dwId++, (WORD)object->getType());
411 pMsg->setField(dwId++, object->getTemplateItemId());
412 if (object->getType() == DCO_TYPE_ITEM)
413 {
414 pMsg->setField(dwId++, ((DCItem *)object)->getInstance());
415 if ((object->getTemplateItemId() != 0) && (object->getTemplateId() == m_id))
416 {
417 // DCI created via instance discovery - send ID of root template item
418 // to allow UI to resolve double template case
419 // (template -> instance discovery item on node -> actual item on node)
420 DCObject *src = getDCObjectById(object->getTemplateItemId(), false);
421 pMsg->setField(dwId++, (src != NULL) ? src->getTemplateItemId() : 0);
422 dwId += 2;
423 }
424 else
425 {
426 dwId += 3;
427 }
428 }
429 else
430 {
431 dwId += 4;
432 }
433 dwCount++;
434 }
435 }
436 pMsg->setField(VID_NUM_ITEMS, dwCount);
437
438 unlockDciAccess();
439 return RCC_SUCCESS;
440 }
441
442 /**
443 * Get threshold violation summary into NXCP message
444 */
445 UINT32 DataCollectionTarget::getThresholdSummary(NXCPMessage *msg, UINT32 baseId)
446 {
447 UINT32 varId = baseId;
448
449 msg->setField(varId++, m_id);
450 UINT32 countId = varId++;
451 UINT32 count = 0;
452
453 lockDciAccess(false);
454 for(int i = 0; i < m_dcObjects->size(); i++)
455 {
456 DCObject *object = m_dcObjects->get(i);
457 if (object->hasValue() && (object->getType() == DCO_TYPE_ITEM) && (object->getStatus() == ITEM_STATUS_ACTIVE))
458 {
459 if (((DCItem *)object)->hasActiveThreshold())
460 {
461 ((DCItem *)object)->fillLastValueMessage(msg, varId);
462 varId += 50;
463 count++;
464 }
465 }
466 }
467 unlockDciAccess();
468 msg->setField(countId, count);
469 return varId;
470 }
471
472 /**
473 * Process new DCI value
474 */
475 bool DataCollectionTarget::processNewDCValue(DCObject *dco, time_t currTime, const void *value)
476 {
477 bool updateStatus;
478 bool result = dco->processNewValue(currTime, value, &updateStatus);
479 if (updateStatus)
480 {
481 calculateCompoundStatus(FALSE);
482 }
483 return result;
484 }
485
486 /**
487 * Check if data collection is disabled
488 */
489 bool DataCollectionTarget::isDataCollectionDisabled()
490 {
491 return false;
492 }
493
494 /**
495 * Put items which requires polling into the queue
496 */
497 void DataCollectionTarget::queueItemsForPolling(Queue *pPollerQueue)
498 {
499 if ((m_status == STATUS_UNMANAGED) || isDataCollectionDisabled() || m_isDeleted)
500 return; // Do not collect data for unmanaged objects or if data collection is disabled
501
502 time_t currTime = time(NULL);
503
504 lockDciAccess(false);
505 for(int i = 0; i < m_dcObjects->size(); i++)
506 {
507 DCObject *object = m_dcObjects->get(i);
508 if (object->isReadyForPolling(currTime))
509 {
510 object->setBusyFlag(TRUE);
511 incRefCount(); // Increment reference count for each queued DCI
512 pPollerQueue->put(object);
513 DbgPrintf(8, _T("DataCollectionTarget(%s)->QueueItemsForPolling(): item %d \"%s\" added to queue"), m_name, object->getId(), object->getName());
514 }
515 }
516 unlockDciAccess();
517 }
518
519 /**
520 * Get object from parameter
521 */
522 NetObj *DataCollectionTarget::objectFromParameter(const TCHAR *param)
523 {
524 TCHAR *eptr, arg[256];
525 AgentGetParameterArg(param, 1, arg, 256);
526 UINT32 objectId = _tcstoul(arg, &eptr, 0);
527 if (*eptr != 0)
528 {
529 // Argument is object's name
530 objectId = 0;
531 }
532
533 // Find child object with requested ID or name
534 NetObj *object = NULL;
535 lockChildList(false);
536 for(int i = 0; i < m_childList->size(); i++)
537 {
538 NetObj *curr = m_childList->get(i);
539 if (((objectId == 0) && (!_tcsicmp(curr->getName(), arg))) ||
540 (objectId == curr->getId()))
541 {
542 object = curr;
543 break;
544 }
545 }
546 unlockChildList();
547 return object;
548 }
549
550 /**
551 * Get value for server's internal parameter
552 */
553 UINT32 DataCollectionTarget::getInternalItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
554 {
555 UINT32 dwError = DCE_SUCCESS;
556
557 if (!_tcsicmp(param, _T("Status")))
558 {
559 _sntprintf(buffer, bufSize, _T("%d"), m_status);
560 }
561 else if (!_tcsicmp(param, _T("Dummy")) || MatchString(_T("Dummy(*)"), param, FALSE))
562 {
563 _tcscpy(buffer, _T("0"));
564 }
565 else if (MatchString(_T("ChildStatus(*)"), param, FALSE))
566 {
567 NetObj *object = objectFromParameter(param);
568 if (object != NULL)
569 {
570 _sntprintf(buffer, bufSize, _T("%d"), object->getStatus());
571 }
572 else
573 {
574 dwError = DCE_NOT_SUPPORTED;
575 }
576 }
577 else if (MatchString(_T("ConditionStatus(*)"), param, FALSE))
578 {
579 TCHAR *pEnd, szArg[256];
580 UINT32 dwId;
581 NetObj *pObject = NULL;
582
583 AgentGetParameterArg(param, 1, szArg, 256);
584 dwId = _tcstoul(szArg, &pEnd, 0);
585 if (*pEnd == 0)
586 {
587 pObject = FindObjectById(dwId);
588 if (pObject != NULL)
589 if (pObject->getObjectClass() != OBJECT_CONDITION)
590 pObject = NULL;
591 }
592 else
593 {
594 // Argument is object's name
595 pObject = FindObjectByName(szArg, OBJECT_CONDITION);
596 }
597
598 if (pObject != NULL)
599 {
600 if (pObject->isTrustedNode(m_id))
601 {
602 _sntprintf(buffer, bufSize, _T("%d"), pObject->getStatus());
603 }
604 else
605 {
606 dwError = DCE_NOT_SUPPORTED;
607 }
608 }
609 else
610 {
611 dwError = DCE_NOT_SUPPORTED;
612 }
613 }
614 else
615 {
616 dwError = DCE_NOT_SUPPORTED;
617 }
618
619 return dwError;
620 }
621
622 /**
623 * Get parameter value from NXSL script
624 */
625 UINT32 DataCollectionTarget::getScriptItem(const TCHAR *param, size_t bufSize, TCHAR *buffer)
626 {
627 TCHAR name[256];
628 nx_strncpy(name, param, 256);
629 Trim(name);
630
631 ObjectArray<NXSL_Value> args(16, 16, false);
632
633 // Can be in form parameter(arg1, arg2, ... argN)
634 TCHAR *p = _tcschr(name, _T('('));
635 if (p != NULL)
636 {
637 if (name[_tcslen(name) - 1] != _T(')'))
638 return DCE_NOT_SUPPORTED;
639 name[_tcslen(name) - 1] = 0;
640
641 if (!ParseValueList(&p, args))
642 {
643 // argument parsing error
644 args.clear();
645 return DCE_NOT_SUPPORTED;
646 }
647 }
648
649 UINT32 rc = DCE_NOT_SUPPORTED;
650 NXSL_VM *vm = g_pScriptLibrary->createVM(name, new NXSL_ServerEnv);
651 if (vm != NULL)
652 {
653 vm->setGlobalVariable(_T("$object"), createNXSLObject());
654 if (getObjectClass() == OBJECT_NODE)
655 {
656 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
657 }
658 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
659 if (vm->run(&args))
660 {
661 NXSL_Value *value = vm->getResult();
662 if (value->isNull())
663 {
664 // NULL value is an error indicator
665 rc = DCE_COMM_ERROR;
666 }
667 else
668 {
669 const TCHAR *dciValue = value->getValueAsCString();
670 nx_strncpy(buffer, CHECK_NULL_EX(dciValue), bufSize);
671 rc = DCE_SUCCESS;
672 }
673 }
674 else
675 {
676 DbgPrintf(4, _T("DataCollectionTarget(%s)->getScriptItem(%s): Script execution error: %s"), m_name, param, vm->getErrorText());
677 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", name, vm->getErrorText(), m_id);
678 rc = DCE_COMM_ERROR;
679 }
680 delete vm;
681 }
682 else
683 {
684 args.setOwner(true);
685 }
686 DbgPrintf(7, _T("DataCollectionTarget(%s)->getScriptItem(%s): rc=%d"), m_name, param, rc);
687 return rc;
688 }
689
690 /**
691 * Get list from library script
692 */
693 UINT32 DataCollectionTarget::getListFromScript(const TCHAR *param, StringList **list)
694 {
695 TCHAR name[256];
696 nx_strncpy(name, param, 256);
697 Trim(name);
698
699 ObjectArray<NXSL_Value> args(16, 16, false);
700
701 // Can be in form parameter(arg1, arg2, ... argN)
702 TCHAR *p = _tcschr(name, _T('('));
703 if (p != NULL)
704 {
705 if (name[_tcslen(name) - 1] != _T(')'))
706 return DCE_NOT_SUPPORTED;
707 name[_tcslen(name) - 1] = 0;
708
709 if (!ParseValueList(&p, args))
710 {
711 // argument parsing error
712 args.clear();
713 return DCE_NOT_SUPPORTED;
714 }
715 }
716
717 UINT32 rc = DCE_NOT_SUPPORTED;
718 NXSL_VM *vm = g_pScriptLibrary->createVM(name, new NXSL_ServerEnv);
719 if (vm != NULL)
720 {
721 vm->setGlobalVariable(_T("$object"), createNXSLObject());
722 if (getObjectClass() == OBJECT_NODE)
723 {
724 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, this)));
725 }
726 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
727 if (vm->run(&args))
728 {
729 rc = DCE_SUCCESS;
730 NXSL_Value *value = vm->getResult();
731 if (value->isArray())
732 {
733 *list = value->getValueAsArray()->toStringList();
734 }
735 else if (value->isString())
736 {
737 *list = new StringList;
738 (*list)->add(value->getValueAsCString());
739 }
740 else if (value->isNull())
741 {
742 rc = DCE_COMM_ERROR;
743 }
744 else
745 {
746 *list = new StringList;
747 }
748 }
749 else
750 {
751 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): Script execution error: %s"), m_name, param, vm->getErrorText());
752 PostEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, "ssd", name, vm->getErrorText(), m_id);
753 rc = DCE_COMM_ERROR;
754 }
755 delete vm;
756 }
757 else
758 {
759 args.setOwner(true);
760 DbgPrintf(4, _T("DataCollectionTarget(%s)->getListFromScript(%s): script \"%s\" not found"), m_name, param, name);
761 }
762 DbgPrintf(7, _T("DataCollectionTarget(%s)->getListFromScript(%s): rc=%d"), m_name, param, rc);
763 return rc;
764 }
765
766 /**
767 * Get last (current) DCI values for summary table.
768 */
769 void DataCollectionTarget::getDciValuesSummary(SummaryTable *tableDefinition, Table *tableData)
770 {
771 int offset = tableDefinition->isMultiInstance() ? 2 : 1;
772 int baseRow = tableData->getNumRows();
773 bool rowAdded = false;
774 lockDciAccess(false);
775 for(int i = 0; i < tableDefinition->getNumColumns(); i++)
776 {
777 SummaryTableColumn *tc = tableDefinition->getColumn(i);
778 for(int j = 0; j < m_dcObjects->size(); j++)
779 {
780 DCObject *object = m_dcObjects->get(j);
781 if ((object->getType() == DCO_TYPE_ITEM) && object->hasValue() &&
782 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
783 ((tc->m_flags & COLUMN_DEFINITION_REGEXP_MATCH) ?
784 RegexpMatch(object->getName(), tc->m_dciName, FALSE) :
785 !_tcsicmp(object->getName(), tc->m_dciName)
786 ))
787 {
788 int row;
789 if (tableDefinition->isMultiInstance())
790 {
791 // Find instance
792 const TCHAR *instance = ((DCItem *)object)->getInstance();
793 for(row = baseRow; row < tableData->getNumRows(); row++)
794 {
795 const TCHAR *v = tableData->getAsString(row, 1);
796 if (!_tcscmp(CHECK_NULL_EX(v), instance))
797 break;
798 }
799 if (row == tableData->getNumRows())
800 {
801 tableData->addRow();
802 tableData->set(0, m_name);
803 tableData->set(1, instance);
804 tableData->setObjectId(tableData->getNumRows() - 1, m_id);
805 }
806 }
807 else
808 {
809 if (!rowAdded)
810 {
811 tableData->addRow();
812 tableData->set(0, m_name);
813 tableData->setObjectId(tableData->getNumRows() - 1, m_id);
814 rowAdded = true;
815 }
816 row = tableData->getNumRows() - 1;
817 }
818 tableData->setStatusAt(row, i + offset, ((DCItem *)object)->getThresholdSeverity());
819 tableData->setCellObjectIdAt(row, i + offset, object->getId());
820 tableData->getColumnDefinitions()->get(i + offset)->setDataType(((DCItem *)object)->getDataType());
821 if (tableDefinition->getAggregationFunction() == F_LAST)
822 {
823 tableData->setAt(row, i + offset, ((DCItem *)object)->getLastValue());
824 }
825 else
826 {
827 tableData->setAt(row, i + offset,
828 ((DCItem *)object)->getAggregateValue(
829 tableDefinition->getAggregationFunction(),
830 tableDefinition->getPeriodStart(),
831 tableDefinition->getPeriodEnd()));
832 }
833
834 if (!tableDefinition->isMultiInstance())
835 break;
836 }
837 }
838 }
839 unlockDciAccess();
840 }
841
842 /**
843 * Must return true if object is a possible event source
844 */
845 bool DataCollectionTarget::isEventSource()
846 {
847 return true;
848 }
849
850 /**
851 * Returns most critical status of DCI used for
852 * status calculation
853 */
854 int DataCollectionTarget::getMostCriticalDCIStatus()
855 {
856 int status = -1;
857 lockDciAccess(false);
858 for(int i = 0; i < m_dcObjects->size(); i++)
859 {
860 DCObject *curr = m_dcObjects->get(i);
861 if (curr->isStatusDCO() && (curr->getType() == DCO_TYPE_ITEM) &&
862 curr->hasValue() && (curr->getStatus() == ITEM_STATUS_ACTIVE))
863 {
864 if (getObjectClass() == OBJECT_CLUSTER && !curr->isAggregateOnCluster())
865 continue; // Calculated only on those that are agregated on cluster
866
867 ItemValue *value = ((DCItem *)curr)->getInternalLastValue();
868 if (value != NULL && (INT32)*value >= STATUS_NORMAL && (INT32)*value <= STATUS_CRITICAL)
869 status = max(status, (INT32)*value);
870 delete value;
871 }
872 }
873 unlockDciAccess();
874 return (status == -1) ? STATUS_UNKNOWN : status;
875 }
876
877 /**
878 * Calculate compound status
879 */
880 void DataCollectionTarget::calculateCompoundStatus(BOOL bForcedRecalc)
881 {
882 NetObj::calculateCompoundStatus(bForcedRecalc);
883 }
884
885 /**
886 * Returns last ping time
887 */
888 UINT32 DataCollectionTarget::getPingTime()
889 {
890 if ((time(NULL) - m_pingLastTimeStamp) > g_dwStatusPollingInterval)
891 {
892 updatePingData();
893 DbgPrintf(7, _T("DataCollectionTarget::getPingTime: update ping time is required! Last ping time %d."), m_pingLastTimeStamp);
894 }
895 return m_pingTime;
896 }
897
898 /**
899 * Update ping data
900 */
901 void DataCollectionTarget::updatePingData()
902 {
903 m_pingLastTimeStamp = 0;
904 m_pingTime = PING_TIME_TIMEOUT;
905 }
906
907 /**
908 * Enter maintenance mode
909 */
910 void DataCollectionTarget::enterMaintenanceMode()
911 {
912 DbgPrintf(4, _T("Entering maintenance mode for %s [%d]"), m_name, m_id);
913 UINT64 eventId = PostEvent2(EVENT_MAINTENANCE_MODE_ENTERED, m_id, NULL);
914 lockProperties();
915 m_maintenanceMode = true;
916 m_maintenanceEventId = eventId;
917 setModified();
918 unlockProperties();
919 }
920
921 /**
922 * Leave maintenance mode
923 */
924 void DataCollectionTarget::leaveMaintenanceMode()
925 {
926 DbgPrintf(4, _T("Leaving maintenance mode for %s [%d]"), m_name, m_id);
927 PostEvent(EVENT_MAINTENANCE_MODE_LEFT, m_id, NULL);
928 lockProperties();
929 m_maintenanceMode = false;
930 m_maintenanceEventId = 0;
931 setModified();
932 unlockProperties();
933 }
934
935 /**
936 * Update cache size for given data collection item
937 */
938 void DataCollectionTarget::updateDCItemCacheSize(UINT32 dciId, UINT32 conditionId)
939 {
940 lockDciAccess(false);
941 DCObject *dci = getDCObjectById(dciId, false);
942 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
943 {
944 ((DCItem *)dci)->updateCacheSize(conditionId);
945 }
946 unlockDciAccess();
947 }
948
949 /**
950 * Returns true if object is data collection target
951 */
952 bool DataCollectionTarget::isDataCollectionTarget()
953 {
954 return true;
955 }