Templates fully implemented
[public/netxms.git] / src / server / core / objects.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004 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 ** $module: objects.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25
26 //
27 // Global data
28 //
29
30 BOOL g_bModificationsLocked = FALSE;
31
32 Network *g_pEntireNet = NULL;
33 ServiceRoot *g_pServiceRoot = NULL;
34 TemplateRoot *g_pTemplateRoot = NULL;
35
36 DWORD g_dwMgmtNode = 0;
37 INDEX *g_pIndexById = NULL;
38 DWORD g_dwIdIndexSize = 0;
39 INDEX *g_pSubnetIndexByAddr = NULL;
40 DWORD g_dwSubnetAddrIndexSize = 0;
41 INDEX *g_pNodeIndexByAddr = NULL;
42 DWORD g_dwNodeAddrIndexSize = 0;
43 INDEX *g_pInterfaceIndexByAddr = NULL;
44 DWORD g_dwInterfaceAddrIndexSize = 0;
45
46 RWLOCK g_rwlockIdIndex;
47 RWLOCK g_rwlockNodeIndex;
48 RWLOCK g_rwlockSubnetIndex;
49 RWLOCK g_rwlockInterfaceIndex;
50
51 DWORD g_dwNumCategories = 0;
52 CONTAINER_CATEGORY *g_pContainerCatList = NULL;
53
54 Queue *g_pTemplateUpdateQueue = NULL;
55
56 char *g_pszStatusName[] = { "Normal", "Warning", "Minor", "Major", "Critical",
57 "Unknown", "Unmanaged", "Disabled", "Testing" };
58 char *g_szClassName[]={ "Generic", "Subnet", "Node", "Interface",
59 "Network", "Container", "Zone", "ServiceRoot",
60 "Template", "TemplateGroup", "TemplateRoot", "NetworkService" };
61
62
63 //
64 // Thread which apply template updates
65 //
66
67 static THREAD_RESULT THREAD_CALL ApplyTemplateThread(void *pArg)
68 {
69 TEMPLATE_UPDATE_INFO *pInfo;
70 NetObj *pNode;
71 BOOL bSuccess, bLock1, bLock2;
72
73 while(1)
74 {
75 pInfo = (TEMPLATE_UPDATE_INFO *)g_pTemplateUpdateQueue->GetOrBlock();
76 if (pInfo == INVALID_POINTER_VALUE)
77 break;
78
79 bSuccess = FALSE;
80 pNode = FindObjectById(pInfo->dwNodeId);
81 if (pNode != NULL)
82 {
83 if (pNode->Type() == OBJECT_NODE)
84 {
85 bLock1 = pInfo->pTemplate->LockDCIList(0x7FFFFFFF);
86 bLock2 = ((Node *)pNode)->LockDCIList(0x7FFFFFFF);
87 if (bLock1 && bLock2)
88 {
89 pInfo->pTemplate->ApplyToNode((Node *)pNode);
90 bSuccess = TRUE;
91 }
92 if (bLock1)
93 pInfo->pTemplate->UnlockDCIList(0x7FFFFFFF);
94 if (bLock2)
95 ((Node *)pNode)->UnlockDCIList(0x7FFFFFFF);
96 }
97 }
98
99 if (bSuccess)
100 {
101 free(pInfo);
102 }
103 else
104 {
105 g_pTemplateUpdateQueue->Put(pInfo); // Requeue
106 ThreadSleepMs(500);
107 }
108 }
109
110 return THREAD_OK;
111 }
112
113
114 //
115 // Initialize objects infrastructure
116 //
117
118 void ObjectsInit(void)
119 {
120 g_pTemplateUpdateQueue = new Queue;
121
122 g_rwlockIdIndex = RWLockCreate();
123 g_rwlockNodeIndex = RWLockCreate();
124 g_rwlockSubnetIndex = RWLockCreate();
125 g_rwlockInterfaceIndex = RWLockCreate();
126
127 // Create "Entire Network" object
128 g_pEntireNet = new Network;
129 NetObjInsert(g_pEntireNet, FALSE);
130
131 // Create "Service Root" object
132 g_pServiceRoot = new ServiceRoot;
133 NetObjInsert(g_pServiceRoot, FALSE);
134
135 // Create "Template Root" object
136 g_pTemplateRoot = new TemplateRoot;
137 NetObjInsert(g_pTemplateRoot, FALSE);
138 DbgPrintf(AF_DEBUG_MISC, "Built-in objects created");
139
140 // Start template update applying thread
141 ThreadCreate(ApplyTemplateThread, 0, NULL);
142 }
143
144
145 //
146 // Function to compare two indexes
147 //
148
149 static int IndexCompare(const void *pArg1, const void *pArg2)
150 {
151 return (((INDEX *)pArg1)->dwKey < ((INDEX *)pArg2)->dwKey) ? -1 :
152 ((((INDEX *)pArg1)->dwKey > ((INDEX *)pArg2)->dwKey) ? 1 : 0);
153 }
154
155
156 //
157 // Add new object to index
158 //
159
160 static void AddObjectToIndex(INDEX **ppIndex, DWORD *pdwIndexSize, DWORD dwKey, NetObj *pObject)
161 {
162 *ppIndex = (INDEX *)realloc(*ppIndex, sizeof(INDEX) * ((*pdwIndexSize) + 1));
163 (*ppIndex)[*pdwIndexSize].dwKey = dwKey;
164 (*ppIndex)[*pdwIndexSize].pObject = pObject;
165 (*pdwIndexSize)++;
166 qsort(*ppIndex, *pdwIndexSize, sizeof(INDEX), IndexCompare);
167 }
168
169
170 //
171 // Perform binary search on index
172 // Returns INVALID_INDEX if key not found or position of appropriate network object
173 // We assume that pIndex == NULL will not be passed
174 //
175
176 static DWORD SearchIndex(INDEX *pIndex, DWORD dwIndexSize, DWORD dwKey)
177 {
178 DWORD dwFirst, dwLast, dwMid;
179
180 dwFirst = 0;
181 dwLast = dwIndexSize - 1;
182
183 if ((dwKey < pIndex[0].dwKey) || (dwKey > pIndex[dwLast].dwKey))
184 return INVALID_INDEX;
185
186 while(dwFirst < dwLast)
187 {
188 dwMid = (dwFirst + dwLast) / 2;
189 if (dwKey == pIndex[dwMid].dwKey)
190 return dwMid;
191 if (dwKey < pIndex[dwMid].dwKey)
192 dwLast = dwMid - 1;
193 else
194 dwFirst = dwMid + 1;
195 }
196
197 if (dwKey == pIndex[dwLast].dwKey)
198 return dwLast;
199
200 return INVALID_INDEX;
201 }
202
203
204 //
205 // Delete object from index
206 //
207
208 static void DeleteObjectFromIndex(INDEX **ppIndex, DWORD *pdwIndexSize, DWORD dwKey)
209 {
210 DWORD dwPos;
211 INDEX *pIndex = *ppIndex;
212
213 dwPos = SearchIndex(pIndex, *pdwIndexSize, dwKey);
214 if (dwPos != INVALID_INDEX)
215 {
216 (*pdwIndexSize)--;
217 memmove(&pIndex[dwPos], &pIndex[dwPos + 1], sizeof(INDEX) * (*pdwIndexSize - dwPos));
218 }
219 }
220
221
222 //
223 // Insert new object into network
224 //
225
226 void NetObjInsert(NetObj *pObject, BOOL bNewObject)
227 {
228 if (bNewObject)
229 {
230 // Assign unique ID to new object
231 pObject->SetId(CreateUniqueId(IDG_NETWORK_OBJECT));
232
233 // Create table for storing data collection values
234 if (pObject->Type() == OBJECT_NODE)
235 {
236 char szQuery[256], szQueryTemplate[256];
237 DWORD i;
238
239 ConfigReadStr("IDataTableCreationCommand", szQueryTemplate, 255, "");
240 sprintf(szQuery, szQueryTemplate, pObject->Id());
241 DBQuery(g_hCoreDB, szQuery);
242
243 for(i = 0; i < 10; i++)
244 {
245 sprintf(szQuery, "IDataIndexCreationCommand_%d", i);
246 ConfigReadStr(szQuery, szQueryTemplate, 255, "");
247 if (szQueryTemplate[0] != 0)
248 {
249 sprintf(szQuery, szQueryTemplate, pObject->Id(), pObject->Id());
250 DBQuery(g_hCoreDB, szQuery);
251 }
252 }
253 }
254 }
255 RWLockWriteLock(g_rwlockIdIndex, INFINITE);
256 AddObjectToIndex(&g_pIndexById, &g_dwIdIndexSize, pObject->Id(), pObject);
257 RWLockUnlock(g_rwlockIdIndex);
258 if ((pObject->IpAddr() != 0) && (!pObject->IsDeleted()))
259 {
260 switch(pObject->Type())
261 {
262 case OBJECT_GENERIC:
263 case OBJECT_NETWORK:
264 case OBJECT_CONTAINER:
265 case OBJECT_SERVICEROOT:
266 case OBJECT_NETWORKSERVICE:
267 break;
268 case OBJECT_SUBNET:
269 RWLockWriteLock(g_rwlockSubnetIndex, INFINITE);
270 AddObjectToIndex(&g_pSubnetIndexByAddr, &g_dwSubnetAddrIndexSize, pObject->IpAddr(), pObject);
271 RWLockUnlock(g_rwlockSubnetIndex);
272 if (bNewObject)
273 PostEvent(EVENT_SUBNET_ADDED, pObject->Id(), NULL);
274 break;
275 case OBJECT_NODE:
276 RWLockWriteLock(g_rwlockNodeIndex, INFINITE);
277 AddObjectToIndex(&g_pNodeIndexByAddr, &g_dwNodeAddrIndexSize, pObject->IpAddr(), pObject);
278 RWLockUnlock(g_rwlockNodeIndex);
279 if (bNewObject)
280 PostEvent(EVENT_NODE_ADDED, pObject->Id(), NULL);
281 break;
282 case OBJECT_INTERFACE:
283 RWLockWriteLock(g_rwlockInterfaceIndex, INFINITE);
284 AddObjectToIndex(&g_pInterfaceIndexByAddr, &g_dwInterfaceAddrIndexSize, pObject->IpAddr(), pObject);
285 RWLockUnlock(g_rwlockInterfaceIndex);
286 break;
287 default:
288 WriteLog(MSG_BAD_NETOBJ_TYPE, EVENTLOG_ERROR_TYPE, "d", pObject->Type());
289 break;
290 }
291 }
292 }
293
294
295 //
296 // Delete object from indexes
297 // If object has an IP address, this function will delete it from
298 // appropriate index. Normally this function should be called from
299 // NetObj::Delete() method.
300 //
301
302 void NetObjDeleteFromIndexes(NetObj *pObject)
303 {
304 if (pObject->IpAddr() != 0)
305 switch(pObject->Type())
306 {
307 case OBJECT_GENERIC:
308 case OBJECT_NETWORK:
309 case OBJECT_CONTAINER:
310 case OBJECT_SERVICEROOT:
311 case OBJECT_NETWORKSERVICE:
312 break;
313 case OBJECT_SUBNET:
314 RWLockWriteLock(g_rwlockSubnetIndex, INFINITE);
315 DeleteObjectFromIndex(&g_pSubnetIndexByAddr, &g_dwSubnetAddrIndexSize, pObject->IpAddr());
316 RWLockUnlock(g_rwlockSubnetIndex);
317 break;
318 case OBJECT_NODE:
319 RWLockWriteLock(g_rwlockNodeIndex, INFINITE);
320 DeleteObjectFromIndex(&g_pNodeIndexByAddr, &g_dwNodeAddrIndexSize, pObject->IpAddr());
321 RWLockUnlock(g_rwlockNodeIndex);
322 break;
323 case OBJECT_INTERFACE:
324 RWLockWriteLock(g_rwlockInterfaceIndex, INFINITE);
325 DeleteObjectFromIndex(&g_pInterfaceIndexByAddr, &g_dwInterfaceAddrIndexSize, pObject->IpAddr());
326 RWLockUnlock(g_rwlockInterfaceIndex);
327 break;
328 default:
329 WriteLog(MSG_BAD_NETOBJ_TYPE, EVENTLOG_ERROR_TYPE, "d", pObject->Type());
330 break;
331 }
332 }
333
334
335 //
336 // Get IP netmask for object of any class
337 //
338
339 static DWORD GetObjectNetmask(NetObj *pObject)
340 {
341 switch(pObject->Type())
342 {
343 case OBJECT_INTERFACE:
344 return ((Interface *)pObject)->IpNetMask();
345 case OBJECT_SUBNET:
346 return ((Subnet *)pObject)->IpNetMask();
347 default:
348 return 0;
349 }
350 }
351
352
353 //
354 // Find node by IP address
355 //
356
357 Node NXCORE_EXPORTABLE *FindNodeByIP(DWORD dwAddr)
358 {
359 DWORD dwPos;
360 Node *pNode;
361
362 if ((g_pInterfaceIndexByAddr == NULL) || (dwAddr == 0))
363 return NULL;
364
365 RWLockReadLock(g_rwlockInterfaceIndex, INFINITE);
366 dwPos = SearchIndex(g_pInterfaceIndexByAddr, g_dwInterfaceAddrIndexSize, dwAddr);
367 pNode = (dwPos == INVALID_INDEX) ? NULL : (Node *)g_pInterfaceIndexByAddr[dwPos].pObject->GetParent();
368 RWLockUnlock(g_rwlockInterfaceIndex);
369 return pNode;
370 }
371
372
373 //
374 // Find subnet by IP address
375 //
376
377 Subnet NXCORE_EXPORTABLE *FindSubnetByIP(DWORD dwAddr)
378 {
379 DWORD dwPos;
380 Subnet *pSubnet;
381
382 if ((g_pSubnetIndexByAddr == NULL) || (dwAddr == 0))
383 return NULL;
384
385 RWLockReadLock(g_rwlockSubnetIndex, INFINITE);
386 dwPos = SearchIndex(g_pSubnetIndexByAddr, g_dwSubnetAddrIndexSize, dwAddr);
387 pSubnet = (dwPos == INVALID_INDEX) ? NULL : (Subnet *)g_pSubnetIndexByAddr[dwPos].pObject;
388 RWLockUnlock(g_rwlockSubnetIndex);
389 return pSubnet;
390 }
391
392
393 //
394 // Find subnet for given IP address
395 //
396
397 Subnet NXCORE_EXPORTABLE *FindSubnetForNode(DWORD dwNodeAddr)
398 {
399 DWORD i;
400 Subnet *pSubnet = NULL;
401
402 if ((g_pSubnetIndexByAddr == NULL) || (dwNodeAddr == 0))
403 return NULL;
404
405 RWLockReadLock(g_rwlockSubnetIndex, INFINITE);
406 for(i = 0; i < g_dwSubnetAddrIndexSize; i++)
407 if ((dwNodeAddr & ((Subnet *)g_pSubnetIndexByAddr[i].pObject)->IpNetMask()) ==
408 ((Subnet *)g_pSubnetIndexByAddr[i].pObject)->IpAddr())
409 {
410 pSubnet = (Subnet *)g_pSubnetIndexByAddr[i].pObject;
411 break;
412 }
413 RWLockUnlock(g_rwlockSubnetIndex);
414 return pSubnet;
415 }
416
417
418 //
419 // Find object by ID
420 //
421
422 NetObj NXCORE_EXPORTABLE *FindObjectById(DWORD dwId)
423 {
424 DWORD dwPos;
425 NetObj *pObject;
426
427 if (g_pIndexById == NULL)
428 return NULL;
429
430 RWLockReadLock(g_rwlockIdIndex, INFINITE);
431 dwPos = SearchIndex(g_pIndexById, g_dwIdIndexSize, dwId);
432 pObject = (dwPos == INVALID_INDEX) ? NULL : g_pIndexById[dwPos].pObject;
433 RWLockUnlock(g_rwlockIdIndex);
434 return pObject;
435 }
436
437
438 //
439 // Find local management node ID
440 //
441
442 DWORD FindLocalMgmtNode(void)
443 {
444 DWORD i, dwId = 0;
445
446 if (g_pNodeIndexByAddr == NULL)
447 return 0;
448
449 RWLockReadLock(g_rwlockNodeIndex, INFINITE);
450 for(i = 0; i < g_dwNodeAddrIndexSize; i++)
451 if (((Node *)g_pNodeIndexByAddr[i].pObject)->Flags() & NF_IS_LOCAL_MGMT)
452 {
453 dwId = g_pNodeIndexByAddr[i].pObject->Id();
454 break;
455 }
456 RWLockUnlock(g_rwlockNodeIndex);
457 return dwId;
458 }
459
460
461 //
462 // Load objects from database at stratup
463 //
464
465 BOOL LoadObjects(void)
466 {
467 DB_RESULT hResult;
468 DWORD i, dwNumRows;
469 DWORD dwId;
470 char szQuery[256];
471
472 // Prevent objects to change it's modification flag
473 g_bModificationsLocked = TRUE;
474
475 // Load container categories
476 DbgPrintf(AF_DEBUG_MISC, "Loading container categories...");
477 hResult = DBSelect(g_hCoreDB, "SELECT category,name,image_id,description FROM container_categories");
478 if (hResult != NULL)
479 {
480 g_dwNumCategories = DBGetNumRows(hResult);
481 g_pContainerCatList = (CONTAINER_CATEGORY *)malloc(sizeof(CONTAINER_CATEGORY) * g_dwNumCategories);
482 for(i = 0; i < (int)g_dwNumCategories; i++)
483 {
484 g_pContainerCatList[i].dwCatId = DBGetFieldULong(hResult, i, 0);
485 strncpy(g_pContainerCatList[i].szName, DBGetField(hResult, i, 1), MAX_OBJECT_NAME);
486 g_pContainerCatList[i].dwImageId = DBGetFieldULong(hResult, i, 2);
487 g_pContainerCatList[i].pszDescription = strdup(DBGetField(hResult, i, 3));
488 }
489 DBFreeResult(hResult);
490 }
491
492 // Load built-in object properties
493 DbgPrintf(AF_DEBUG_MISC, "Loading built-in object properties...");
494 g_pEntireNet->LoadFromDB();
495 g_pServiceRoot->LoadFromDB();
496 g_pTemplateRoot->LoadFromDB();
497
498 // Load subnets
499 DbgPrintf(AF_DEBUG_MISC, "Loading subnets...");
500 hResult = DBSelect(g_hCoreDB, "SELECT id FROM subnets");
501 if (hResult != 0)
502 {
503 Subnet *pSubnet;
504
505 dwNumRows = DBGetNumRows(hResult);
506 for(i = 0; i < dwNumRows; i++)
507 {
508 dwId = DBGetFieldULong(hResult, i, 0);
509 pSubnet = new Subnet;
510 if (pSubnet->CreateFromDB(dwId))
511 {
512 if (!pSubnet->IsDeleted())
513 g_pEntireNet->AddSubnet(pSubnet);
514 NetObjInsert(pSubnet, FALSE); // Insert into indexes
515 }
516 else // Object load failed
517 {
518 delete pSubnet;
519 WriteLog(MSG_SUBNET_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
520 }
521 }
522 DBFreeResult(hResult);
523 }
524
525 // Load nodes
526 DbgPrintf(AF_DEBUG_MISC, "Loading nodes...");
527 hResult = DBSelect(g_hCoreDB, "SELECT id FROM nodes");
528 if (hResult != 0)
529 {
530 Node *pNode;
531
532 dwNumRows = DBGetNumRows(hResult);
533 for(i = 0; i < dwNumRows; i++)
534 {
535 dwId = DBGetFieldULong(hResult, i, 0);
536 pNode = new Node;
537 if (pNode->CreateFromDB(dwId))
538 {
539 NetObjInsert(pNode, FALSE); // Insert into indexes
540 }
541 else // Object load failed
542 {
543 delete pNode;
544 WriteLog(MSG_NODE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
545 }
546 }
547 DBFreeResult(hResult);
548 }
549
550 // Load interfaces
551 DbgPrintf(AF_DEBUG_MISC, "Loading interfaces...");
552 hResult = DBSelect(g_hCoreDB, "SELECT id FROM interfaces");
553 if (hResult != 0)
554 {
555 Interface *pInterface;
556
557 dwNumRows = DBGetNumRows(hResult);
558 for(i = 0; i < dwNumRows; i++)
559 {
560 dwId = DBGetFieldULong(hResult, i, 0);
561 pInterface = new Interface;
562 if (pInterface->CreateFromDB(dwId))
563 {
564 NetObjInsert(pInterface, FALSE); // Insert into indexes
565 }
566 else // Object load failed
567 {
568 delete pInterface;
569 WriteLog(MSG_INTERFACE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
570 }
571 }
572 DBFreeResult(hResult);
573 }
574
575 // Load network services
576 DbgPrintf(AF_DEBUG_MISC, "Loading network services...");
577 hResult = DBSelect(g_hCoreDB, "SELECT id FROM network_services");
578 if (hResult != 0)
579 {
580 NetworkService *pService;
581
582 dwNumRows = DBGetNumRows(hResult);
583 for(i = 0; i < dwNumRows; i++)
584 {
585 dwId = DBGetFieldULong(hResult, i, 0);
586 pService = new NetworkService;
587 if (pService->CreateFromDB(dwId))
588 {
589 NetObjInsert(pService, FALSE); // Insert into indexes
590 }
591 else // Object load failed
592 {
593 delete pService;
594 WriteLog(MSG_NETSRV_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
595 }
596 }
597 DBFreeResult(hResult);
598 }
599
600 // Load templates
601 DbgPrintf(AF_DEBUG_MISC, "Loading templates...");
602 hResult = DBSelect(g_hCoreDB, "SELECT id FROM templates");
603 if (hResult != 0)
604 {
605 Template *pTemplate;
606
607 dwNumRows = DBGetNumRows(hResult);
608 for(i = 0; i < dwNumRows; i++)
609 {
610 dwId = DBGetFieldULong(hResult, i, 0);
611 pTemplate = new Template;
612 if (pTemplate->CreateFromDB(dwId))
613 {
614 NetObjInsert(pTemplate, FALSE); // Insert into indexes
615 }
616 else // Object load failed
617 {
618 delete pTemplate;
619 WriteLog(MSG_TEMPLATE_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
620 }
621 }
622 DBFreeResult(hResult);
623 }
624
625 // Load container objects
626 DbgPrintf(AF_DEBUG_MISC, "Loading containers...");
627 sprintf(szQuery, "SELECT id FROM containers WHERE object_class=%d", OBJECT_CONTAINER);
628 hResult = DBSelect(g_hCoreDB, szQuery);
629 if (hResult != 0)
630 {
631 Container *pContainer;
632
633 dwNumRows = DBGetNumRows(hResult);
634 for(i = 0; i < dwNumRows; i++)
635 {
636 dwId = DBGetFieldULong(hResult, i, 0);
637 pContainer = new Container;
638 if (pContainer->CreateFromDB(dwId))
639 {
640 NetObjInsert(pContainer, FALSE); // Insert into indexes
641 }
642 else // Object load failed
643 {
644 delete pContainer;
645 WriteLog(MSG_CONTAINER_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
646 }
647 }
648 DBFreeResult(hResult);
649 }
650
651 // Load template group objects
652 DbgPrintf(AF_DEBUG_MISC, "Loading template groups...");
653 sprintf(szQuery, "SELECT id FROM containers WHERE object_class=%d", OBJECT_TEMPLATEGROUP);
654 hResult = DBSelect(g_hCoreDB, szQuery);
655 if (hResult != 0)
656 {
657 TemplateGroup *pGroup;
658
659 dwNumRows = DBGetNumRows(hResult);
660 for(i = 0; i < dwNumRows; i++)
661 {
662 dwId = DBGetFieldULong(hResult, i, 0);
663 pGroup = new TemplateGroup;
664 if (pGroup->CreateFromDB(dwId))
665 {
666 NetObjInsert(pGroup, FALSE); // Insert into indexes
667 }
668 else // Object load failed
669 {
670 delete pGroup;
671 WriteLog(MSG_TG_LOAD_FAILED, EVENTLOG_ERROR_TYPE, "d", dwId);
672 }
673 }
674 DBFreeResult(hResult);
675 }
676
677 // Link childs to container and template group objects
678 DbgPrintf(AF_DEBUG_MISC, "Linking objects...");
679 for(i = 0; i < g_dwIdIndexSize; i++)
680 if ((g_pIndexById[i].pObject->Type() == OBJECT_CONTAINER) ||
681 (g_pIndexById[i].pObject->Type() == OBJECT_TEMPLATEGROUP))
682 ((Container *)g_pIndexById[i].pObject)->LinkChildObjects();
683
684 // Link childs to "Service Root" and "Template Root" objects
685 g_pServiceRoot->LinkChildObjects();
686 g_pTemplateRoot->LinkChildObjects();
687
688 // Allow objects to change it's modification flag
689 g_bModificationsLocked = FALSE;
690
691 // Recalculate status for built-in objects
692 g_pEntireNet->CalculateCompoundStatus();
693 g_pServiceRoot->CalculateCompoundStatus();
694 g_pTemplateRoot->CalculateCompoundStatus();
695
696 return TRUE;
697 }
698
699
700 //
701 // Delete user or group from all objects' ACLs
702 //
703
704 void DeleteUserFromAllObjects(DWORD dwUserId)
705 {
706 DWORD i;
707
708 // Walk through all objects
709 RWLockReadLock(g_rwlockIdIndex, INFINITE);
710 for(i = 0; i < g_dwIdIndexSize; i++)
711 g_pIndexById[i].pObject->DropUserAccess(dwUserId);
712 RWLockUnlock(g_rwlockIdIndex);
713 }
714
715
716 //
717 // Dump objects to console in standalone mode
718 //
719
720 void DumpObjects(CONSOLE_CTX pCtx)
721 {
722 DWORD i;
723 char *pBuffer;
724 CONTAINER_CATEGORY *pCat;
725
726 pBuffer = (char *)malloc(128000);
727 RWLockReadLock(g_rwlockIdIndex, INFINITE);
728 for(i = 0; i < g_dwIdIndexSize; i++)
729 {
730 ConsolePrintf(pCtx, "Object ID %d \"%s\"\n"
731 " Class: %s Primary IP: %s Status: %s IsModified: %d IsDeleted: %d\n",
732 g_pIndexById[i].pObject->Id(),g_pIndexById[i].pObject->Name(),
733 g_szClassName[g_pIndexById[i].pObject->Type()],
734 IpToStr(g_pIndexById[i].pObject->IpAddr(), pBuffer),
735 g_pszStatusName[g_pIndexById[i].pObject->Status()],
736 g_pIndexById[i].pObject->IsModified(), g_pIndexById[i].pObject->IsDeleted());
737 ConsolePrintf(pCtx, " Parents: <%s>\n Childs: <%s>\n",
738 g_pIndexById[i].pObject->ParentList(pBuffer),
739 g_pIndexById[i].pObject->ChildList(&pBuffer[4096]));
740 ConsolePrintf(pCtx, " Last change: %s\n", g_pIndexById[i].pObject->TimeStampAsText());
741 switch(g_pIndexById[i].pObject->Type())
742 {
743 case OBJECT_NODE:
744 ConsolePrintf(pCtx, " IsSNMP: %d IsAgent: %d IsLocal: %d OID: %s\n",
745 ((Node *)(g_pIndexById[i].pObject))->IsSNMPSupported(),
746 ((Node *)(g_pIndexById[i].pObject))->IsNativeAgent(),
747 ((Node *)(g_pIndexById[i].pObject))->IsLocalManagement(),
748 ((Node *)(g_pIndexById[i].pObject))->ObjectId());
749 break;
750 case OBJECT_SUBNET:
751 ConsolePrintf(pCtx, " Network mask: %s\n",
752 IpToStr(((Subnet *)g_pIndexById[i].pObject)->IpNetMask(), pBuffer));
753 break;
754 case OBJECT_CONTAINER:
755 pCat = FindContainerCategory(((Container *)g_pIndexById[i].pObject)->Category());
756 ConsolePrintf(pCtx, " Category: %s\n Description: %s\n", pCat ? pCat->szName : "<unknown>",
757 ((Container *)g_pIndexById[i].pObject)->Description());
758 break;
759 case OBJECT_TEMPLATE:
760 ConsolePrintf(pCtx, " Version: %d.%d\n Description: %s\n",
761 ((Template *)(g_pIndexById[i].pObject))->VersionMajor(),
762 ((Template *)(g_pIndexById[i].pObject))->VersionMinor(),
763 ((Template *)(g_pIndexById[i].pObject))->Description());
764 break;
765 }
766 }
767 RWLockUnlock(g_rwlockIdIndex);
768 free(pBuffer);
769 }
770
771
772 //
773 // Check is given object class is a valid parent class for other object
774 // This function is used to check manually created bindings, so i won't
775 // return TRUE for node -- subnet for example
776 //
777
778 BOOL IsValidParentClass(int iChildClass, int iParentClass)
779 {
780 switch(iParentClass)
781 {
782 case OBJECT_SERVICEROOT:
783 case OBJECT_CONTAINER:
784 if ((iChildClass == OBJECT_CONTAINER) ||
785 (iChildClass == OBJECT_NODE))
786 return TRUE;
787 break;
788 case OBJECT_TEMPLATEROOT:
789 case OBJECT_TEMPLATEGROUP:
790 if ((iChildClass == OBJECT_TEMPLATEGROUP) ||
791 (iChildClass == OBJECT_TEMPLATE))
792 return TRUE;
793 break;
794 case OBJECT_NODE:
795 if (iChildClass == OBJECT_NETWORKSERVICE)
796 return TRUE;
797 break;
798 case -1: // Creating object without parent
799 if (iChildClass == OBJECT_NODE)
800 return TRUE; // OK only for nodes, because parent subnet will be created automatically
801 break;
802 }
803 return FALSE;
804 }
805
806
807 //
808 // Delete object (final step)
809 // This function should be called ONLY from syncer thread
810 // Access to object index by id are write-locked when this function is called
811 // Object will be removed from index by ID and destroyed.
812 //
813
814 void NetObjDelete(NetObj *pObject)
815 {
816 char szQuery[256], szIpAddr[16], szNetMask[16];
817
818 // Write object to deleted objects table
819 _sntprintf(szQuery, 256, _T("INSERT INTO deleted_objects (object_id,object_class,name,"
820 "ip_addr,ip_netmask) VALUES (%ld,%ld,'%s','%s','%s')"),
821 pObject->Id(), pObject->Type(), pObject->Name(),
822 IpToStr(pObject->IpAddr(), szIpAddr),
823 IpToStr(GetObjectNetmask(pObject), szNetMask));
824 DBQuery(g_hCoreDB, szQuery);
825
826 // Delete object from index by ID and object itself
827 DeleteObjectFromIndex(&g_pIndexById, &g_dwIdIndexSize, pObject->Id());
828 delete pObject;
829 }