changed DROP TABLE order to avoid FK violation
[public/netxms.git] / src / server / core / dctarget.cpp
CommitLineData
6fd6de0a
VK
1/*
2** NetXMS - Network Management System
d51f2182 3** Copyright (C) 2003-2013 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{
30}
31
32/**
33 * Constructor for creating new data collection capable objects
34 */
35DataCollectionTarget::DataCollectionTarget(const TCHAR *name) : Template(name)
36{
37}
38
39/**
40 * Destructor
41 */
42DataCollectionTarget::~DataCollectionTarget()
43{
44}
45
46/**
47 * Delete object from database
48 */
22ee6d97 49bool DataCollectionTarget::deleteFromDB(DB_HANDLE hdb)
6fd6de0a 50{
22ee6d97
VK
51 bool success = Template::deleteFromDB(hdb);
52 if (success)
6fd6de0a 53 {
22ee6d97
VK
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 {
613f619c 59 _sntprintf(query, 256, _T("DROP TABLE tdata_rows_%d"), (int)m_dwId);
22ee6d97
VK
60 success = DBQuery(hdb, query) ? true : false;
61 }
22aaa779
VK
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 {
613f619c 69 _sntprintf(query, 256, _T("DROP TABLE tdata_%d"), (int)m_dwId);
22aaa779
VK
70 success = DBQuery(hdb, query) ? true : false;
71 }
6fd6de0a 72 }
22ee6d97 73 return success;
6fd6de0a
VK
74}
75
76/**
77 * Create NXCP message with object's data
78 */
79void DataCollectionTarget::CreateMessage(CSCPMessage *msg)
80{
81 Template::CreateMessage(msg);
82}
83
84/**
85 * Modify object from message
86 */
967893bb 87UINT32 DataCollectionTarget::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
6fd6de0a
VK
88{
89 if (!bAlreadyLocked)
90 LockData();
91
92 return Template::ModifyFromMessage(pRequest, TRUE);
93}
94
95/**
96 * Update cache for all DCI's
97 */
98void DataCollectionTarget::updateDciCache()
99{
b06436f4 100 lockDciAccess(false);
6fd6de0a
VK
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 */
114void DataCollectionTarget::cleanDCIData()
115{
b06436f4 116 lockDciAccess(false);
6fd6de0a
VK
117 for(int i = 0; i < m_dcObjects->size(); i++)
118 m_dcObjects->get(i)->deleteExpiredData();
119 unlockDciAccess();
120}
121
122/**
6fd6de0a
VK
123 * Get last collected values of given table
124 */
967893bb 125UINT32 DataCollectionTarget::getTableLastValues(UINT32 dciId, CSCPMessage *msg)
6fd6de0a 126{
967893bb 127 UINT32 rcc = RCC_INVALID_DCI_ID;
6fd6de0a 128
b06436f4 129 lockDciAccess(false);
6fd6de0a
VK
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 {
4a435beb 136 ((DCTable *)object)->fillLastValueMessage(msg);
6fd6de0a
VK
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 */
967893bb 150bool DataCollectionTarget::applyTemplateItem(UINT32 dwTemplateId, DCObject *dcObject)
6fd6de0a
VK
151{
152 bool bResult = true;
153
b06436f4 154 lockDciAccess(true); // write lock
6fd6de0a
VK
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();
01152a54 209 m_isModified = true;
6fd6de0a
VK
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 */
967893bb 220void DataCollectionTarget::cleanDeletedTemplateItems(UINT32 dwTemplateId, UINT32 dwNumItems, UINT32 *pdwItemList)
6fd6de0a 221{
967893bb 222 UINT32 i, j, dwNumDeleted, *pdwDeleteList;
6fd6de0a 223
b06436f4 224 lockDciAccess(true); // write lock
6fd6de0a 225
967893bb 226 pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
6fd6de0a
VK
227 dwNumDeleted = 0;
228
967893bb 229 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
6fd6de0a
VK
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 */
967893bb 252void DataCollectionTarget::unbindFromTemplate(UINT32 dwTemplateId, BOOL bRemoveDCI)
6fd6de0a 253{
967893bb 254 UINT32 i;
6fd6de0a
VK
255
256 if (bRemoveDCI)
257 {
b06436f4 258 lockDciAccess(true); // write lock
6fd6de0a 259
967893bb
VK
260 UINT32 *pdwDeleteList = (UINT32 *)malloc(sizeof(UINT32) * m_dcObjects->size());
261 UINT32 dwNumDeleted = 0;
6fd6de0a 262
967893bb 263 for(i = 0; i < (UINT32)m_dcObjects->size(); i++)
6fd6de0a
VK
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 {
b06436f4 278 lockDciAccess(false);
6fd6de0a
VK
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 */
967893bb 293UINT32 DataCollectionTarget::getPerfTabDCIList(CSCPMessage *pMsg)
6fd6de0a 294{
b06436f4 295 lockDciAccess(false);
6fd6de0a 296
967893bb 297 UINT32 dwId = VID_SYSDCI_LIST_BASE, dwCount = 0;
6fd6de0a
VK
298 for(int i = 0; i < m_dcObjects->size(); i++)
299 {
300 DCObject *object = m_dcObjects->get(i);
7e39d641
VK
301 if ((object->getPerfTabSettings() != NULL) &&
302 object->hasValue() &&
303 (object->getStatus() == ITEM_STATUS_ACTIVE) &&
304 object->matchClusterResource())
6fd6de0a
VK
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());
5dbf115e 311 pMsg->SetVariable(dwId++, object->getTemplateItemId());
6d6599dc
VK
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 }
6fd6de0a
VK
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 */
967893bb 333UINT32 DataCollectionTarget::getThresholdSummary(CSCPMessage *msg, UINT32 baseId)
6fd6de0a 334{
967893bb 335 UINT32 varId = baseId;
6fd6de0a
VK
336
337 msg->SetVariable(varId++, m_dwId);
967893bb
VK
338 UINT32 countId = varId++;
339 UINT32 count = 0;
6fd6de0a 340
b06436f4 341 lockDciAccess(false);
6fd6de0a
VK
342 for(int i = 0; i < m_dcObjects->size(); i++)
343 {
344 DCObject *object = m_dcObjects->get(i);
d51f2182 345 if (object->hasValue() && (object->getType() == DCO_TYPE_ITEM))
6fd6de0a
VK
346 {
347 if (((DCItem *)object)->hasActiveThreshold())
348 {
4a435beb 349 ((DCItem *)object)->fillLastValueMessage(msg, varId);
6fd6de0a
VK
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 */
363void DataCollectionTarget::processNewDCValue(DCObject *dco, time_t currTime, void *value)
364{
b06436f4 365 lockDciAccess(false);
6fd6de0a
VK
366 dco->processNewValue(currTime, value);
367 unlockDciAccess();
368}
369
370/**
371 * Check if data collection is disabled
372 */
373bool DataCollectionTarget::isDataCollectionDisabled()
374{
375 return false;
376}
377
378/**
379 * Put items which requires polling into the queue
380 */
381void DataCollectionTarget::queueItemsForPolling(Queue *pPollerQueue)
382{
01152a54 383 if ((m_iStatus == STATUS_UNMANAGED) || isDataCollectionDisabled() || m_isDeleted)
6fd6de0a
VK
384 return; // Do not collect data for unmanaged objects or if data collection is disabled
385
386 time_t currTime = time(NULL);
387
b06436f4 388 lockDciAccess(false);
6fd6de0a
VK
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);
21c9acce 395 incRefCount(); // Increment reference count for each queued DCI
6fd6de0a
VK
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 */
967893bb 406UINT32 DataCollectionTarget::getInternalItem(const TCHAR *szParam, UINT32 dwBufSize, TCHAR *szBuffer)
6fd6de0a 407{
967893bb 408 UINT32 dwError = DCE_SUCCESS;
6fd6de0a
VK
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];
967893bb 421 UINT32 i, dwId;
6fd6de0a
VK
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];
967893bb 457 UINT32 dwId;
6fd6de0a
VK
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 {
21c9acce 477 if (pObject->isTrustedNode(m_dwId))
6fd6de0a
VK
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}
4a435beb
VK
498
499/**
500 * Get last (current) DCI values for summary table.
501 */
502void DataCollectionTarget::getLastValuesSummary(SummaryTable *tableDefinition, Table *tableData)
503{
504 bool rowAdded = false;
b06436f4 505 lockDciAccess(false);
4a435beb
VK
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);
2da939ac
VK
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 ))
4a435beb
VK
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());
967893bb 525 tableData->getColumnDefinitions()->get(i + 1)->setDataType(((DCItem *)object)->getDataType());
4a435beb
VK
526 }
527 }
528 }
529 unlockDciAccess();
530}