c78f30465acd80a9821f1237f20b0c8f9bec4990
[public/netxms.git] / src / server / core / dctarget.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2013 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 }
31
32 /**
33 * Constructor for creating new data collection capable objects
34 */
35 DataCollectionTarget::DataCollectionTarget(const TCHAR *name) : Template(name)
36 {
37 }
38
39 /**
40 * Destructor
41 */
42 DataCollectionTarget::~DataCollectionTarget()
43 {
44 }
45
46 /**
47 * Delete object from database
48 */
49 bool DataCollectionTarget::deleteFromDB(DB_HANDLE hdb)
50 {
51 bool success = Template::deleteFromDB(hdb);
52 if (success)
53 {
54 TCHAR query[256];
55 _sntprintf(query, 256, _T("DROP TABLE idata_%d"), (int)m_dwId);
56 success = DBQuery(hdb, query) ? true : false;
57 if (success)
58 {
59 _sntprintf(query, 256, _T("DROP TABLE tdata_%d"), (int)m_dwId);
60 success = DBQuery(hdb, query) ? true : false;
61 }
62 if (success)
63 {
64 _sntprintf(query, 256, _T("DROP TABLE tdata_records_%d"), (int)m_dwId);
65 success = DBQuery(hdb, query) ? true : false;
66 }
67 if (success)
68 {
69 _sntprintf(query, 256, _T("DROP TABLE tdata_rows_%d"), (int)m_dwId);
70 success = DBQuery(hdb, query) ? true : false;
71 }
72 }
73 return success;
74 }
75
76 /**
77 * Create NXCP message with object's data
78 */
79 void DataCollectionTarget::CreateMessage(CSCPMessage *msg)
80 {
81 Template::CreateMessage(msg);
82 }
83
84 /**
85 * Modify object from message
86 */
87 UINT32 DataCollectionTarget::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
88 {
89 if (!bAlreadyLocked)
90 LockData();
91
92 return Template::ModifyFromMessage(pRequest, TRUE);
93 }
94
95 /**
96 * Update cache for all DCI's
97 */
98 void DataCollectionTarget::updateDciCache()
99 {
100 lockDciAccess(false);
101 for(int i = 0; i < m_dcObjects->size(); i++)
102 {
103 if (m_dcObjects->get(i)->getType() == DCO_TYPE_ITEM)
104 {
105 ((DCItem *)m_dcObjects->get(i))->updateCacheSize();
106 }
107 }
108 unlockDciAccess();
109 }
110
111 /**
112 * Clean expired DCI data
113 */
114 void DataCollectionTarget::cleanDCIData()
115 {
116 lockDciAccess(false);
117 for(int i = 0; i < m_dcObjects->size(); i++)
118 m_dcObjects->get(i)->deleteExpiredData();
119 unlockDciAccess();
120 }
121
122 /**
123 * Get last collected values of given table
124 */
125 UINT32 DataCollectionTarget::getTableLastValues(UINT32 dciId, CSCPMessage *msg)
126 {
127 UINT32 rcc = RCC_INVALID_DCI_ID;
128
129 lockDciAccess(false);
130
131 for(int i = 0; i < m_dcObjects->size(); i++)
132 {
133 DCObject *object = m_dcObjects->get(i);
134 if ((object->getId() == dciId) && (object->getType() == DCO_TYPE_TABLE))
135 {
136 ((DCTable *)object)->fillLastValueMessage(msg);
137 rcc = RCC_SUCCESS;
138 break;
139 }
140 }
141
142 unlockDciAccess();
143 return rcc;
144 }
145
146 /**
147 * Apply DCI from template
148 * pItem passed to this method should be a template's DCI
149 */
150 bool DataCollectionTarget::applyTemplateItem(UINT32 dwTemplateId, DCObject *dcObject)
151 {
152 bool bResult = true;
153
154 lockDciAccess(true); // write lock
155
156 DbgPrintf(5, _T("Applying DCO \"%s\" to target \"%s\""), dcObject->getName(), m_szName);
157
158 // Check if that template item exists
159 int i;
160 for(i = 0; i < m_dcObjects->size(); i++)
161 if ((m_dcObjects->get(i)->getTemplateId() == dwTemplateId) &&
162 (m_dcObjects->get(i)->getTemplateItemId() == dcObject->getId()))
163 break; // Item with specified id already exist
164
165 if (i == m_dcObjects->size())
166 {
167 // New item from template, just add it
168 DCObject *newObject;
169 switch(dcObject->getType())
170 {
171 case DCO_TYPE_ITEM:
172 newObject = new DCItem((DCItem *)dcObject);
173 break;
174 case DCO_TYPE_TABLE:
175 newObject = new DCTable((DCTable *)dcObject);
176 break;
177 default:
178 newObject = NULL;
179 break;
180 }
181 if (newObject != NULL)
182 {
183 newObject->setTemplateId(dwTemplateId, dcObject->getId());
184 newObject->changeBinding(CreateUniqueId(IDG_ITEM), this, TRUE);
185 bResult = addDCObject(newObject, true);
186 }
187 }
188 else
189 {
190 // Update existing item unless it is disabled
191 if (m_dcObjects->get(i)->getStatus() != ITEM_STATUS_DISABLED || (g_dwFlags & AF_APPLY_TO_DISABLED_DCI_FROM_TEMPLATE))
192 {
193 m_dcObjects->get(i)->updateFromTemplate(dcObject);
194 DbgPrintf(9, _T("DCO \"%s\" NOT disabled or ApplyDCIFromTemplateToDisabledDCI set, updated (%d)"),
195 dcObject->getName(), m_dcObjects->get(i)->getStatus());
196 }
197 else
198 {
199 DbgPrintf(9, _T("DCO \"%s\" is disabled and ApplyDCIFromTemplateToDisabledDCI not set, no update (%d)"),
200 dcObject->getName(), m_dcObjects->get(i)->getStatus());
201 }
202 }
203
204 unlockDciAccess();
205
206 if (bResult)
207 {
208 LockData();
209 m_isModified = true;
210 UnlockData();
211 }
212 return bResult;
213 }
214
215 /**
216 * Clean deleted template items from target's DCI list
217 * Arguments is template id and list of valid template item ids.
218 * all items related to given template and not presented in list should be deleted.
219 */
220 void DataCollectionTarget::cleanDeletedTemplateItems(UINT32 dwTemplateId, UINT32 dwNumItems, UINT32 *pdwItemList)
221 {
222 UINT32 i, j, dwNumDeleted, *pdwDeleteList;
223
224 lockDciAccess(true); // write lock
225
226 pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
227 dwNumDeleted = 0;
228
229 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
230 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
231 {
232 for(j = 0; j < dwNumItems; j++)
233 if (m_dcObjects->get(i)->getTemplateItemId() == pdwItemList[j])
234 break;
235
236 // Delete DCI if it's not in list
237 if (j == dwNumItems)
238 pdwDeleteList[dwNumDeleted++] = m_dcObjects->get(i)->getId();
239 }
240
241 for(i = 0; i < dwNumDeleted; i++)
242 deleteDCObject(pdwDeleteList[i], false);
243
244 unlockDciAccess();
245 free(pdwDeleteList);
246 }
247
248 /**
249 * Unbind data collection target from template, i.e either remove DCI
250 * association with template or remove these DCIs at all
251 */
252 void DataCollectionTarget::unbindFromTemplate(UINT32 dwTemplateId, BOOL bRemoveDCI)
253 {
254 UINT32 i;
255
256 if (bRemoveDCI)
257 {
258 lockDciAccess(true); // write lock
259
260 UINT32 *pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
261 UINT32 dwNumDeleted = 0;
262
263 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
264 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
265 {
266 pdwDeleteList[dwNumDeleted++] = m_dcObjects->get(i)->getId();
267 }
268
269 for(i = 0; i < dwNumDeleted; i++)
270 deleteDCObject(pdwDeleteList[i], false);
271
272 unlockDciAccess();
273
274 safe_free(pdwDeleteList);
275 }
276 else
277 {
278 lockDciAccess(false);
279
280 for(int i = 0; i < m_dcObjects->size(); i++)
281 if (m_dcObjects->get(i)->getTemplateId() == dwTemplateId)
282 {
283 m_dcObjects->get(i)->setTemplateId(0, 0);
284 }
285
286 unlockDciAccess();
287 }
288 }
289
290 /**
291 * Get list of DCIs to be shown on performance tab
292 */
293 UINT32 DataCollectionTarget::getPerfTabDCIList(CSCPMessage *pMsg)
294 {
295 lockDciAccess(false);
296
297 UINT32 dwId = VID_SYSDCI_LIST_BASE, dwCount = 0;
298 for(int i = 0; i < m_dcObjects->size(); i++)
299 {
300 DCObject *object = m_dcObjects->get(i);
301 if ((object->getPerfTabSettings() != NULL) &&
302 object->hasValue() &&
303 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
304 object->matchClusterResource())
305 {
306 pMsg->SetVariable(dwId++, object->getId());
307 pMsg->SetVariable(dwId++, object->getDescription());
308 pMsg->SetVariable(dwId++, (WORD)object->getStatus());
309 pMsg->SetVariable(dwId++, object->getPerfTabSettings());
310 pMsg->SetVariable(dwId++, (WORD)object->getType());
311 pMsg->SetVariable(dwId++, object->getTemplateItemId());
312 if (object->getType() == DCO_TYPE_ITEM)
313 {
314 pMsg->SetVariable(dwId++, ((DCItem *)object)->getInstance());
315 dwId += 3;
316 }
317 else
318 {
319 dwId += 4;
320 }
321 dwCount++;
322 }
323 }
324 pMsg->SetVariable(VID_NUM_ITEMS, dwCount);
325
326 unlockDciAccess();
327 return RCC_SUCCESS;
328 }
329
330 /**
331 * Get threshold violation summary into NXCP message
332 */
333 UINT32 DataCollectionTarget::getThresholdSummary(CSCPMessage *msg, UINT32 baseId)
334 {
335 UINT32 varId = baseId;
336
337 msg->SetVariable(varId++, m_dwId);
338 UINT32 countId = varId++;
339 UINT32 count = 0;
340
341 lockDciAccess(false);
342 for(int i = 0; i < m_dcObjects->size(); i++)
343 {
344 DCObject *object = m_dcObjects->get(i);
345 if (object->hasValue() && (object->getType() == DCO_TYPE_ITEM))
346 {
347 if (((DCItem *)object)->hasActiveThreshold())
348 {
349 ((DCItem *)object)->fillLastValueMessage(msg, varId);
350 varId += 50;
351 count++;
352 }
353 }
354 }
355 unlockDciAccess();
356 msg->SetVariable(countId, count);
357 return varId;
358 }
359
360 /**
361 * Process new DCI value
362 */
363 void DataCollectionTarget::processNewDCValue(DCObject *dco, time_t currTime, void *value)
364 {
365 lockDciAccess(false);
366 dco->processNewValue(currTime, value);
367 unlockDciAccess();
368 }
369
370 /**
371 * Check if data collection is disabled
372 */
373 bool DataCollectionTarget::isDataCollectionDisabled()
374 {
375 return false;
376 }
377
378 /**
379 * Put items which requires polling into the queue
380 */
381 void DataCollectionTarget::queueItemsForPolling(Queue *pPollerQueue)
382 {
383 if ((m_iStatus == STATUS_UNMANAGED) || isDataCollectionDisabled() || m_isDeleted)
384 return; // Do not collect data for unmanaged objects or if data collection is disabled
385
386 time_t currTime = time(NULL);
387
388 lockDciAccess(false);
389 for(int i = 0; i < m_dcObjects->size(); i++)
390 {
391 DCObject *object = m_dcObjects->get(i);
392 if (object->isReadyForPolling(currTime))
393 {
394 object->setBusyFlag(TRUE);
395 incRefCount(); // Increment reference count for each queued DCI
396 pPollerQueue->Put(object);
397 DbgPrintf(8, _T("DataCollectionTarget(%s)->QueueItemsForPolling(): item %d \"%s\" added to queue"), m_szName, object->getId(), object->getName());
398 }
399 }
400 unlockDciAccess();
401 }
402
403 /**
404 * Get value for server's internal parameter
405 */
406 UINT32 DataCollectionTarget::getInternalItem(const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer)
407 {
408 UINT32 dwError = DCE_SUCCESS;
409
410 if (!_tcsicmp(szParam, _T("Status")))
411 {
412 _sntprintf(szBuffer, dwBufSize, _T("%d"), m_iStatus);
413 }
414 else if (!_tcsicmp(szParam, _T("Dummy")))
415 {
416 _tcscpy(szBuffer, _T("0"));
417 }
418 else if (MatchString(_T("ChildStatus(*)"), szParam, FALSE))
419 {
420 TCHAR *pEnd, szArg[256];
421 UINT32 i, dwId;
422 NetObj *pObject = NULL;
423
424 AgentGetParameterArg(szParam, 1, szArg, 256);
425 dwId = _tcstoul(szArg, &pEnd, 0);
426 if (*pEnd != 0)
427 {
428 // Argument is object's name
429 dwId = 0;
430 }
431
432 // Find child object with requested ID or name
433 LockChildList(FALSE);
434 for(i = 0; i < m_dwChildCount; i++)
435 {
436 if (((dwId == 0) && (!_tcsicmp(m_pChildList[i]->Name(), szArg))) ||
437 (dwId == m_pChildList[i]->Id()))
438 {
439 pObject = m_pChildList[i];
440 break;
441 }
442 }
443 UnlockChildList();
444
445 if (pObject != NULL)
446 {
447 _sntprintf(szBuffer, dwBufSize, _T("%d"), pObject->Status());
448 }
449 else
450 {
451 dwError = DCE_NOT_SUPPORTED;
452 }
453 }
454 else if (MatchString(_T("ConditionStatus(*)"), szParam, FALSE))
455 {
456 TCHAR *pEnd, szArg[256];
457 UINT32 dwId;
458 NetObj *pObject = NULL;
459
460 AgentGetParameterArg(szParam, 1, szArg, 256);
461 dwId = _tcstoul(szArg, &pEnd, 0);
462 if (*pEnd == 0)
463 {
464 pObject = FindObjectById(dwId);
465 if (pObject != NULL)
466 if (pObject->Type() != OBJECT_CONDITION)
467 pObject = NULL;
468 }
469 else
470 {
471 // Argument is object's name
472 pObject = FindObjectByName(szArg, OBJECT_CONDITION);
473 }
474
475 if (pObject != NULL)
476 {
477 if (pObject->isTrustedNode(m_dwId))
478 {
479 _sntprintf(szBuffer, dwBufSize, _T("%d"), pObject->Status());
480 }
481 else
482 {
483 dwError = DCE_NOT_SUPPORTED;
484 }
485 }
486 else
487 {
488 dwError = DCE_NOT_SUPPORTED;
489 }
490 }
491 else
492 {
493 dwError = DCE_NOT_SUPPORTED;
494 }
495
496 return dwError;
497 }
498
499 /**
500 * Get last (current) DCI values for summary table.
501 */
502 void DataCollectionTarget::getLastValuesSummary(SummaryTable *tableDefinition, Table *tableData)
503 {
504 bool rowAdded = false;
505 lockDciAccess(false);
506 for(int i = 0; i < tableDefinition->getNumColumns(); i++)
507 {
508 SummaryTableColumn *tc = tableDefinition->getColumn(i);
509 for(int j = 0; j < m_dcObjects->size(); j++)
510 {
511 DCObject *object = m_dcObjects->get(j);
512 if ((object->getType() == DCO_TYPE_ITEM) && object->hasValue() &&
513 ((tc->m_flags & COLUMN_DEFINITION_REGEXP_MATCH) ?
514 RegexpMatch(object->getName(), tc->m_dciName, FALSE) :
515 !_tcsicmp(object->getName(), tc->m_dciName)
516 ))
517 {
518 if (!rowAdded)
519 {
520 tableData->addRow();
521 tableData->set(0, m_szName);
522 rowAdded = true;
523 }
524 tableData->set(i + 1, ((DCItem *)object)->getLastValue());
525 tableData->getColumnDefinitions()->get(i + 1)->setDataType(((DCItem *)object)->getDataType());
526 }
527 }
528 }
529 unlockDciAccess();
530 }