custom attributes can be used in object tools
[public/netxms.git] / src / server / core / dc_nxsl.cpp
CommitLineData
d02f6b92
VK
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: dc_nxsl.cpp
20**
21**/
22
23#include "nxcore.h"
24
25/**
26 * NXSL function: Get DCI object
27 * First argument is a node object (usually passed to script via $node variable),
28 * and second is DCI ID
29 */
30static int F_GetDCIObject(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
31{
32 if (!argv[0]->isObject())
33 return NXSL_ERR_NOT_OBJECT;
34
35 if (!argv[1]->isInteger())
36 return NXSL_ERR_NOT_INTEGER;
37
38 NXSL_Object *object = argv[0]->getValueAsObject();
39 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
40 return NXSL_ERR_BAD_CLASS;
41
42 Node *node = (Node *)object->getData();
43 DCObject *dci = node->getDCObjectById(argv[1]->getValueAsUInt32());
44 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
45 {
46 *ppResult = new NXSL_Value(new NXSL_Object(&g_nxslDciClass, dci));
47 }
48 else
49 {
50 *ppResult = new NXSL_Value; // Return NULL if DCI not found
51 }
52
53 return 0;
54}
55
56/**
42c782b1 57 * Common handler for GetDCIValue and GetDCIRawValue
d02f6b92 58 */
42c782b1 59static int GetDCIValueImpl(bool rawValue, int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
d02f6b92
VK
60{
61 if (!argv[0]->isObject())
62 return NXSL_ERR_NOT_OBJECT;
63
64 if (!argv[1]->isInteger())
65 return NXSL_ERR_NOT_INTEGER;
66
67 NXSL_Object *object = argv[0]->getValueAsObject();
68 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
69 return NXSL_ERR_BAD_CLASS;
70
71 Node *node = (Node *)object->getData();
72 DCObject *dci = node->getDCObjectById(argv[1]->getValueAsUInt32());
73 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
74 {
42c782b1 75 *ppResult = rawValue ? ((DCItem *)dci)->getRawValueForNXSL() : ((DCItem *)dci)->getValueForNXSL(F_LAST, 1);
d02f6b92
VK
76 }
77 else
78 {
79 *ppResult = new NXSL_Value; // Return NULL if DCI not found
80 }
81
82 return 0;
83}
84
42c782b1
VK
85/**
86 * NXSL function: Get DCI value from within transformation script
87 * First argument is a node object (passed to script via $node variable),
88 * and second is DCI ID
89 */
90static int F_GetDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
91{
92 return GetDCIValueImpl(false, argc, argv, ppResult, program);
93}
94
95/**
96 * NXSL function: Get raw DCI value from within transformation script
97 * First argument is a node object (passed to script via $node variable),
98 * and second is DCI ID
99 */
100static int F_GetDCIRawValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
101{
102 return GetDCIValueImpl(true, argc, argv, ppResult, program);
103}
104
d02f6b92
VK
105/**
106 * Internal implementation of GetDCIValueByName and GetDCIValueByDescription
107 */
108static int GetDciValueExImpl(bool byName, int argc, NXSL_Value **argv, NXSL_Value **ppResult)
109{
110 if (!argv[0]->isObject())
111 return NXSL_ERR_NOT_OBJECT;
112
113 if (!argv[1]->isString())
114 return NXSL_ERR_NOT_STRING;
115
116 NXSL_Object *object = argv[0]->getValueAsObject();
117 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
118 return NXSL_ERR_BAD_CLASS;
119
120 Node *node = (Node *)object->getData();
121 DCObject *dci = byName ? node->getDCObjectByName(argv[1]->getValueAsCString()) : node->getDCObjectByDescription(argv[1]->getValueAsCString());
122 if ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM))
123 {
124 *ppResult = ((DCItem *)dci)->getValueForNXSL(F_LAST, 1);
125 }
126 else
127 {
128 *ppResult = new NXSL_Value; // Return NULL if DCI not found
129 }
130
131 return 0;
132}
133
134/**
135 * NXSL function: Get DCI value from within transformation script
136 * First argument is a node object (passed to script via $node variable),
137 * and second is DCI name
138 */
139static int F_GetDCIValueByName(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
140{
141 return GetDciValueExImpl(true, argc, argv, ppResult);
142}
143
144/**
145 * NXSL function: Get DCI value from within transformation script
146 * First argument is a node object (passed to script via $node variable),
147 * and second is DCI description
148 */
149static int F_GetDCIValueByDescription(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
150{
151 return GetDciValueExImpl(false, argc, argv, ppResult);
152}
153
154/**
155 * NXSL function: Find DCI by name
156 */
157static int F_FindDCIByName(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
158{
159 if (!argv[0]->isObject())
160 return NXSL_ERR_NOT_OBJECT;
161
162 if (!argv[1]->isString())
163 return NXSL_ERR_NOT_STRING;
164
165 NXSL_Object *object = argv[0]->getValueAsObject();
166 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
167 return NXSL_ERR_BAD_CLASS;
168
169 Node *node = (Node *)object->getData();
170 DCObject *dci = node->getDCObjectByName(argv[1]->getValueAsCString());
967893bb 171 *ppResult = ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM)) ? new NXSL_Value(dci->getId()) : new NXSL_Value((UINT32)0);
d02f6b92
VK
172 return 0;
173}
174
175/**
176 * NXSL function: Find DCI by description
177 */
178static int F_FindDCIByDescription(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
179{
180 if (!argv[0]->isObject())
181 return NXSL_ERR_NOT_OBJECT;
182
183 if (!argv[1]->isString())
184 return NXSL_ERR_NOT_STRING;
185
186 NXSL_Object *object = argv[0]->getValueAsObject();
187 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
188 return NXSL_ERR_BAD_CLASS;
189
190 Node *node = (Node *)object->getData();
191 DCObject *dci = node->getDCObjectByDescription(argv[1]->getValueAsCString());
967893bb 192 *ppResult = ((dci != NULL) && (dci->getType() == DCO_TYPE_ITEM)) ? new NXSL_Value(dci->getId()) : new NXSL_Value((UINT32)0);
d02f6b92
VK
193 return 0;
194}
195
196/**
197 * Get min, max or average of DCI values for a period
198 */
215637cc 199typedef enum { DCI_MIN = 0, DCI_MAX = 1, DCI_AVG = 2, DCI_SUM = 3 } DciSqlFunc_t;
d02f6b92
VK
200
201static int F_GetDCIValueStat(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program, DciSqlFunc_t sqlFunc)
202{
203 if (!argv[0]->isObject())
204 return NXSL_ERR_NOT_OBJECT;
205
206 if (!argv[1]->isInteger() || !argv[2]->isInteger() || !argv[3]->isInteger())
207 return NXSL_ERR_NOT_INTEGER;
208
209 NXSL_Object *object = argv[0]->getValueAsObject();
210 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
211 return NXSL_ERR_BAD_CLASS;
212
213 Node *node = (Node *)object->getData();
967893bb 214 UINT32 nodeId = node->Id();
d02f6b92
VK
215 DCObject *dci = node->getDCObjectById(argv[1]->getValueAsUInt32());
216 if (dci == NULL || dci->getType() != DCO_TYPE_ITEM)
217 {
218 *ppResult = new NXSL_Value; // Return NULL if DCI not found
219 }
220 else
221 {
222 *ppResult = NULL;
223
224 double result = 0.;
225 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
226 TCHAR query[1024];
e8e76b4f 227 static const TCHAR *functions[] = { _T("min"), _T("max"), _T("avg"), _T("sum") };
d02f6b92
VK
228
229 if (g_nDBSyntax == DB_SYNTAX_ORACLE)
230 {
231 _sntprintf(query, 1024, _T("SELECT %s(coalesce(to_number(idata_value),0)) FROM idata_%u ")
232 _T("WHERE item_id=? and idata_timestamp between ? and ?"),
215637cc 233 functions[sqlFunc], node->Id());
d02f6b92
VK
234 }
235 else if (g_nDBSyntax == DB_SYNTAX_PGSQL)
236 {
237 _sntprintf(query, 1024, _T("SELECT %s(coalesce(idata_value::double precision,0)) FROM idata_%u ")
238 _T("WHERE item_id=? and idata_timestamp between ? and ?"),
215637cc 239 functions[sqlFunc], node->Id());
d02f6b92
VK
240 }
241 else
242 {
243 _sntprintf(query, 1024, _T("SELECT %s(coalesce(idata_value,0)) FROM idata_%u ")
244 _T("WHERE item_id=? and idata_timestamp between ? and ?"),
215637cc 245 functions[sqlFunc], node->Id());
d02f6b92
VK
246 }
247
248 DB_STATEMENT hStmt = DBPrepare(hdb, query);
249 if (hStmt != NULL)
250 {
251 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, argv[1]->getValueAsUInt32());
252 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, argv[2]->getValueAsInt32());
253 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, argv[3]->getValueAsInt32());
254 DB_RESULT hResult = DBSelectPrepared(hStmt);
255 if (hResult != NULL)
256 {
257 if (DBGetNumRows(hResult) == 1)
258 {
259 result = DBGetFieldDouble(hResult, 0, 0);
260 }
261 *ppResult = new NXSL_Value(result);
262 DBFreeResult(hResult);
263 }
264 else
265 {
266 *ppResult = new NXSL_Value; // Return NULL if prepared select failed
267 }
268 DBFreeStatement(hStmt);
269 }
270 else
271 {
272 *ppResult = new NXSL_Value; // Return NULL if prepare failed
273 }
274
275 DBConnectionPoolReleaseConnection(hdb);
276 }
277
278 return 0;
279}
280
281/**
282 * Get min of DCI values for a period
283 */
284static int F_GetMinDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
285{
286 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_MIN);
287}
288
289/**
290 * Get max of DCI values for a period
291 */
292static int F_GetMaxDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
293{
294 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_MAX);
295}
296
297/**
298 * Get average of DCI values for a period
299 */
300static int F_GetAvgDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
301{
302 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_AVG);
303}
304
215637cc
VK
305/**
306 * Get average of DCI values for a period
307 */
308static int F_GetSumDCIValue(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
309{
310 return F_GetDCIValueStat(argc, argv, ppResult, program, DCI_SUM);
311}
312
d02f6b92
VK
313/**
314 * NXSL function: create new DCI
315 * Format: CreateDCI(node, origin, name, description, dataType, pollingInterval, retentionTime)
316 * Possible origin values: "agent", "snmp", "internal", "push"
317 * Possible dataType values: "int32", "uint32", "int64", "uint64", "float", "string"
318 * Returns DCI object on success and NULL of failure
319 */
320static int F_CreateDCI(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
321{
322 if (!argv[0]->isObject())
323 return NXSL_ERR_NOT_OBJECT;
324
325 if (!argv[1]->isString() || !argv[2]->isString() || !argv[3]->isString() || !argv[4]->isString())
326 return NXSL_ERR_NOT_STRING;
327
328 if (!argv[5]->isInteger() || !argv[6]->isInteger())
329 return NXSL_ERR_NOT_INTEGER;
330
331 NXSL_Object *object = argv[0]->getValueAsObject();
332 if (_tcscmp(object->getClass()->getName(), g_nxslNodeClass.getName()))
333 return NXSL_ERR_BAD_CLASS;
334 Node *node = (Node *)object->getData();
335
336 // Origin
337 static const TCHAR *originNames[] = { _T("internal"), _T("agent"), _T("snmp"), _T("cpsnmp"), _T("push"), NULL };
338 int origin = -1;
339 const TCHAR *name = argv[1]->getValueAsCString();
340 for(int i = 0; originNames[i] != NULL; i++)
341 if (!_tcsicmp(originNames[i], name))
342 {
343 origin = i;
344 break;
345 }
346
347 // Data types
348 static const TCHAR *dtNames[] = { _T("int32"), _T("uint32"), _T("int64"), _T("uint64"), _T("string"), _T("float"), NULL };
349 int dataType = -1;
350 name = argv[4]->getValueAsCString();
351 for(int i = 0; dtNames[i] != NULL; i++)
352 if (!_tcsicmp(dtNames[i], name))
353 {
354 dataType = i;
355 break;
356 }
357
358 int pollingInterval = argv[5]->getValueAsInt32();
359 int retentionTime = argv[6]->getValueAsInt32();
360
361 if ((origin != -1) && (dataType != -1) && (pollingInterval > 0) && (retentionTime > 0))
362 {
363 DCItem *dci = new DCItem(CreateUniqueId(IDG_ITEM), argv[2]->getValueAsCString(),
364 origin, dataType, pollingInterval, retentionTime, node, argv[3]->getValueAsCString());
365 node->addDCObject(dci);
366 *ppResult = new NXSL_Value(new NXSL_Object(&g_nxslDciClass, dci));
367 }
368 else
369 {
370 *ppResult = new NXSL_Value;
371 }
372 return 0;
373}
374
375/**
376 * Additional NXSL functions for DCI manipulation
377 */
378static NXSL_ExtFunction m_nxslDCIFunctions[] =
379{
380 { _T("CreateDCI"), F_CreateDCI, 7 },
381 { _T("FindDCIByName"), F_FindDCIByName, 2 },
382 { _T("FindDCIByDescription"), F_FindDCIByDescription, 2 },
215637cc 383 { _T("GetAvgDCIValue"), F_GetAvgDCIValue, 4 },
d02f6b92 384 { _T("GetDCIObject"), F_GetDCIObject, 2 },
42c782b1 385 { _T("GetDCIRawValue"), F_GetDCIRawValue, 2 },
08a5ea19 386 { _T("GetDCIValue"), F_GetDCIValue, 2 },
d02f6b92 387 { _T("GetDCIValueByDescription"), F_GetDCIValueByDescription, 2 },
215637cc 388 { _T("GetDCIValueByName"), F_GetDCIValueByName, 2 },
d02f6b92
VK
389 { _T("GetMaxDCIValue"), F_GetMaxDCIValue, 4 },
390 { _T("GetMinDCIValue"), F_GetMinDCIValue, 4 },
215637cc 391 { _T("GetSumDCIValue"), F_GetSumDCIValue, 4 }
d02f6b92
VK
392};
393
394/**
395 * Register DCI-related functions in NXSL environment
396 */
397void RegisterDCIFunctions(NXSL_Environment *pEnv)
398{
399 pEnv->registerFunctionSet(sizeof(m_nxslDCIFunctions) / sizeof(NXSL_ExtFunction), m_nxslDCIFunctions);
400}