added virtual method NetObj::linkObjects for post-load object linking; added flags...
[public/netxms.git] / src / server / core / chassis.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 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: chassis.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Default constructor
27 */
28 Chassis::Chassis() : DataCollectionTarget()
29 {
30 m_controllerId = 0;
31 m_rackId = 0;
32 m_rackPosition = 0;
33 m_rackHeight = 1;
34 }
35
36 /**
37 * Create new chassis object
38 */
39 Chassis::Chassis(const TCHAR *name, UINT32 controllerId) : DataCollectionTarget(name)
40 {
41 m_controllerId = controllerId;
42 m_rackId = 0;
43 m_rackPosition = 0;
44 m_rackHeight = 1;
45 }
46
47 /**
48 * Destructor
49 */
50 Chassis::~Chassis()
51 {
52 }
53
54 /**
55 * Called by client session handler to check if threshold summary should be shown for this object.
56 */
57 bool Chassis::showThresholdSummary()
58 {
59 return true;
60 }
61
62 /**
63 * Update rack binding
64 */
65 void Chassis::updateRackBinding()
66 {
67 bool rackFound = false;
68 ObjectArray<NetObj> deleteList(16, 16, false);
69
70 lockParentList(true);
71 for(int i = 0; i < m_parentList->size(); i++)
72 {
73 NetObj *object = m_parentList->get(i);
74 if (object->getObjectClass() != OBJECT_RACK)
75 continue;
76 if (object->getId() == m_rackId)
77 {
78 rackFound = true;
79 continue;
80 }
81 object->incRefCount();
82 deleteList.add(object);
83 }
84 unlockParentList();
85
86 for(int n = 0; n < deleteList.size(); n++)
87 {
88 NetObj *rack = deleteList.get(n);
89 DbgPrintf(5, _T("Chassis::updateRackBinding(%s [%d]): delete incorrect rack binding %s [%d]"), m_name, m_id, rack->getName(), rack->getId());
90 rack->deleteChild(this);
91 deleteParent(rack);
92 rack->decRefCount();
93 }
94
95 if (!rackFound && (m_rackId != 0))
96 {
97 Rack *rack = (Rack *)FindObjectById(m_rackId, OBJECT_RACK);
98 if (rack != NULL)
99 {
100 DbgPrintf(5, _T("Chassis::updateRackBinding(%s [%d]): add rack binding %s [%d]"), m_name, m_id, rack->getName(), rack->getId());
101 rack->addChild(this);
102 addParent(rack);
103 }
104 else
105 {
106 DbgPrintf(5, _T("Chassis::updateRackBinding(%s [%d]): rack object [%d] not found"), m_name, m_id, m_rackId);
107 }
108 }
109 }
110
111 /**
112 * Update controller binding
113 */
114 void Chassis::updateControllerBinding()
115 {
116 bool controllerFound = false;
117
118 lockParentList(true);
119 for(int i = 0; i < m_parentList->size(); i++)
120 {
121 NetObj *object = m_parentList->get(i);
122 if (object->getId() == m_controllerId)
123 {
124 controllerFound = true;
125 break;
126 }
127 }
128 unlockParentList();
129
130 if ((m_flags & CHF_BIND_UNDER_CONTROLLER) && !controllerFound)
131 {
132 NetObj *controller = FindObjectById(m_controllerId);
133 if (controller != NULL)
134 {
135 controller->addChild(this);
136 addParent(controller);
137 }
138 else
139 {
140 nxlog_debug(4, _T("Chassis::updateControllerBinding(%s [%d]): controller object with ID %d not found"), m_name, m_id, m_controllerId);
141 }
142 }
143 else if (!(m_flags & CHF_BIND_UNDER_CONTROLLER) && controllerFound)
144 {
145 NetObj *controller = FindObjectById(m_controllerId);
146 if (controller != NULL)
147 {
148 controller->deleteChild(this);
149 deleteParent(controller);
150 }
151 }
152 }
153
154 /**
155 * Create NXCP message with object's data
156 */
157 void Chassis::fillMessageInternal(NXCPMessage *msg)
158 {
159 DataCollectionTarget::fillMessageInternal(msg);
160 msg->setField(VID_CONTROLLER_ID, m_controllerId);
161 msg->setField(VID_RACK_ID, m_rackId);
162 msg->setField(VID_RACK_IMAGE, m_rackImage);
163 msg->setField(VID_RACK_POSITION, m_rackPosition);
164 msg->setField(VID_RACK_HEIGHT, m_rackHeight);
165 }
166
167 /**
168 * Modify object from NXCP message
169 */
170 UINT32 Chassis::modifyFromMessageInternal(NXCPMessage *request)
171 {
172 if (request->isFieldExist(VID_CONTROLLER_ID))
173 m_controllerId = request->getFieldAsUInt32(VID_CONTROLLER_ID);
174 if (request->isFieldExist(VID_RACK_ID))
175 {
176 m_rackId = request->getFieldAsUInt32(VID_RACK_ID);
177 updateRackBinding();
178 }
179 if (request->isFieldExist(VID_RACK_IMAGE))
180 m_rackImage = request->getFieldAsGUID(VID_RACK_IMAGE);
181 if (request->isFieldExist(VID_RACK_POSITION))
182 m_rackPosition = request->getFieldAsInt16(VID_RACK_POSITION);
183 if (request->isFieldExist(VID_RACK_HEIGHT))
184 m_rackHeight = request->getFieldAsInt16(VID_RACK_HEIGHT);
185
186 return DataCollectionTarget::modifyFromMessageInternal(request);
187 }
188
189 /**
190 * Save to database
191 */
192 BOOL Chassis::saveToDatabase(DB_HANDLE hdb)
193 {
194 lockProperties();
195 bool success = saveCommonProperties(hdb);
196 if (success)
197 {
198 DB_STATEMENT hStmt;
199 if (IsDatabaseRecordExist(hdb, _T("chassis"), _T("id"), m_id))
200 hStmt = DBPrepare(hdb, _T("UPDATE chassis SET controller_id=?,rack_id=?,rack_image=?,rack_position=?,rack_height=?,flags=? WHERE id=?"));
201 else
202 hStmt = DBPrepare(hdb, _T("INSERT INTO chassis (controller_id,rack_id,rack_image,rack_position,rack_height,flags,id) VALUES (?,?,?,?,?,?,?)"));
203 if (hStmt != NULL)
204 {
205 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_controllerId);
206 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_rackId);
207 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_rackImage);
208 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_rackPosition);
209 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, m_rackHeight);
210 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, m_flags);
211 DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, m_id);
212 success = DBExecute(hStmt);
213 DBFreeStatement(hStmt);
214 }
215 else
216 {
217 success = false;
218 }
219 }
220 unlockProperties();
221
222 if (success)
223 {
224 lockDciAccess(false);
225 for(int i = 0; (i < m_dcObjects->size()) && success; i++)
226 success = m_dcObjects->get(i)->saveToDatabase(hdb);
227 unlockDciAccess();
228 }
229
230 if (success)
231 {
232 success = saveACLToDB(hdb);
233 }
234 return success;
235 }
236
237 /**
238 * Delete from database
239 */
240 bool Chassis::deleteFromDatabase(DB_HANDLE hdb)
241 {
242 bool success = DataCollectionTarget::deleteFromDatabase(hdb);
243 if (success)
244 {
245 success = executeQueryOnObject(hdb, _T("DELETE FROM chassis WHERE id=?"));
246 }
247 return success;
248 }
249
250 /**
251 * Load from database
252 */
253 bool Chassis::loadFromDatabase(DB_HANDLE hdb, UINT32 id)
254 {
255 m_id = id;
256 if (!loadCommonProperties(hdb))
257 {
258 nxlog_debug(2, _T("Cannot load common properties for chassis object %d"), id);
259 return false;
260 }
261
262 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT controller_id,rack_id,rack_image,rack_position,rack_height,flags FROM chassis WHERE id=?"));
263 if (hStmt == NULL)
264 return false;
265
266 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, id);
267 DB_RESULT hResult = DBSelectPrepared(hStmt);
268 if (hResult == NULL)
269 {
270 DBFreeStatement(hStmt);
271 return false;
272 }
273
274 m_controllerId = DBGetFieldULong(hResult, 0, 0);
275 m_rackId = DBGetFieldULong(hResult, 0, 1);
276 m_rackImage = DBGetFieldGUID(hResult, 0, 2);
277 m_rackPosition = DBGetFieldULong(hResult, 0, 3);
278 m_rackHeight = DBGetFieldULong(hResult, 0, 4);
279 m_flags = DBGetFieldULong(hResult, 0, 5);
280
281 DBFreeResult(hResult);
282 DBFreeStatement(hStmt);
283
284 loadACLFromDB(hdb);
285 loadItemsFromDB(hdb);
286 for(int i = 0; i < m_dcObjects->size(); i++)
287 if (!m_dcObjects->get(i)->loadThresholdsFromDB(hdb))
288 return false;
289
290 updateRackBinding();
291 return true;
292 }
293
294
295 /**
296 * Link related objects after loading from database
297 */
298 void Chassis::linkObjects()
299 {
300 DataCollectionTarget::linkObjects();
301 updateControllerBinding();
302 }
303
304 /**
305 * Called when data collection configuration changed
306 */
307 void Chassis::onDataCollectionChange()
308 {
309 Node *controller = (Node *)FindObjectById(m_controllerId, OBJECT_NODE);
310 if (controller == NULL)
311 {
312 nxlog_debug(4, _T("Chassis::onDataCollectionChange(%s [%d]): cannot find controller node object with id %d"), m_name, m_id, m_controllerId);
313 return;
314 }
315 controller->relatedNodeDataCollectionChanged();
316 }
317
318 /**
319 * Collect info for SNMP proxy and DCI source (proxy) nodes
320 */
321 void Chassis::collectProxyInfo(ProxyInfo *info)
322 {
323 Node *controller = (Node *)FindObjectById(m_controllerId, OBJECT_NODE);
324 if (controller == NULL)
325 {
326 nxlog_debug(4, _T("Chassis::collectProxyInfo(%s [%d]): cannot find controller node object with id %d"), m_name, m_id, m_controllerId);
327 return;
328 }
329
330 bool snmpProxy = (controller->getEffectiveSnmpProxy() == info->proxyId);
331 bool isTarget = false;
332
333 lockDciAccess(false);
334 for(int i = 0; i < m_dcObjects->size(); i++)
335 {
336 DCObject *dco = m_dcObjects->get(i);
337 if (dco->getStatus() == ITEM_STATUS_DISABLED)
338 continue;
339
340 if (((snmpProxy && (dco->getDataSource() == DS_SNMP_AGENT) && (dco->getSourceNode() == 0)) ||
341 ((dco->getDataSource() == DS_NATIVE_AGENT) && (dco->getSourceNode() == info->proxyId))) &&
342 dco->hasValue() && (dco->getAgentCacheMode() == AGENT_CACHE_ON))
343 {
344 addProxyDataCollectionElement(info, dco);
345 if (dco->getDataSource() == DS_SNMP_AGENT)
346 isTarget = true;
347 }
348 }
349 unlockDciAccess();
350
351 if (isTarget)
352 addProxySnmpTarget(info, controller);
353 }
354
355 /**
356 * Create NXSL object for this object
357 */
358 NXSL_Value *Chassis::createNXSLObject()
359 {
360 return new NXSL_Value(new NXSL_Object(&g_nxslChassisClass, this));
361 }
362
363 /**
364 * Get effective source node for given data collection object
365 */
366 UINT32 Chassis::getEffectiveSourceNode(DCObject *dco)
367 {
368 if (dco->getSourceNode() != 0)
369 return dco->getSourceNode();
370 if ((dco->getDataSource() == DS_NATIVE_AGENT) ||
371 (dco->getDataSource() == DS_SMCLP) ||
372 (dco->getDataSource() == DS_SNMP_AGENT) ||
373 (dco->getDataSource() == DS_WINPERF))
374 {
375 return m_controllerId;
376 }
377 return 0;
378 }
379
380 /**
381 * Update controller binding flag
382 */
383 void Chassis::setBindUnderController(bool doBind)
384 {
385 lockProperties();
386 if (doBind)
387 m_flags |= CHF_BIND_UNDER_CONTROLLER;
388 else
389 m_flags &= ~CHF_BIND_UNDER_CONTROLLER;
390 setModified(false);
391 unlockProperties();
392 updateControllerBinding();
393 }