Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimirs Maksimovs <vladimirs.maksimovs@zabbix.com>2022-11-04 17:52:15 +0300
committerVladimirs Maksimovs <vladimirs.maksimovs@zabbix.com>2022-11-04 17:52:15 +0300
commit4f4d9097321fddf2267c4d9ddd9837ec77491032 (patch)
tree2912c10ec62dc429a95a773f77eac493a114ba40
parente27a0bcd3dcdf27d3108e1f7c9b61d975167cb07 (diff)
parentb2b8335f76e81892cce2f555caf25b2ffa04432d (diff)
.......... [ZBXNEXT-6470,ZBXNEXT-6980] updated to latest from master; no conflicts
-rw-r--r--.gitignore6
-rw-r--r--ChangeLog.d/bugfix/ZBX-216551
-rw-r--r--ChangeLog.d/bugfix/ZBX-216771
-rw-r--r--ChangeLog.d/bugfix/ZBX-216871
-rw-r--r--ChangeLog.d/bugfix/ZBX-216891
-rw-r--r--ChangeLog.d/feature/ZBXNEXT-79401
-rw-r--r--ChangeLog.d/feature/ZBXNEXT-80401
-rw-r--r--build/mingw/Makefile8
-rw-r--r--build/win32/project/Makefile_agent2
-rw-r--r--build/win32/project/Makefile_get2
-rw-r--r--build/win32/project/Makefile_sender2
-rw-r--r--build/win32/project/Makefile_sender_dll2
-rw-r--r--include/zbxjson.h46
-rw-r--r--src/go/pkg/zbxlib/globals_windows.go2
-rw-r--r--src/libs/zbxjson/Makefile.am4
-rw-r--r--src/libs/zbxjson/json.c14
-rw-r--r--src/libs/zbxjson/json.h2
-rw-r--r--src/libs/zbxjson/json_parser.c127
-rw-r--r--src/libs/zbxjson/json_parser.h8
-rw-r--r--src/libs/zbxjson/jsonobj.c366
-rw-r--r--src/libs/zbxjson/jsonobj.h56
-rw-r--r--src/libs/zbxjson/jsonpath.c1297
-rw-r--r--src/libs/zbxjson/jsonpath.h21
-rw-r--r--src/libs/zbxsysinfo/linux/diskio.c2
-rw-r--r--src/libs/zbxsysinfo/linux/hardware.c7
-rw-r--r--src/libs/zbxsysinfo/linux/proc.c5
-rw-r--r--src/libs/zbxsysinfo/sysinfo.h8
-rw-r--r--src/libs/zbxsysinfo/win32/proc.c5
-rw-r--r--src/libs/zbxsysinfo/win32/services.c13
-rw-r--r--src/libs/zbxsysinfo/win32/win32.c8
-rw-r--r--src/zabbix_agent/Makefile.am2
-rw-r--r--src/zabbix_server/Makefile.am2
-rw-r--r--src/zabbix_server/poller/checks_simple_vmware.c4
-rw-r--r--src/zabbix_server/preprocessor/item_preproc.c73
-rw-r--r--src/zabbix_server/preprocessor/preproc_cache.c5
-rw-r--r--src/zabbix_server/vmware/vmware.c678
-rw-r--r--src/zabbix_server/vmware/vmware.h1
-rw-r--r--src/zabbix_server/vmware/vmware_rest.c4
-rw-r--r--templates/module/process/README.md77
-rw-r--r--templates/module/process/template_module_process.yaml332
-rw-r--r--tests/libs/zbxjson/Makefile.am20
-rw-r--r--tests/libs/zbxjson/zbx_jsonobj_query.c (renamed from tests/libs/zbxjson/zbx_jsonpath_query.c)46
-rw-r--r--tests/libs/zbxjson/zbx_jsonobj_query.inc.yaml (renamed from tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml)0
-rw-r--r--tests/libs/zbxjson/zbx_jsonobj_query.yaml (renamed from tests/libs/zbxjson/zbx_jsonpath_query.yaml)182
-rw-r--r--tests/libs/zbxjson/zbx_jsonpath_compile.c2
-rw-r--r--tests/libs/zbxsysinfo/Makefile.am3
-rw-r--r--tests/zabbix_server/poller/Makefile.am2
-rw-r--r--tests/zabbix_server/preprocessor/zbx_item_preproc.yaml6
-rw-r--r--ui/app/controllers/CControllerLatestView.php1
-rw-r--r--ui/app/views/js/monitoring.latest.view.js.php2
-rw-r--r--ui/app/views/js/monitoring.problem.view.js.php2
-rw-r--r--ui/app/views/monitoring.latest.view.php4
-rw-r--r--ui/js/widgets/class.widget.js27
-rw-r--r--ui/tests/include/web/CPage.php1
-rw-r--r--ui/tests/selenium/dashboard/testDashboardPages.php1
-rw-r--r--ui/tests/selenium/dashboard/testDashboardTriggerOverviewWidget.php16
-rw-r--r--ui/tests/selenium/testInheritanceHostPrototype.php2
57 files changed, 2579 insertions, 935 deletions
diff --git a/.gitignore b/.gitignore
index a7b68a17a62..1f5a959de20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -144,6 +144,7 @@ tests/libs/zbxcommon/zbx_function_find
tests/libs/zbxcommon/zbx_function_get_param_dyn
tests/libs/zbxcommon/zbx_get_week_number
tests/libs/zbxcommon/zbx_interval_preproc
+tests/libs/zbxcommon/zbx_iso8601_utc
tests/libs/zbxcommon/zbx_json_to_xml
tests/libs/zbxcommon/zbx_ltrim_utf8
tests/libs/zbxcommon/zbx_rtrim_utf8
@@ -190,8 +191,8 @@ tests/libs/zbxhistory/zbx_history_get_values
tests/libs/zbxjson/zbx_json_decodevalue
tests/libs/zbxjson/zbx_json_decodevalue_dyn
tests/libs/zbxjson/zbx_json_open_path
+tests/libs/zbxjson/zbx_jsonobj_query
tests/libs/zbxjson/zbx_jsonpath_compile
-tests/libs/zbxjson/zbx_jsonpath_query
tests/libs/zbxprometheus/prometheus_filter_init
tests/libs/zbxprometheus/prometheus_parse_row
tests/libs/zbxprometheus/zbx_prometheus_pattern
@@ -205,6 +206,8 @@ tests/libs/zbxserver/macro_fmttime
tests/libs/zbxserver/substitute_lld_macros
tests/libs/zbxserver/valuemaps
tests/libs/zbxsysinfo/check_key_access_rules
+tests/libs/zbxsysinfo/zbx_execute_agent_check
+tests/libs/zbxsysinfo/zbx_execute_agent_check_http
tests/libs/zbxsysinfo/common/system_localtime
tests/libs/zbxsysinfo/common/vfs_file_exists
tests/libs/zbxsysinfo/common/web_page_get
@@ -226,6 +229,7 @@ tests/libs/zbxcommon/zbx_tm_add
tests/libs/zbxcommon/zbx_tm_sub
tests/libs/zbxcommon/zbx_tm_round_up
tests/libs/zbxcommon/zbx_tm_round_down
+tests/libs/zbxtime/zbx_iso8601_utc
tests/libs/zbxtrends/zbx_baseline_get_data
tests/libs/zbxtrends/zbx_trends_parse_range
tests/libs/zbxsysinfo/process_http
diff --git a/ChangeLog.d/bugfix/ZBX-21655 b/ChangeLog.d/bugfix/ZBX-21655
new file mode 100644
index 00000000000..beffcf71e44
--- /dev/null
+++ b/ChangeLog.d/bugfix/ZBX-21655
@@ -0,0 +1 @@
+.......PS. [ZBX-21655] fixed VMware datastore discovery to not return same datastore multiple times (asestakovs)
diff --git a/ChangeLog.d/bugfix/ZBX-21677 b/ChangeLog.d/bugfix/ZBX-21677
new file mode 100644
index 00000000000..56d9cc310f2
--- /dev/null
+++ b/ChangeLog.d/bugfix/ZBX-21677
@@ -0,0 +1 @@
+..F....... [ZBX-21677] fixed checkbox resetting in Monitoring->Latest data and Monitoring->Problems (rdetlavs)
diff --git a/ChangeLog.d/bugfix/ZBX-21687 b/ChangeLog.d/bugfix/ZBX-21687
new file mode 100644
index 00000000000..111d856e167
--- /dev/null
+++ b/ChangeLog.d/bugfix/ZBX-21687
@@ -0,0 +1 @@
+..F....... [ZBX-21687] fixed persistent preloader icons over dashboard widgets on Safari 16 (averza)
diff --git a/ChangeLog.d/bugfix/ZBX-21689 b/ChangeLog.d/bugfix/ZBX-21689
new file mode 100644
index 00000000000..0a25ef361b5
--- /dev/null
+++ b/ChangeLog.d/bugfix/ZBX-21689
@@ -0,0 +1 @@
+...G...... [ZBX-21689] fixed proc.num to not crash agent on Windows when 'user' parameter is set (asestakovs)
diff --git a/ChangeLog.d/feature/ZBXNEXT-7940 b/ChangeLog.d/feature/ZBXNEXT-7940
new file mode 100644
index 00000000000..4cefde4bc30
--- /dev/null
+++ b/ChangeLog.d/feature/ZBXNEXT-7940
@@ -0,0 +1 @@
+.........T [ZBXNEXT-7940] added template OS processes by Zabbix agent (egordymov)
diff --git a/ChangeLog.d/feature/ZBXNEXT-8040 b/ChangeLog.d/feature/ZBXNEXT-8040
new file mode 100644
index 00000000000..15238ae2c93
--- /dev/null
+++ b/ChangeLog.d/feature/ZBXNEXT-8040
@@ -0,0 +1 @@
+.......PS. [ZBXNEXT-8040] added object based json parsing and jsonpath optimizations (wiper)
diff --git a/build/mingw/Makefile b/build/mingw/Makefile
index 66dabc2c9e6..dd7c35a73b1 100644
--- a/build/mingw/Makefile
+++ b/build/mingw/Makefile
@@ -34,6 +34,7 @@ OBJS = \
$(OUTPUTDIR)\md5.o \
$(OUTPUTDIR)\sysinfo.o \
$(OUTPUTDIR)\vector.o \
+ $(OUTPUTDIR)\hashset.o \
$(OUTPUTDIR)\zbxregexp.o \
$(OUTPUTDIR)\persistent_state.o \
$(OUTPUTDIR)\logfiles.o \
@@ -42,6 +43,7 @@ OBJS = \
$(OUTPUTDIR)\json.o \
$(OUTPUTDIR)\json_parser.o \
$(OUTPUTDIR)\jsonpath.o \
+ $(OUTPUTDIR)\jsonobj.o \
$(OUTPUTDIR)\sha256crypt.o \
$(OUTPUTDIR)\variant.o \
$(OUTPUTDIR)\sysinfo_system.o \
@@ -179,6 +181,9 @@ $(OUTPUTDIR)\json_parser.o: $(TOPDIR)\src\libs\zbxjson\json_parser.c
$(OUTPUTDIR)\jsonpath.o: $(TOPDIR)\src\libs\zbxjson\jsonpath.c
$(CC) $(CFLAGS) -DUNICODE -DWITH_COMMON_METRICS -c $^ -o $@
+$(OUTPUTDIR)\jsonobj.o: $(TOPDIR)\src\libs\zbxjson\jsonobj.c
+ $(CC) $(CFLAGS) -DUNICODE -DWITH_COMMON_METRICS -c $^ -o $@
+
$(OUTPUTDIR)\sha256crypt.o: $(TOPDIR)\src\libs\zbxhash\sha256crypt.c
$(CC) $(CFLAGS) -DUNICODE -DWITH_COMMON_METRICS -c $^ -o $@
@@ -209,6 +214,9 @@ $(OUTPUTDIR)\sysinfo_alias.o: $(TOPDIR)\src\libs\zbxsysinfo\alias\alias.c
$(OUTPUTDIR)\vector.o: $(TOPDIR)\src\libs\zbxalgo\vector.c
$(CC) $(CFLAGS) -DUNICODE -c $^ -o $@
+$(OUTPUTDIR)\hashset.o: $(TOPDIR)\src\libs\zbxalgo\hashset.c
+ $(CC) $(CFLAGS) -DUNICODE -c $^ -o $@
+
$(OUTPUTDIR)\version.o: $(TOPDIR)\src\libs\zbxversion\version.c
$(CC) $(CFLAGS) -DUNICODE -c $^ -o $@
diff --git a/build/win32/project/Makefile_agent b/build/win32/project/Makefile_agent
index ae7cde69102..8b37be7e784 100644
--- a/build/win32/project/Makefile_agent
+++ b/build/win32/project/Makefile_agent
@@ -37,6 +37,7 @@ ADD_RFLAGS = /d "ZABBIX_AGENT"
OBJS = \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxip\ip.o \
..\..\..\src\libs\zbxip\iprange.o \
@@ -66,6 +67,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxmutexs\mutexs.o \
..\..\..\src\libs\zbxsymbols\symbols.o \
diff --git a/build/win32/project/Makefile_get b/build/win32/project/Makefile_get
index d10b275b2d4..8fe19a2417a 100644
--- a/build/win32/project/Makefile_get
+++ b/build/win32/project/Makefile_get
@@ -29,6 +29,7 @@ ADD_RFLAGS = /d "ZABBIX_GET"
OBJS = \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxip\ip.o \
..\..\..\src\libs\zbxip\iprange.o \
@@ -56,6 +57,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxmutexs\mutexs.o \
..\..\..\src\libs\zbxsymbols\symbols.o \
diff --git a/build/win32/project/Makefile_sender b/build/win32/project/Makefile_sender
index d7443a2560e..e22e8ce79df 100644
--- a/build/win32/project/Makefile_sender
+++ b/build/win32/project/Makefile_sender
@@ -56,6 +56,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxmutexs\mutexs.o \
..\..\..\src\libs\zbxsymbols\symbols.o \
@@ -64,6 +65,7 @@ OBJS = \
..\..\..\src\libs\zbxwin32\fatal.o \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxregexp\zbxregexp.o \
..\..\..\src\libs\zbxversion\version.o \
..\..\..\src\libs\zbxxml\xml.o \
diff --git a/build/win32/project/Makefile_sender_dll b/build/win32/project/Makefile_sender_dll
index eb8275cba64..0a5d1c05fd8 100644
--- a/build/win32/project/Makefile_sender_dll
+++ b/build/win32/project/Makefile_sender_dll
@@ -60,6 +60,7 @@ OBJS = \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
..\..\..\src\libs\zbxjson\jsonpath.o \
+ ..\..\..\src\libs\zbxjson\jsonobj.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxmutexs\mutexs.o \
..\..\..\src\libs\zbxsymbols\symbols.o \
@@ -68,6 +69,7 @@ OBJS = \
..\..\..\src\libs\zbxwin32\fatal.o \
..\..\..\src\libs\zbxalgo\algodefs.o \
..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxalgo\hashset.o \
..\..\..\src\libs\zbxregexp\zbxregexp.o \
..\..\..\src\libs\zbxversion\version.o \
..\..\..\src\libs\zbxxml\xml.o \
diff --git a/include/zbxjson.h b/include/zbxjson.h
index 28ed6fd68a6..e5c91376b14 100644
--- a/include/zbxjson.h
+++ b/include/zbxjson.h
@@ -21,6 +21,7 @@
#define ZABBIX_ZJSON_H
#include "zbxtypes.h"
+#include "zbxalgo.h"
#define ZBX_PROTO_TAG_CLOCK "clock"
#define ZBX_PROTO_TAG_NS "ns"
@@ -250,7 +251,8 @@ typedef enum
ZBX_JSON_TYPE_OBJECT,
ZBX_JSON_TYPE_NULL,
ZBX_JSON_TYPE_TRUE,
- ZBX_JSON_TYPE_FALSE
+ ZBX_JSON_TYPE_FALSE,
+ ZBX_JSON_TYPE_NUMBER
}
zbx_json_type_t;
@@ -330,11 +332,51 @@ typedef struct
/* set to 1 when jsonpath points at single location */
unsigned char definite;
+ unsigned char first_match; /* set to 1 if first match must be returned */
}
zbx_jsonpath_t;
-void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath);
+typedef struct zbx_jsonobj zbx_jsonobj_t;
+
+ZBX_PTR_VECTOR_DECL(jsonobj_ptr, zbx_jsonobj_t *)
+
+typedef union
+{
+ char *string;
+ double number;
+ zbx_hashset_t object;
+ zbx_vector_jsonobj_ptr_t array;
+}
+zbx_jsonobj_data_t;
+
+typedef struct
+{
+ char *path; /* the path that was indexed - for example @.a.b.c */
+ zbx_hashset_t objects;
+}
+zbx_jsonobj_index_t;
+
+struct zbx_jsonobj
+{
+ zbx_json_type_t type;
+ zbx_jsonobj_data_t data;
+ zbx_jsonobj_index_t *index;
+};
+
+typedef struct
+{
+ char *name;
+ zbx_jsonobj_t value;
+}
+zbx_jsonobj_el_t;
+
int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath);
int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output);
+void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath);
+
+int zbx_jsonobj_open(const char *data, zbx_jsonobj_t *obj);
+void zbx_jsonobj_clear(zbx_jsonobj_t *obj);
+int zbx_jsonobj_query(zbx_jsonobj_t *obj, const char *path, char **output);
+int zbx_jsonobj_to_string(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj);
#endif /* ZABBIX_ZJSON_H */
diff --git a/src/go/pkg/zbxlib/globals_windows.go b/src/go/pkg/zbxlib/globals_windows.go
index 12873d2aa62..f01106f489f 100644
--- a/src/go/pkg/zbxlib/globals_windows.go
+++ b/src/go/pkg/zbxlib/globals_windows.go
@@ -49,6 +49,7 @@ package zbxlib
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/md5.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sysinfo.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/vector.o
+#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/hashset.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/zbxregexp.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/algodefs.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/persistent_state.o
@@ -56,6 +57,7 @@ package zbxlib
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/json.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/json_parser.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/jsonpath.o
+#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/jsonobj.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sha256crypt.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/variant.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sysinfo_system.o
diff --git a/src/libs/zbxjson/Makefile.am b/src/libs/zbxjson/Makefile.am
index ad27f80c98e..f7981730a30 100644
--- a/src/libs/zbxjson/Makefile.am
+++ b/src/libs/zbxjson/Makefile.am
@@ -8,4 +8,6 @@ libzbxjson_a_SOURCES = \
json_parser.c \
json_parser.h \
jsonpath.c \
- jsonpath.h
+ jsonpath.h \
+ jsonobj.c \
+ jsonobj.h
diff --git a/src/libs/zbxjson/json.c b/src/libs/zbxjson/json.c
index e819f23e892..539c4d834bc 100644
--- a/src/libs/zbxjson/json.c
+++ b/src/libs/zbxjson/json.c
@@ -841,7 +841,7 @@ static unsigned int zbx_json_decode_character(const char **p, unsigned char *byt
* string copying failed. *
* *
******************************************************************************/
-static const char *zbx_json_copy_string(const char *p, char *out, size_t size)
+const char *json_copy_string(const char *p, char *out, size_t size)
{
char *start = out;
@@ -920,7 +920,7 @@ const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_j
/* only primitive values are decoded */
return NULL;
default:
- if (0 == (len = json_parse_value(p, NULL)))
+ if (0 == (len = json_parse_value(p, NULL, NULL)))
return NULL;
}
@@ -930,7 +930,7 @@ const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_j
switch (type_local)
{
case ZBX_JSON_TYPE_STRING:
- return zbx_json_copy_string(p, string, size);
+ return json_copy_string(p, string, size);
case ZBX_JSON_TYPE_NULL:
if (0 == size)
return NULL;
@@ -954,7 +954,7 @@ const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *strin
/* only primitive values are decoded */
return NULL;
default:
- if (0 == (len = json_parse_value(p, NULL)))
+ if (0 == (len = json_parse_value(p, NULL, NULL)))
return NULL;
}
@@ -970,7 +970,7 @@ const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *strin
switch (type_local)
{
case ZBX_JSON_TYPE_STRING:
- return zbx_json_copy_string(p, *string, *string_alloc);
+ return json_copy_string(p, *string, *string_alloc);
case ZBX_JSON_TYPE_NULL:
**string = '\0';
return p + len;
@@ -987,7 +987,7 @@ const char *zbx_json_pair_next(const struct zbx_json_parse *jp, const char *p, c
if (ZBX_JSON_TYPE_STRING != __zbx_json_type(p))
return NULL;
- if (NULL == (p = zbx_json_copy_string(p, name, len)))
+ if (NULL == (p = json_copy_string(p, name, len)))
return NULL;
SKIP_WHITESPACE(p);
@@ -1219,7 +1219,7 @@ int zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct
object.start = p;
if (NULL == (object.end = __zbx_json_rbracket(p)))
- object.end = p + json_parse_value(p, NULL) - 1;
+ object.end = p + json_parse_value(p, NULL, NULL) - 1;
}
*out = object;
diff --git a/src/libs/zbxjson/json.h b/src/libs/zbxjson/json.h
index e0c02e174ab..27006bc5f01 100644
--- a/src/libs/zbxjson/json.h
+++ b/src/libs/zbxjson/json.h
@@ -32,4 +32,6 @@
void zbx_set_json_strerror(const char *fmt, ...) __zbx_attr_format_printf(1, 2);
+const char *json_copy_string(const char *p, char *out, size_t size);
+
#endif
diff --git a/src/libs/zbxjson/json_parser.c b/src/libs/zbxjson/json_parser.c
index 403a3ca2753..0ea71203ec8 100644
--- a/src/libs/zbxjson/json_parser.c
+++ b/src/libs/zbxjson/json_parser.c
@@ -21,27 +21,31 @@
#include "zbxcommon.h"
#include "json.h"
-
-static zbx_int64_t json_parse_object(const char *start, char **error);
+#include "jsonobj.h"
/******************************************************************************
* *
* Purpose: Prepares JSON parsing error message *
* *
- * Parameters: message - [IN] the error message *
- * json_buffer - [IN] the failing data fragment *
- * error - [OUT] the parsing error message (can be NULL) *
+ * Parameters: message - [IN] the error message *
+ * ptr - [IN] the failing data fragment *
+ * error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: 0 - the json_error() function always returns 0 value *
* so it can be used to return from failed parses *
* *
******************************************************************************/
-static zbx_int64_t json_error(const char *message, const char *json_buffer, char **error)
+zbx_int64_t json_error(const char *message, const char *ptr, char **error)
{
if (NULL != error)
{
- if (NULL != json_buffer)
- *error = zbx_dsprintf(*error, "%s at: '%s'", message, json_buffer);
+ if (NULL != ptr)
+ {
+ if (128 < strlen(ptr))
+ *error = zbx_dsprintf(*error, "%s at: '%128s...'", message, ptr);
+ else
+ *error = zbx_dsprintf(*error, "%s at: '%s'", message, ptr);
+ }
else
*error = zbx_strdup(*error, message);
}
@@ -54,6 +58,7 @@ static zbx_int64_t json_error(const char *message, const char *json_buffer, char
* Purpose: Parses JSON string value or object name *
* *
* Parameters: start - [IN] the JSON data without leading whitespace *
+ * str - [OUT] the parsed unquoted string (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -61,7 +66,7 @@ static zbx_int64_t json_error(const char *message, const char *json_buffer, char
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_string(const char *start, char **error)
+static zbx_int64_t json_parse_string(const char *start, char **str, char **error)
{
const char *ptr = start;
@@ -119,6 +124,12 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
ptr++;
}
+ if (NULL != str)
+ {
+ *str = (char *)zbx_malloc(NULL, (size_t)(ptr - start));
+ json_copy_string(start, *str, (size_t)(ptr - start));
+ }
+
return ptr - start + 1;
}
@@ -127,6 +138,7 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
* Purpose: Parses JSON array value *
* *
* Parameters: start - [IN] the JSON data without leading whitespace *
+ * obj - [IN/OUT] the JSON object (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -134,11 +146,14 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_array(const char *start, char **error)
+zbx_int64_t json_parse_array(const char *start, zbx_jsonobj_t *obj, char **error)
{
const char *ptr = start;
zbx_int64_t len;
+ if (NULL != obj)
+ jsonobj_init(obj, ZBX_JSON_TYPE_ARRAY);
+
ptr++;
SKIP_WHITESPACE(ptr);
@@ -146,9 +161,29 @@ static zbx_int64_t json_parse_array(const char *start, char **error)
{
while (1)
{
+ zbx_jsonobj_t *value;
+
+ if (NULL != obj)
+ {
+ value = zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+ jsonobj_init(value, ZBX_JSON_TYPE_UNKNOWN);
+ }
+ else
+ value = NULL;
+
/* json_parse_value strips leading whitespace, so we don't have to do it here */
- if (0 == (len = json_parse_value(ptr, error)))
+ if (0 == (len = json_parse_value(ptr, value, error)))
+ {
+ if (NULL != obj)
+ {
+ zbx_jsonobj_clear(value);
+ zbx_free(value);
+ }
return 0;
+ }
+
+ if (NULL != obj)
+ zbx_vector_jsonobj_ptr_append(&obj->data.array, value);
ptr += len;
SKIP_WHITESPACE(ptr);
@@ -171,15 +206,16 @@ static zbx_int64_t json_parse_array(const char *start, char **error)
* *
* Purpose: Parses JSON number value *
* *
- * Parameters: start - [IN] the JSON data without leading whitespace *
- * error - [OUT] the parsing error message (can be NULL) *
+ * Parameters: start - [IN] the JSON data without leading whitespace *
+ * number - [OUT] the parsed number (can be NULL) *
+ * error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
* error parameter (if not NULL) contains allocated error *
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_number(const char *start, char **error)
+static zbx_int64_t json_parse_number(const char *start, double *number, char **error)
{
const char *ptr = start;
char first_digit;
@@ -235,6 +271,9 @@ static zbx_int64_t json_parse_number(const char *start, char **error)
}
}
+ if (NULL != number)
+ *number = atof(start);
+
return ptr - start;
}
@@ -281,10 +320,12 @@ static zbx_int64_t json_parse_literal(const char *start, const char *text, char
* message. *
* *
******************************************************************************/
-zbx_int64_t json_parse_value(const char *start, char **error)
+zbx_int64_t json_parse_value(const char *start, zbx_jsonobj_t *obj, char **error)
{
const char *ptr = start;
zbx_int64_t len;
+ char *str = NULL;
+ double number;
SKIP_WHITESPACE(ptr);
@@ -293,28 +334,40 @@ zbx_int64_t json_parse_value(const char *start, char **error)
case '\0':
return json_error("unexpected end of object value", NULL, error);
case '"':
- if (0 == (len = json_parse_string(ptr, error)))
+ if (0 == (len = json_parse_string(ptr, (NULL != obj ? &str : NULL), error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_string(obj, str);
break;
case '{':
- if (0 == (len = json_parse_object(ptr, error)))
+ if (0 == (len = json_parse_object(ptr, obj, error)))
return 0;
break;
case '[':
- if (0 == (len = json_parse_array(ptr, error)))
+ if (0 == (len = json_parse_array(ptr, obj, error)))
return 0;
break;
case 't':
if (0 == (len = json_parse_literal(ptr, "true", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_true(obj);
break;
case 'f':
if (0 == (len = json_parse_literal(ptr, "false", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_false(obj);
break;
case 'n':
if (0 == (len = json_parse_literal(ptr, "null", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_null(obj);
break;
case '0':
case '1':
@@ -327,8 +380,12 @@ zbx_int64_t json_parse_value(const char *start, char **error)
case '8':
case '9':
case '-':
- if (0 == (len = json_parse_number(ptr, error)))
+ if (0 == (len = json_parse_number(ptr, (NULL != obj ? &number : NULL), error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_number(obj, number);
+
break;
default:
return json_error("invalid JSON object value starting character", ptr, error);
@@ -342,6 +399,7 @@ zbx_int64_t json_parse_value(const char *start, char **error)
* Purpose: Parses JSON object *
* *
* Parameters: start - [IN] the JSON data *
+ * obj - [IN/OUT] the JSON object (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -349,10 +407,13 @@ zbx_int64_t json_parse_value(const char *start, char **error)
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_object(const char *start, char **error)
+zbx_int64_t json_parse_object(const char *start, zbx_jsonobj_t *obj, char **error)
{
- const char *ptr = start;
- zbx_int64_t len;
+ const char *ptr = start;
+ zbx_int64_t len;
+
+ if (NULL != obj)
+ jsonobj_init(obj, ZBX_JSON_TYPE_OBJECT);
/* parse object name */
SKIP_WHITESPACE(ptr);
@@ -364,11 +425,15 @@ static zbx_int64_t json_parse_object(const char *start, char **error)
{
while (1)
{
+ zbx_jsonobj_el_t el;
+
if ('"' != *ptr)
return json_error("invalid object name", ptr, error);
+ jsonobj_el_init(&el);
+
/* cannot parse object name, failing */
- if (0 == (len = json_parse_string(ptr, error)))
+ if (0 == (len = json_parse_string(ptr, (NULL != obj ? &el.name : NULL), error)))
return 0;
ptr += len;
@@ -377,11 +442,21 @@ static zbx_int64_t json_parse_object(const char *start, char **error)
SKIP_WHITESPACE(ptr);
if (':' != *ptr)
+ {
+ jsonobj_el_clear(&el);
return json_error("invalid object name/value separator", ptr, error);
+ }
+
ptr++;
- if (0 == (len = json_parse_value(ptr, error)))
+ if (0 == (len = json_parse_value(ptr, (NULL != obj ? &el.value : NULL), error)))
+ {
+ jsonobj_el_clear(&el);
return 0;
+ }
+
+ if (NULL != obj)
+ zbx_hashset_insert(&obj->data.object, &el, sizeof(el));
ptr += len;
@@ -426,11 +501,11 @@ zbx_int64_t zbx_json_validate(const char *start, char **error)
switch (*start)
{
case '{':
- if (0 == (len = json_parse_object(start, error)))
+ if (0 == (len = json_parse_object(start, NULL, error)))
return 0;
break;
case '[':
- if (0 == (len = json_parse_array(start, error)))
+ if (0 == (len = json_parse_array(start, NULL, error)))
return 0;
break;
default:
diff --git a/src/libs/zbxjson/json_parser.h b/src/libs/zbxjson/json_parser.h
index f9fb3bb8cf5..cd54939eb7d 100644
--- a/src/libs/zbxjson/json_parser.h
+++ b/src/libs/zbxjson/json_parser.h
@@ -21,9 +21,15 @@
#define ZABBIX_JSON_PARSER_H
#include "zbxtypes.h"
+#include "jsonobj.h"
zbx_int64_t zbx_json_validate(const char *start, char **error);
-zbx_int64_t json_parse_value(const char *start, char **error);
+zbx_int64_t json_parse_value(const char *start, zbx_jsonobj_t *obj, char **error);
+
+zbx_int64_t json_error(const char *message, const char *ptr, char **error);
+
+zbx_int64_t json_parse_object(const char *start, zbx_jsonobj_t *obj, char **error);
+zbx_int64_t json_parse_array(const char *start, zbx_jsonobj_t *obj, char **error);
#endif
diff --git a/src/libs/zbxjson/jsonobj.c b/src/libs/zbxjson/jsonobj.c
new file mode 100644
index 00000000000..2a7c365284c
--- /dev/null
+++ b/src/libs/zbxjson/jsonobj.c
@@ -0,0 +1,366 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "jsonobj.h"
+
+#include "json_parser.h"
+#include "json.h"
+#include "zbxstr.h"
+
+ZBX_PTR_VECTOR_IMPL(jsonobj_ptr, zbx_jsonobj_t *)
+ZBX_VECTOR_IMPL(jsonobj_ref, zbx_jsonobj_ref_t)
+
+/* jsonobject index hashset support */
+
+static zbx_hash_t jsonobj_index_el_hash(const void *v)
+{
+ const zbx_jsonobj_index_el_t *el = (const zbx_jsonobj_index_el_t *)v;
+
+ return ZBX_DEFAULT_STRING_HASH_FUNC(el->value);
+}
+
+static int jsonobj_index_el_compare(const void *v1, const void *v2)
+{
+ const zbx_jsonobj_index_el_t *el1 = (const zbx_jsonobj_index_el_t *)v1;
+ const zbx_jsonobj_index_el_t *el2 = (const zbx_jsonobj_index_el_t *)v2;
+
+ return strcmp(el1->value, el2->value);
+}
+
+/* jsonobject values hashset support */
+
+static zbx_hash_t jsonobj_el_hash(const void *v)
+{
+ const zbx_jsonobj_el_t *el = (const zbx_jsonobj_el_t *)v;
+
+ return ZBX_DEFAULT_STRING_HASH_FUNC(el->name);
+}
+
+static int jsonobj_el_compare(const void *v1, const void *v2)
+{
+ const zbx_jsonobj_el_t *el1 = (const zbx_jsonobj_el_t *)v1;
+ const zbx_jsonobj_el_t *el2 = (const zbx_jsonobj_el_t *)v2;
+
+ return strcmp(el1->name, el2->name);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object structure *
+ * *
+ * Parameters: obj - [IN/OUT] the json object to initialize *
+ * type - [IN] the json object type *
+ * *
+ ******************************************************************************/
+void jsonobj_init(zbx_jsonobj_t *obj, zbx_json_type_t type)
+{
+ obj->type = type;
+
+ switch (type)
+ {
+ case ZBX_JSON_TYPE_ARRAY:
+ zbx_vector_jsonobj_ptr_create(&obj->data.array);
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ zbx_hashset_create(&obj->data.object, 0, jsonobj_el_hash, jsonobj_el_compare);
+ break;
+ default:
+ memset(&obj->data, 0, sizeof(obj->data));
+ break;
+ }
+
+ obj->index = NULL;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object index element *
+ * *
+ * Parameters: v - [IN] the json index element *
+ * *
+ ******************************************************************************/
+static void jsonobj_index_el_clear(void *v)
+{
+ zbx_jsonobj_index_el_t *el = (zbx_jsonobj_index_el_t *)v;
+ int i;
+
+ zbx_free(el->value);
+ for (i = 0; i < el->objects.values_num; i++)
+ {
+ zbx_free(el->objects.values[i].name);
+
+ if (0 != el->objects.values[i].external)
+ {
+ zbx_jsonobj_clear(el->objects.values[i].value);
+ zbx_free(el->objects.values[i].value);
+ }
+ }
+
+ zbx_vector_jsonobj_ref_destroy(&el->objects);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object index *
+ * *
+ * Parameters: obj - [IN/OUT] the json object *
+ * path - [IN] the indexed relative path *
+ * *
+ ******************************************************************************/
+void jsonobj_init_index(zbx_jsonobj_t *obj, const char *path)
+{
+ obj->index = (zbx_jsonobj_index_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_index_t));
+ obj->index->path = zbx_strdup(NULL, path);
+ zbx_hashset_create_ext(&obj->index->objects, 0, jsonobj_index_el_hash, jsonobj_index_el_compare,
+ jsonobj_index_el_clear, ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC,
+ ZBX_DEFAULT_MEM_FREE_FUNC);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set string value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_string(zbx_jsonobj_t *obj, char *str)
+{
+ obj->type = ZBX_JSON_TYPE_STRING;
+ obj->data.string = str;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set numeric value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_number(zbx_jsonobj_t *obj, double number)
+{
+ obj->type = ZBX_JSON_TYPE_NUMBER;
+ obj->data.number = number;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set true value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_true(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_TRUE;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set false value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_false(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_FALSE;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set null value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_null(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_NULL;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object element *
+ * *
+ ******************************************************************************/
+void jsonobj_el_init(zbx_jsonobj_el_t *el)
+{
+ el->name = NULL;
+ jsonobj_init(&el->value, ZBX_JSON_TYPE_UNKNOWN);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object element *
+ * *
+ ******************************************************************************/
+void jsonobj_el_clear(zbx_jsonobj_el_t *el)
+{
+ zbx_free(el->name);
+ zbx_jsonobj_clear(&el->value);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free json object *
+ * *
+ ******************************************************************************/
+static void jsonobj_free(zbx_jsonobj_t *obj)
+{
+ zbx_jsonobj_clear(obj);
+ zbx_free(obj);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object *
+ * *
+ ******************************************************************************/
+void zbx_jsonobj_clear(zbx_jsonobj_t *obj)
+{
+ zbx_jsonobj_el_t *el;
+ zbx_hashset_iter_t iter;
+
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_STRING:
+ zbx_free(obj->data.string);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ zbx_vector_jsonobj_ptr_clear_ext(&obj->data.array, jsonobj_free);
+ zbx_vector_jsonobj_ptr_destroy(&obj->data.array);
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ zbx_free(el->name);
+ zbx_jsonobj_clear(&el->value);
+ }
+ zbx_hashset_destroy(&obj->data.object);
+ break;
+ default:
+ break;
+ }
+
+ if (NULL != obj->index)
+ {
+ zbx_free(obj->index->path);
+ zbx_hashset_destroy(&obj->index->objects);
+ zbx_free(obj->index);
+ }
+}
+
+/******************************************************************************
+ * *
+ * Purpose: convert json object to text format *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_to_string(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj)
+{
+ char *tmp, buf[32], delim;
+ int i;
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_TRUE:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "true");
+ break;
+ case ZBX_JSON_TYPE_FALSE:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "false");
+ break;
+ case ZBX_JSON_TYPE_NULL:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "null");
+ break;
+ case ZBX_JSON_TYPE_STRING:
+ tmp = zbx_strdup(NULL, obj->data.string);
+ zbx_json_escape(&tmp);
+ zbx_snprintf_alloc(str, str_alloc, str_offset, "\"%s\"", tmp);
+ zbx_free(tmp);
+ break;
+ case ZBX_JSON_TYPE_NUMBER:
+ zbx_print_double(buf, sizeof(buf), obj->data.number);
+ zbx_strcpy_alloc(str, str_alloc, str_offset, buf);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ delim = '[';
+ for (i = 0; i < obj->data.array.values_num; i++)
+ {
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, delim);
+ delim = ',';
+ zbx_jsonobj_to_string(str, str_alloc, str_offset, obj->data.array.values[i]);
+ }
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, ']');
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ delim = '{';
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, delim);
+ delim = ',';
+
+ tmp = zbx_strdup(NULL, el->name);
+ zbx_json_escape(&tmp);
+ zbx_snprintf_alloc(str, str_alloc, str_offset, "\"%s\"", tmp);
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, ':');
+ zbx_free(tmp);
+
+ zbx_jsonobj_to_string(str, str_alloc, str_offset, &el->value);
+ }
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, '}');
+ break;
+ default:
+ zbx_set_json_strerror("unknown json object with type: %u", obj->type);
+ return FAIL;
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: parses json formatted data into json object structure *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_open(const char *data, zbx_jsonobj_t *obj)
+{
+ int ret = FAIL;
+ char *error = NULL;
+
+ switch (*data)
+ {
+ case '{':
+ if (0 == json_parse_object(data, obj, &error))
+ goto out;
+ break;
+ case '[':
+ if (0 == json_parse_array(data, obj, &error))
+ goto out;
+ break;
+ default:
+ /* not json data, failing */
+ jsonobj_init(obj, ZBX_JSON_TYPE_UNKNOWN);
+ (void)json_error("invalid object format, expected opening character '{' or '['", data, &error);
+ goto out;
+ }
+
+ ret = SUCCEED;
+out:
+ if (FAIL == ret)
+ {
+ zbx_jsonobj_clear(obj);
+ zbx_set_json_strerror("%s", error);
+ zbx_free(error);
+ }
+
+ return ret;
+}
diff --git a/src/libs/zbxjson/jsonobj.h b/src/libs/zbxjson/jsonobj.h
new file mode 100644
index 00000000000..dfd12df6b9b
--- /dev/null
+++ b/src/libs/zbxjson/jsonobj.h
@@ -0,0 +1,56 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#ifndef ZABBIX_JSONOBJ_H
+#define ZABBIX_JSONOBJ_H
+
+#include "zbxjson.h"
+
+typedef struct
+{
+ char *name;
+ zbx_jsonobj_t *value;
+ unsigned char external; /* 1 - the reference is to an external object. */
+ /* 0 - the reference is to a local object which must be freed */
+ /* when reference is destroyed */
+}
+zbx_jsonobj_ref_t;
+
+ZBX_VECTOR_DECL(jsonobj_ref, zbx_jsonobj_ref_t)
+
+typedef struct
+{
+ char *value; /* the value found at indexed path */
+ zbx_vector_jsonobj_ref_t objects; /* the objects matching value at indexed path */
+}
+zbx_jsonobj_index_el_t;
+
+void jsonobj_init(zbx_jsonobj_t *obj, zbx_json_type_t type);
+
+void jsonobj_el_init(zbx_jsonobj_el_t *el);
+void jsonobj_init_index(zbx_jsonobj_t *obj, const char *path);
+void jsonobj_el_clear(zbx_jsonobj_el_t *el);
+
+void jsonobj_set_string(zbx_jsonobj_t *obj, char *str);
+void jsonobj_set_number(zbx_jsonobj_t *obj, double number);
+void jsonobj_set_true(zbx_jsonobj_t *obj);
+void jsonobj_set_false(zbx_jsonobj_t *obj);
+void jsonobj_set_null(zbx_jsonobj_t *obj);
+
+#endif
diff --git a/src/libs/zbxjson/jsonpath.c b/src/libs/zbxjson/jsonpath.c
index b57aff6f8d5..eec2ffc6935 100644
--- a/src/libs/zbxjson/jsonpath.c
+++ b/src/libs/zbxjson/jsonpath.c
@@ -18,7 +18,6 @@
**/
#include "jsonpath.h"
-#include "zbxjson.h"
#include "zbxregexp.h"
#include "zbxvariant.h"
@@ -26,21 +25,17 @@
#include "zbxexpr.h"
#include "json.h"
#include "json_parser.h"
+#include "jsonobj.h"
typedef struct
{
- char *name;
- const char *value;
+ zbx_jsonobj_t *root; /* the root object */
+ zbx_jsonpath_t *path;
+ unsigned char found; /* set to 1 when one object was matched and */
+ /* no more matches are required */
+ zbx_vector_jsonobj_ref_t objects; /* the matched objects */
}
-zbx_json_element_t;
-
-ZBX_VECTOR_DECL(json, zbx_json_element_t)
-ZBX_VECTOR_IMPL(json, zbx_json_element_t)
-
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects);
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects);
+zbx_jsonpath_context_t;
typedef struct
{
@@ -49,6 +44,10 @@ typedef struct
}
zbx_jsonpath_token_def_t;
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth);
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth);
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj);
+
/* define token groups and precedence */
static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{0, 0},
@@ -74,6 +73,7 @@ static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 7} /* ZBX_JSONPATH_TOKEN_OP_REGEXP */
};
+
static int jsonpath_token_precedence(int type)
{
return jsonpath_tokens[type].precedence;
@@ -84,31 +84,118 @@ static int jsonpath_token_group(int type)
return jsonpath_tokens[type].group;
}
-/* json element vector support */
-static void zbx_vector_json_add_element(zbx_vector_json_t *elements, const char *name, const char *value)
+/******************************************************************************
+ * *
+ * Purpose: add external json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * value - [IN] the json object *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_object(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ zbx_jsonobj_t *value)
{
- zbx_json_element_t el;
+ zbx_jsonobj_ref_t ref;
- el.name = zbx_strdup(NULL, name);
- el.value = value;
- zbx_vector_json_append(elements, el);
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 1;
+
+ ref.value = value;
+ zbx_vector_jsonobj_ref_append(refs, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: add internal json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * str - [IN] the string value of the object *
+ * *
+ * Comments: This function will create json object and add internal reference,*
+ * meaning the object will be destroyed together with its reference.*
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_string(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ const char *str)
+{
+ zbx_jsonobj_ref_t ref;
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 0;
+
+ ref.value = (zbx_jsonobj_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+ jsonobj_init(ref.value, ZBX_JSON_TYPE_STRING);
+ jsonobj_set_string(ref.value, zbx_strdup(NULL, str));
+
+ zbx_vector_jsonobj_ref_append(refs, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: add a copy of json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * ref - [IN] the json object reference *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add(zbx_vector_jsonobj_ref_t *refs, zbx_jsonobj_ref_t *ref)
+{
+ if (0 != ref->external)
+ zbx_vector_jsonobj_ref_add_object(refs, ref->name, ref->value);
+ else
+ zbx_vector_jsonobj_ref_add_string(refs, ref->name, ref->value->data.string);
}
-static void zbx_vector_json_copy(zbx_vector_json_t *dst, const zbx_vector_json_t *src)
+/******************************************************************************
+ * *
+ * Purpose: copy json object references from one vector to other *
+ * *
+ * Parameters: dst - [IN/OUT] the destination json object reference vector *
+ * src - [IN] the source json object reference vector *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_copy(zbx_vector_jsonobj_ref_t *dst, const zbx_vector_jsonobj_ref_t *src)
{
int i;
for (i = 0; i < src->values_num; i++)
- zbx_vector_json_add_element(dst, src->values[i].name, src->values[i].value);
+ {
+ if (0 != src->values[i].external)
+ zbx_vector_jsonobj_ref_add_object(dst, src->values[i].name, src->values[i].value);
+ else
+ zbx_vector_jsonobj_ref_add_string(dst, src->values[i].name, src->values[i].value->data.string);
+ }
}
-static void zbx_vector_json_clear_ext(zbx_vector_json_t *elements)
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object reference *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_clear_ext(zbx_vector_jsonobj_ref_t *refs)
{
int i;
- for (i = 0; i < elements->values_num; i++)
- zbx_free(elements->values[i].name);
- zbx_vector_json_clear(elements);
+ for (i = 0; i < refs->values_num; i++)
+ {
+ zbx_jsonobj_ref_t *ref = &refs->values[i];
+
+ zbx_free(ref->name);
+ if (0 == ref->external)
+ {
+ zbx_jsonobj_clear(ref->value);
+ zbx_free(ref->value);
+ }
+ }
+ zbx_vector_jsonobj_ref_clear(refs);
}
/******************************************************************************
@@ -215,16 +302,116 @@ static void jsonpath_list_free(zbx_jsonpath_list_node_t *list)
/******************************************************************************
* *
+ * Purpose: append array index to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_index(zbx_jsonpath_list_node_t *head, int index,
+ int check_duplicate)
+{
+ zbx_jsonpath_list_node_t *node;
+
+ if (0 != check_duplicate)
+ {
+ for (node = head; NULL != node; node = node->next)
+ {
+ int query_index;
+
+ memcpy(&query_index, node->data, sizeof(query_index));
+ if (query_index == index)
+ return head;
+ }
+ }
+
+ node = jsonpath_list_create_node(sizeof(int));
+ node->next = head;
+ memcpy(node->data, &index, sizeof(int));
+
+ return node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: append name to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_name(zbx_jsonpath_list_node_t *head, const char *name, size_t len)
+{
+ zbx_jsonpath_list_node_t *node, *new_node;
+
+ new_node = jsonpath_list_create_node(len + 1);
+ jsonpath_unquote(new_node->data, name, len + 1);
+
+ for (node = head; NULL != node; node = node->next)
+ {
+ if (0 == strcmp((char *)new_node->data, (char *)node->data))
+ {
+ zbx_free(new_node);
+ return head;
+ }
+ }
+
+ new_node->next = head;
+
+ return new_node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: create jsonpath structure and compile json path *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_t *jsonpath_create_token_jsonpath(const char *text, size_t len)
+{
+ zbx_jsonpath_t *path;
+ char *tmp_text;
+
+ tmp_text = jsonpath_strndup(text, len);
+
+ if ('@' == *tmp_text)
+ *tmp_text = '$';
+
+ path = (zbx_jsonpath_t *)zbx_malloc(NULL, sizeof(zbx_jsonpath_t));
+
+ if (FAIL == zbx_jsonpath_compile(tmp_text, path))
+ {
+ zbx_free(path);
+ goto out;
+ }
+
+ if (1 != path->definite)
+ {
+ zbx_set_json_strerror("only simple path are supported in jsonpath expression: \"%s\"", text);
+ zbx_jsonpath_clear(path);
+ zbx_free(path);
+ goto out;
+ }
+
+ if (ZBX_JSONPATH_SEGMENT_FUNCTION == path->segments[path->segments_num - 1].type)
+ {
+ zbx_set_json_strerror("functions are not supported in jsonpath expression: \"%s\"", text);
+ zbx_jsonpath_clear(path);
+ zbx_free(path);
+ }
+out:
+ zbx_free(tmp_text);
+
+ return path;
+}
+
+/******************************************************************************
+ * *
* Purpose: create jsonpath expression token *
* *
* Parameters: type - [IN] the token type *
* expression - [IN] the expression *
* loc - [IN] the token location in the expression *
* *
- * Return value: The created token (must be freed by the caller). *
+ * Return value: The created token (must be freed by the caller) or *
+ * NULL in the case of error. *
* *
******************************************************************************/
-static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *expression, const zbx_strloc_t *loc)
+static zbx_jsonpath_token_t *jsonpath_create_token(unsigned char type, const char *expression,
+ const zbx_strloc_t *loc)
{
zbx_jsonpath_token_t *token;
@@ -234,23 +421,46 @@ static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *express
switch (token->type)
{
case ZBX_JSONPATH_TOKEN_CONST_STR:
- token->data = jsonpath_unquote_dyn(expression + loc->l, loc->r - loc->l + 1);
+ token->text = jsonpath_unquote_dyn(expression + loc->l, loc->r - loc->l + 1);
+ token->path = NULL;
break;
case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ if (NULL == (token->path = jsonpath_create_token_jsonpath(expression + loc->l,
+ loc->r - loc->l + 1)))
+ {
+ zbx_free(token);
+ }
+ else
+ token->text = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ break;
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- token->data = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ token->text = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ token->path = NULL;
break;
default:
- token->data = NULL;
+ token->text = NULL;
+ token->path = NULL;
}
return token;
}
+/******************************************************************************
+ * *
+ * Purpose: free jsonpath expression token *
+ * *
+ ******************************************************************************/
static void jsonpath_token_free(zbx_jsonpath_token_t *token)
{
- zbx_free(token->data);
+ zbx_free(token->text);
+
+ if (NULL != token->path)
+ {
+ zbx_jsonpath_clear(token->path);
+ zbx_free(token->path);
+ }
+
zbx_free(token);
}
@@ -274,16 +484,21 @@ static void jsonpath_reserve(zbx_jsonpath_t *jsonpath, int num)
jsonpath->segments_alloc *= 2;
jsonpath->segments = (zbx_jsonpath_segment_t *)zbx_realloc(jsonpath->segments,
- sizeof(zbx_jsonpath_segment_t) * jsonpath->segments_alloc);
+ sizeof(zbx_jsonpath_segment_t) * (size_t)jsonpath->segments_alloc);
/* Initialize the memory allocated for new segments, as parser can set */
/* detached flag for the next segment, so the memory cannot be initialized */
/* when creating a segment. */
memset(jsonpath->segments + old_alloc, 0,
- (jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
+ (size_t)(jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
}
}
+/******************************************************************************
+ * *
+ * Purpose: free resource allocated by jsonpath segment *
+ * *
+ ******************************************************************************/
static void jsonpath_segment_clear(zbx_jsonpath_segment_t *segment)
{
switch (segment->type)
@@ -391,7 +606,7 @@ static int jsonpath_next(const char **pnext)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_substring(const char *start, int *len)
+static int jsonpath_parse_substring(const char *start, size_t *len)
{
const char *ptr;
char quotes;
@@ -400,7 +615,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
{
if (*ptr == quotes)
{
- *len = ptr - start + 1;
+ *len = (size_t)(ptr - start + 1);
return SUCCEED;
}
@@ -429,7 +644,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
* jsonpath filter expressions. *
* *
******************************************************************************/
-static int jsonpath_parse_path(const char *start, int *len)
+static int jsonpath_parse_path(const char *start, size_t *len)
{
const char *ptr = start + 1;
@@ -439,7 +654,7 @@ static int jsonpath_parse_path(const char *start, int *len)
return FAIL;
}
- *len = ptr - start;
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -454,7 +669,7 @@ static int jsonpath_parse_path(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_number(const char *start, int *len)
+static int jsonpath_parse_number(const char *start, size_t *len)
{
const char *ptr = start;
char *end;
@@ -474,7 +689,7 @@ static int jsonpath_parse_number(const char *start, int *len)
if (ptr != end || HUGE_VAL == tmp || -HUGE_VAL == tmp || EDOM == errno)
return FAIL;
- *len = (int)(ptr - start);
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -494,14 +709,14 @@ static int jsonpath_parse_number(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_expression_next_token(const char *expression, int pos, int prev_group,
+static int jsonpath_expression_next_token(const char *expression, size_t pos, int prev_group,
zbx_jsonpath_token_type_t *type, zbx_strloc_t *loc)
{
- int len;
+ size_t len;
const char *ptr = expression + pos;
SKIP_WHITESPACE(ptr);
- loc->l = ptr - expression;
+ loc->l = (size_t)(ptr - expression);
switch (*ptr)
{
@@ -633,6 +848,139 @@ out:
return zbx_jsonpath_error(ptr);
}
+/* value types on index stack */
+typedef enum
+{
+ ZBX_JSONPATH_CONST = 1, /* constant value - string or number */
+ ZBX_JSONPATH_VALUE, /* result of an operation after which cannot be used in index */
+ ZBX_JSONPATH_PATH, /* relative jsonpath - @.a.b.c */
+ ZBX_JSONPATH_PATH_OP /* result of an operation with jsonpath which still can be used in index */
+}
+zbx_jsonpath_index_value_type_t;
+
+typedef struct
+{
+ zbx_jsonpath_index_value_type_t type;
+ zbx_jsonpath_token_t *index_token;
+ zbx_jsonpath_token_t *value_token;
+}
+zbx_jsonpath_index_value_t;
+
+ZBX_VECTOR_DECL(jpi_value, zbx_jsonpath_index_value_t)
+ZBX_VECTOR_IMPL(jpi_value, zbx_jsonpath_index_value_t)
+
+/******************************************************************************
+ * *
+ * Purpose: analyze expression and set indexing fields if possible *
+ * *
+ * Comments: Expression can be indexed if it contains relative json path *
+ * comparison with constant that is used in and operations. *
+ * This is tested by doing a pseudo evaluation by operand types *
+ * and checking the result type. *
+ * *
+ * So expressions like ?(@.a.b == 1), ?(@.a == "A" and @.b == "B") *
+ * can be indexed (by @.a.b and by @.a) while expressions like *
+ * ?(@.a == @.b), ?(@.a == "A" or @.b == "B") cannot. *
+ * *
+ ******************************************************************************/
+static void jsonpath_expression_prepare_index(zbx_jsonpath_expression_t *exp)
+{
+ int i;
+ zbx_vector_jpi_value_t stack;
+ zbx_jsonpath_index_value_t *left, *right;
+
+ zbx_vector_jpi_value_create(&stack);
+
+ for (i = 0; i < exp->tokens.values_num; i++)
+ {
+ zbx_jsonpath_token_t *token = (zbx_jsonpath_token_t *)exp->tokens.values[i];
+ zbx_jsonpath_index_value_t jpi = {0};
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_NOT:
+ if (1 > stack.values_num)
+ goto out;
+ stack.values[stack.values_num - 1].type = ZBX_JSONPATH_VALUE;
+ stack.values[stack.values_num - 1].index_token = NULL;
+ stack.values[stack.values_num - 1].value_token = NULL;
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ jpi.index_token = token;
+ jpi.type = ZBX_JSONPATH_PATH;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ jpi.type = ZBX_JSONPATH_VALUE;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ jpi.value_token = token;
+ jpi.type = ZBX_JSONPATH_CONST;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ }
+
+ if (2 > stack.values_num)
+ goto out;
+
+ left = &stack.values[stack.values_num - 2];
+ right = &stack.values[stack.values_num - 1];
+ stack.values_num--;
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_EQ:
+ if ((ZBX_JSONPATH_PATH == left->type || ZBX_JSONPATH_PATH == right->type) &&
+ (ZBX_JSONPATH_CONST == left->type || ZBX_JSONPATH_CONST == right->type))
+ {
+ left->type = ZBX_JSONPATH_PATH_OP;
+
+ if (ZBX_JSONPATH_CONST == right->type)
+ left->value_token = right->value_token;
+ else
+ left->index_token = right->index_token;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ case ZBX_JSONPATH_TOKEN_OP_AND:
+ if (ZBX_JSONPATH_PATH == left->type)
+ left->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH == right->type)
+ right->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH_OP == left->type && ZBX_JSONPATH_PATH_OP == right->type)
+ continue;
+
+ if ((ZBX_JSONPATH_PATH_OP == left->type || ZBX_JSONPATH_PATH_OP == right->type) &&
+ (ZBX_JSONPATH_VALUE == left->type || ZBX_JSONPATH_VALUE == right->type))
+ {
+ if (ZBX_JSONPATH_PATH_OP != left->type)
+ *left = *right;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ default:
+ left->type = ZBX_JSONPATH_VALUE;
+ left->index_token = NULL;
+ left->value_token = NULL;
+ break;
+ }
+ }
+
+ if (1 == stack.values_num && ZBX_JSONPATH_PATH_OP == stack.values[0].type)
+ {
+ exp->index_token = stack.values[0].index_token;
+ exp->value_token = stack.values[0].value_token;
+ }
+out:
+ zbx_vector_jpi_value_destroy(&stack);
+}
+
/******************************************************************************
* *
* Purpose: parse jsonpath filter expression in format *
@@ -659,7 +1007,7 @@ out:
static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jsonpath, const char **next)
{
int nesting = 1, ret = FAIL;
- zbx_jsonpath_token_t *optoken;
+ zbx_jsonpath_token_t *optoken, *token;
zbx_vector_ptr_t output, operators;
zbx_strloc_t loc = {0, 0};
zbx_jsonpath_token_type_t token_type;
@@ -706,7 +1054,10 @@ static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jso
goto out;
}
- zbx_vector_ptr_append(&output, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = jsonpath_token_group(token_type);
continue;
}
@@ -746,14 +1097,20 @@ static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jso
zbx_vector_ptr_append(&output, optoken);
}
- zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = jsonpath_token_group(token_type);
continue;
}
if (ZBX_JSONPATH_TOKEN_PAREN_LEFT == token_type)
{
- zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = ZBX_JSONPATH_TOKEN_GROUP_NONE;
continue;
}
@@ -816,6 +1173,10 @@ out:
zbx_vector_ptr_create(&segment->data.expression.tokens);
zbx_vector_ptr_append_array(&segment->data.expression.tokens, output.values, output.values_num);
+ /* index only json path that has been definite until this point */
+ if (0 != jsonpath->definite)
+ jsonpath_expression_prepare_index(&segment->data.expression);
+
jsonpath->definite = 0;
}
cleanup:
@@ -869,18 +1230,13 @@ static int jsonpath_parse_names(const char *list, zbx_jsonpath_t *jsonpath, cons
}
else if (*start == *end)
{
- zbx_jsonpath_list_node_t *node;
-
if (start + 1 == end)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(end - start + 1);
- jsonpath_unquote(node->data, start, end - start + 1);
- node->next = head;
- head = node;
+ head = jsonpath_list_append_name(head, start, (size_t)(end - start));
parsed_name = 1;
start = NULL;
}
@@ -987,19 +1343,13 @@ static int jsonpath_parse_indexes(const char *list, zbx_jsonpath_t *jsonpath, co
if (NULL != start)
{
- int value;
-
if ('-' == *start && end == start + 1)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(sizeof(int));
- node->next = head;
- head = node;
- value = atoi(start);
- memcpy(node->data, &value, sizeof(int));
+ head = jsonpath_list_append_index(head, atoi(start), type == ZBX_JSONPATH_SEGMENT_MATCH_LIST);
start = NULL;
parsed_index = 1;
}
@@ -1163,7 +1513,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
{
zbx_jsonpath_segment_t *segment;
const char *ptr;
- int len;
+ size_t len;
segment = &jsonpath->segments[jsonpath->segments_num];
jsonpath->segments_num++;
@@ -1179,6 +1529,8 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
for (ptr = start; 0 != isalnum((unsigned char)*ptr) || '_' == *ptr;)
ptr++;
+ len = (size_t)(ptr - start);
+
if ('(' == *ptr)
{
const char *end = ptr + 1;
@@ -1186,18 +1538,31 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
SKIP_WHITESPACE(end);
if (')' == *end)
{
- if (ZBX_CONST_STRLEN("min") == ptr - start && 0 == strncmp(start, "min", ptr - start))
+ if (ZBX_CONST_STRLEN("min") == len && 0 == strncmp(start, "min", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MIN;
- else if (ZBX_CONST_STRLEN("max") == ptr - start && 0 == strncmp(start, "max", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("max") == len && 0 == strncmp(start, "max", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MAX;
- else if (ZBX_CONST_STRLEN("avg") == ptr - start && 0 == strncmp(start, "avg", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("avg") == len && 0 == strncmp(start, "avg", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_AVG;
- else if (ZBX_CONST_STRLEN("length") == ptr - start && 0 == strncmp(start, "length", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("length") == len && 0 == strncmp(start, "length", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_LENGTH;
- else if (ZBX_CONST_STRLEN("first") == ptr - start && 0 == strncmp(start, "first", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("first") == len && 0 == strncmp(start, "first", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_FIRST;
- else if (ZBX_CONST_STRLEN("sum") == ptr - start && 0 == strncmp(start, "sum", ptr - start))
+ jsonpath->first_match = 1;
+ }
+ else if (ZBX_CONST_STRLEN("sum") == len && 0 == strncmp(start, "sum", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_SUM;
+ }
else
return zbx_jsonpath_error(start);
@@ -1207,7 +1572,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
}
}
- if (0 < (len = ptr - start))
+ if (0 < len)
{
segment->type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
segment->data.list.type = ZBX_JSONPATH_LIST_NAME;
@@ -1247,117 +1612,84 @@ static int jsonpath_parse_name_reference(const char *start, zbx_jsonpath_t *json
/******************************************************************************
* *
- * Purpose: convert a pointer to an object/array/value in json data to *
- * json parse structure *
- * *
- * Parameters: pnext - [IN] a pointer to object/array/value data *
- * jp - [OUT] json parse data with start/end set *
- * *
- * Return value: SUCCEED - pointer was converted successfully *
- * FAIL - otherwise *
- * *
- ******************************************************************************/
-static int jsonpath_pointer_to_jp(const char *pnext, struct zbx_json_parse *jp)
-{
- if ('[' == *pnext || '{' == *pnext)
- {
- return zbx_json_brackets_open(pnext, jp);
- }
- else
- {
- jp->start = pnext;
- jp->end = pnext + json_parse_value(pnext, NULL) - 1;
- return SUCCEED;
- }
-}
-
-/******************************************************************************
- * *
* Purpose: perform the rest of jsonpath query on json data *
* *
- * Parameters: jp_root - [IN] the document root *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the data were queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_contents(const struct zbx_json_parse *jp_root, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_contents(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- struct zbx_json_parse jp_child;
+ int ret;
- switch (*pnext)
+ switch (obj->type)
{
- case '{':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_object(jp_root, &jp_child, jsonpath, path_depth, objects);
- case '[':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_array(jp_root, &jp_child, jsonpath, path_depth, objects);
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(ctx, obj, path_depth);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(ctx, obj, path_depth);
+ break;
+ default:
+ ret = SUCCEED;
}
- return SUCCEED;
+
+ return ret;
}
/******************************************************************************
* *
* Purpose: query next segment *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the current json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the segment was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_next_segment(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_next_segment(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
/* check if jsonpath end has been reached, so we have found matching data */
/* (functions are processed afterwards) */
- if (++path_depth == jsonpath->segments_num ||
- ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath->segments[path_depth].type)
+ if (++path_depth == ctx->path->segments_num ||
+ ZBX_JSONPATH_SEGMENT_FUNCTION == ctx->path->segments[path_depth].type)
{
- zbx_vector_json_add_element(objects, name, pnext);
+ if (1 == ctx->path->first_match)
+ ctx->found = 1;
+
+ zbx_vector_jsonobj_ref_add_object(&ctx->objects, name, obj);
return SUCCEED;
}
- /* continue by matching found data against the rest of jsonpath segments */
- return jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+ /* continue by matching found object against the rest of jsonpath segments */
+ return jsonpath_query_contents(ctx, obj, path_depth);
}
/******************************************************************************
* *
- * Purpose: match object value name against jsonpath segment name list *
+ * Purpose: match object contents against jsonpath segment name list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object value with the specified *
- * name *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] parent json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_match_name(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
+ zbx_jsonobj_el_t el_local, *el;
/* object contents can match only name list */
if (ZBX_JSONPATH_LIST_NAME != segment->data.list.type)
@@ -1365,11 +1697,11 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
for (node = segment->data.list.values; NULL != node; node = node->next)
{
- if (0 == strcmp(name, node->data))
+ el_local.name = (char *)node->data;
+ if (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_search(&parent->data.object, &el_local)))
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ if (FAIL == jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth))
return FAIL;
- break;
}
}
@@ -1380,8 +1712,8 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* *
* Purpose: extract value from json data by the specified path *
* *
- * Parameters: jp - [IN] the parent object *
- * path - [IN] the jsonpath (definite) *
+ * Parameters: obj - [IN] the parent object *
+ * path - [IN] the jsonpath *
* value - [OUT] the extracted value *
* *
* Return value: SUCCEED - the value was extracted successfully *
@@ -1389,35 +1721,28 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* extract *
* *
******************************************************************************/
-static int jsonpath_extract_value(const struct zbx_json_parse *jp, const char *path, zbx_variant_t *value)
+static int jsonpath_extract_value(zbx_jsonobj_t *obj, zbx_jsonpath_t *path, zbx_variant_t *value)
{
- struct zbx_json_parse jp_child;
- char *data = NULL, *tmp_path = NULL;
- size_t data_alloc = 0;
- int ret = FAIL;
+ int ret = FAIL;
+ zbx_jsonpath_context_t ctx;
- if ('@' == *path)
- {
- tmp_path = zbx_strdup(NULL, path);
- *tmp_path = '$';
- path = tmp_path;
- }
+ ctx.path = path;
+ ctx.found = 0;
+ ctx.root = obj;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if (FAIL == zbx_json_open_path(jp, path, &jp_child))
- goto out;
-
- if (NULL == zbx_json_decodevalue_dyn(jp_child.start, &data, &data_alloc, NULL))
+ if (SUCCEED == jsonpath_query_contents(&ctx, obj, 0) && 0 != ctx.objects.values_num)
{
- size_t len = jp_child.end - jp_child.start + 2;
+ char *str = NULL;
+ size_t str_alloc = 0, str_offset = 0;
- data = (char *)zbx_malloc(NULL, len);
- zbx_strlcpy(data, jp_child.start, len);
+ jsonpath_str_copy_value(&str, &str_alloc, &str_offset, ctx.objects.values[0].value);
+ zbx_variant_set_str(value, str);
+ ret = SUCCEED;
}
- zbx_variant_set_str(value, data);
- ret = SUCCEED;
-out:
- zbx_free(tmp_path);
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
return ret;
}
@@ -1452,7 +1777,7 @@ static char *jsonpath_expression_to_str(zbx_jsonpath_expression_t *expression)
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
case ZBX_JSONPATH_TOKEN_CONST_STR:
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- zbx_strcpy_alloc(&str, &str_alloc, &str_offset, token->data);
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, token->text);
break;
case ZBX_JSONPATH_TOKEN_PAREN_LEFT:
zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "(");
@@ -1604,35 +1929,123 @@ static int jsonpath_regexp_match(const char *text, const char *pattern, double *
/******************************************************************************
* *
+ * Purpose: add matched object to the index *
+ * *
+ * Parameters: index - [IN] the parent object index *
+ * name - [IN] the name of objec to add to index *
+ * obj - [IN] the object to add to index *
+ * value - [IN] the object matched by index path *
+ * *
+ ******************************************************************************/
+static void jsonpath_index_append_result(zbx_hashset_t *index, const char *name, zbx_jsonobj_t *obj,
+ zbx_jsonobj_t *value)
+{
+ zbx_jsonobj_index_el_t el_local = {.value = NULL}, *el;
+ size_t value_alloc = 0, value_offset = 0;
+ zbx_jsonobj_ref_t ref;
+
+ jsonpath_str_copy_value(&el_local.value, &value_alloc, &value_offset, value);
+
+ if (NULL == (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(index, &el_local)))
+ {
+ el = (zbx_jsonobj_index_el_t *)zbx_hashset_insert(index, &el_local, sizeof(el_local));
+ zbx_vector_jsonobj_ref_create(&el->objects);
+ }
+ else
+ zbx_free(el_local.value);
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.value = obj;
+ ref.external = 0;
+ zbx_vector_jsonobj_ref_append(&el->objects, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: index json object using the expression token index path *
+ * *
+ * Parameters: obj - [IN] the object to index *
+ * index_token - [IN] the expression index token (relative path) *
+ * *
+ ******************************************************************************/
+static void jsonpath_create_index(zbx_jsonobj_t *obj, zbx_jsonpath_token_t *index_token)
+{
+ zbx_jsonpath_context_t ctx;
+
+ jsonobj_init_index(obj, index_token->text);
+
+ ctx.root = obj;
+ ctx.path = index_token->path;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
+
+ if (ZBX_JSON_TYPE_OBJECT == obj->type)
+ {
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, &el->value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, el->name, &el->value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < obj->data.array.values_num; i++)
+ {
+ char name[MAX_ID_LEN + 1];
+ zbx_jsonobj_t *value = obj->data.array.values[i];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, name, value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
+}
+
+/******************************************************************************
+ * *
* Purpose: match json array element/object value against jsonpath expression *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to array element/object value *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the jsonobject to match *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_match_expression(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
- struct zbx_json_parse jp;
zbx_vector_var_t stack;
int i, ret = SUCCEED;
zbx_jsonpath_segment_t *segment;
zbx_variant_t value, *right;
double res;
- if (SUCCEED != jsonpath_pointer_to_jp(pnext, &jp))
- return FAIL;
-
zbx_vector_var_create(&stack);
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
for (i = 0; i < segment->data.expression.tokens.values_num; i++)
{
@@ -1779,25 +2192,25 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
switch (token->type)
{
case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
- if (FAIL == jsonpath_extract_value(jp_root, token->data, &value))
+ if (FAIL == jsonpath_extract_value(ctx->root, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
/* relative path can be applied only to array or object */
- if ('[' != *jp.start && '{' != *jp.start)
+ if (ZBX_JSON_TYPE_ARRAY != obj->type && ZBX_JSON_TYPE_OBJECT != obj->type)
goto out;
- if (FAIL == jsonpath_extract_value(&jp, token->data, &value))
+ if (FAIL == jsonpath_extract_value(obj, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_CONST_STR:
- zbx_variant_set_str(&value, zbx_strdup(NULL, token->data));
+ zbx_variant_set_str(&value, zbx_strdup(NULL, token->text));
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- zbx_variant_set_dbl(&value, atof(token->data));
+ zbx_variant_set_dbl(&value, atof(token->text));
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_OP_NOT:
@@ -1824,7 +2237,7 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
jsonpath_variant_to_boolean(&stack.values[0]);
if (SUCCEED != zbx_double_compare(stack.values[0].data.dbl, 0.0))
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_next_segment(ctx, name, obj, path_depth);
out:
for (i = 0; i < stack.values_num; i++)
zbx_variant_clear(&stack.values[i]);
@@ -1835,47 +2248,91 @@ out:
/******************************************************************************
* *
+ * Purpose: query indexed object fields for jsonpath segment match *
+ * *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
+ * path_depth - [IN] the jsonpath segment to match *
+ * *
+ * Return value: SUCCEED - the object was queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_indexed_expression(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
+{
+ zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ zbx_jsonobj_index_el_t index_local, *el;
+
+ index_local.value = segment->data.expression.value_token->text;
+
+ if (NULL != (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(&obj->index->objects, &index_local)))
+ {
+ int i;
+
+ for (i = 0; i < el->objects.values_num; i++)
+ {
+ jsonpath_match_expression(ctx, el->objects.values[i].name, el->objects.values[i].value,
+ path_depth);
+ }
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
* Purpose: query object fields for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json object to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the object was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- const char *pnext = NULL;
- char name[MAX_STRING_LEN];
const zbx_jsonpath_segment_t *segment;
int ret = SUCCEED;
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ segment = &ctx->path->segments[path_depth];
+
+ if (ZBX_JSONPATH_SEGMENT_MATCH_LIST == segment->type)
+ {
+ ret = jsonpath_match_name(ctx, obj, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ }
+ else if (ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION == segment->type && NULL != segment->data.expression.index_token)
+ {
+ if (NULL == obj->index)
+ jsonpath_create_index(obj, segment->data.expression.index_token);
- segment = &jsonpath->segments[path_depth];
+ if (0 == strcmp(obj->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, obj, path_depth);
+ }
- while (NULL != (pnext = zbx_json_pair_next(jp, pnext, name, sizeof(name))) && SUCCEED == ret)
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)) && SUCCEED == ret &&
+ 0 == ctx->found)
{
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_name(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_match_expression(ctx, el->name, &el->value, path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_contents(ctx, &el->value, path_depth);
}
return ret;
@@ -1883,25 +2340,19 @@ static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const str
/******************************************************************************
* *
- * Purpose: match array element against segment index list *
+ * Purpose: array elements against segment index list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
* path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_json_t *objects)
+static int jsonpath_match_index(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
/* array contents can match only index list */
@@ -1914,11 +2365,20 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
memcpy(&query_index, node->data, sizeof(query_index));
- if ((query_index >= 0 && index == query_index) || index == elements_num + query_index)
+ if (0 > query_index)
+ query_index += parent->data.array.values_num;
+
+ if (query_index >= 0 && query_index < parent->data.array.values_num)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", query_index);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[query_index],
+ path_depth))
+ {
return FAIL;
- break;
+ }
}
}
@@ -1927,38 +2387,37 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: match array element against segment index range *
+ * Purpose: match array elements against segment index range *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * objects - [OUT] the matched json elements (name, value) *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
+ * path_depth - [IN] the jsonpath segment to match *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_json_t *objects)
+static int jsonpath_match_range(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- int start_index, end_index;
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ int i, start_index, end_index, values_num;
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ values_num = parent->data.array.values_num;
start_index = (0 != (segment->data.range.flags & 0x01) ? segment->data.range.start : 0);
- end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : elements_num);
+ end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : values_num);
if (0 > start_index)
- start_index += elements_num;
+ start_index += values_num;
if (0 > end_index)
- end_index += elements_num;
+ end_index += values_num;
- if (start_index <= index && end_index > index)
+ for (i = start_index; i < end_index; i++)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[i], path_depth))
return FAIL;
}
@@ -1967,59 +2426,69 @@ static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: query array elements for jsonpath segment match *
+ * Purpose: query json array for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json array to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * array - [IN] the json array to query *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the array was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth)
{
- const char *pnext = NULL;
- int index = 0, elements_num = 0, ret = SUCCEED;
+ int ret = SUCCEED, i;
zbx_jsonpath_segment_t *segment;
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
- while (NULL != (pnext = zbx_json_next(jp, pnext)))
- elements_num++;
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ ret = jsonpath_match_index(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
+ ret = jsonpath_match_range(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ if (NULL != segment->data.expression.index_token)
+ {
+ if (NULL == array->index)
+ jsonpath_create_index(array, segment->data.expression.index_token);
- while (NULL != (pnext = zbx_json_next(jp, pnext)) && SUCCEED == ret)
+ if (0 == strcmp(array->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, array, path_depth);
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < array->data.array.values_num && SUCCEED == ret && 0 == ctx->found; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_index(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
- ret = jsonpath_match_range(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, objects);
+ ret = jsonpath_query_next_segment(ctx, name, array->data.array.values[i], path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_match_expression(ctx, name, array->data.array.values[i], path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
-
- index++;
+ ret = jsonpath_query_contents(ctx, array->data.array.values[i], path_depth);
}
return ret;
@@ -2027,123 +2496,99 @@ static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const stru
/******************************************************************************
* *
- * Purpose: extract JSON element value from data *
- * *
- * Parameters: ptr - [IN] pointer to the element to extract *
- * element - [OUT] the extracted element *
+ * Purpose: get numeric value from json data *
* *
- * Return value: SUCCEED - the element was extracted successfully *
- * FAIL - the pointer was not pointing to a JSON element *
+ * Parameters: obj - [IN] json object *
+ * value - [OUT] the extracted value *
* *
- * Comments: String value element is unquoted, other elements are copied as *
- * is. *
+ * Return value: SUCCEED - the value was extracted successfully *
+ * FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_element(const char *ptr, char **element)
+static int jsonpath_get_numeric_value(const zbx_jsonobj_t *obj, double *value)
{
- size_t element_size = 0;
-
- if (NULL == zbx_json_decodevalue_dyn(ptr, element, &element_size, NULL))
+ switch (obj->type)
{
- struct zbx_json_parse jp;
-
- if (SUCCEED != zbx_json_brackets_open(ptr, &jp))
+ case ZBX_JSON_TYPE_NUMBER:
+ *value = obj->data.number;
+ return SUCCEED;
+ case ZBX_JSON_TYPE_STRING:
+ if (SUCCEED == zbx_is_double(obj->data.string, value))
+ return SUCCEED;
+ zbx_set_json_strerror("array value is not a number or out of range: %s", obj->data.string);
+ return FAIL;
+ default:
+ zbx_set_json_strerror("array value type is not a number or string");
return FAIL;
-
- *element = jsonpath_strndup(jp.start, jp.end - jp.start + 1);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
- * Purpose: extract numeric value from json data *
- * *
- * Parameters: ptr - [IN] pointer to the value to extract *
- * value - [OUT] the extracted value *
+ * Purpose: get value from json data *
* *
* Return value: SUCCEED - the value was extracted successfully *
* FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_numeric_value(const char *ptr, double *value)
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj)
{
- char buffer[MAX_STRING_LEN];
-
- if (NULL == zbx_json_decodevalue(ptr, buffer, sizeof(buffer), NULL) ||
- SUCCEED != zbx_is_double(buffer, value))
+ switch (obj->type)
{
- zbx_set_json_strerror("array value is not a number or out of range starting with: %s", ptr);
- return FAIL;
+ case ZBX_JSON_TYPE_STRING:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, obj->data.string);
+ return SUCCEED;
+ break;
+ default:
+ return zbx_jsonobj_to_string(str, str_alloc, str_offset, obj);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
+ * Parameters: in - [IN] the matched objects *
* type - [IN] the function type *
- * definite_path - [IN] 1 - if the path is definite (pointing at *
- * single object) *
- * 0 - otherwise *
- * output - [OUT] the output value *
+ * definite_path - [IN/OUT] 1 - if the path is definite (pointing *
+ * at single object) *
+ * 0 - otherwise *
+ * out - [OUT] the result objects *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpath_function_type_t type,
- int definite_path, char **output)
+static int jsonpath_apply_function(const zbx_vector_jsonobj_ref_t *in, zbx_jsonpath_function_type_t type,
+ int *definite_path, zbx_vector_jsonobj_ref_t *out)
{
- int i, ret = FAIL;
- zbx_vector_json_t objects_tmp;
- double result;
+ int i, ret = FAIL;
+ double result;
+ zbx_vector_jsonobj_ref_t tmp;
+ char buffer[64];
- zbx_vector_json_create(&objects_tmp);
+ zbx_vector_jsonobj_ref_create(&tmp);
if (ZBX_JSONPATH_FUNCTION_NAME == type)
{
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot extract name from empty result");
goto out;
}
- /* For definite paths we have single output value, so return its name. */
- /* Otherwise return array of all output element names. */
- if (0 == definite_path)
- {
- struct zbx_json j;
-
- /* reserve some space for output json, 1k being large enough to satisfy most queries */
- zbx_json_initarray(&j, 1024);
- for (i = 0; i < objects->values_num; i++)
- zbx_json_addstring(&j, NULL, objects->values[i].name, ZBX_JSON_TYPE_STRING);
-
- zbx_json_close(&j);
- *output = zbx_strdup(NULL, j.buffer);
- zbx_json_clean(&j);
- }
- else
- *output = zbx_strdup(NULL, objects->values[0].name);
+ for (i = 0; i < in->values_num; i++)
+ zbx_vector_jsonobj_ref_add_string(out, "", in->values[i].name);
ret = SUCCEED;
goto out;
}
/* convert definite path result to object array if possible */
- if (0 != definite_path)
+ if (0 != *definite_path)
{
- const char *pnext;
- struct zbx_json_parse jp;
- int index = 0;
-
- if (0 == objects->values_num || '[' != *objects->values[0].value)
+ if (0 == in->values_num || ZBX_JSON_TYPE_ARRAY != in->values[0].value->type)
{
/* all functions can be applied only to arrays */
/* attempt to apply a function to non-array will fail */
@@ -2151,51 +2596,51 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
goto out;
}
- if (FAIL == zbx_json_brackets_open(objects->values[0].value, &jp))
- goto out;
-
- for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp, pnext));)
+ for (i = 0; i < in->values[0].value->data.array.values_num; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index++);
- zbx_vector_json_add_element(&objects_tmp, name, pnext);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+ zbx_vector_jsonobj_ref_add_object(&tmp, name, in->values[0].value->data.array.values[i]);
}
- objects = &objects_tmp;
+ in = &tmp;
+ *definite_path = 0;
}
if (ZBX_JSONPATH_FUNCTION_LENGTH == type)
{
- *output = zbx_dsprintf(NULL, "%d", objects->values_num);
+ zbx_snprintf(buffer, sizeof(buffer), "%d", in->values_num);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
goto out;
}
if (ZBX_JSONPATH_FUNCTION_FIRST == type)
{
- if (0 < objects->values_num)
- ret = jsonpath_extract_element(objects->values[0].value, output);
- else
- ret = SUCCEED;
+ if (0 < in->values_num)
+ zbx_vector_jsonobj_ref_add(out, &in->values[0]);
+ *definite_path = 1;
+ ret = SUCCEED;
goto out;
}
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot apply aggregation function to empty array");
goto out;
}
- if (FAIL == jsonpath_extract_numeric_value(objects->values[0].value, &result))
+ if (FAIL == jsonpath_get_numeric_value(in->values[0].value, &result))
goto out;
- for (i = 1; i < objects->values_num; i++)
+ for (i = 1; i < in->values_num; i++)
{
double value;
- if (FAIL == jsonpath_extract_numeric_value(objects->values[i].value, &value))
+ if (FAIL == jsonpath_get_numeric_value(in->values[i].value, &value))
goto out;
switch (type)
@@ -2218,19 +2663,22 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
}
if (ZBX_JSONPATH_FUNCTION_AVG == type)
- result /= objects->values_num;
+ result /= in->values_num;
- *output = zbx_dsprintf(NULL, ZBX_FS_DBL, result);
- if (SUCCEED != zbx_is_double(*output, NULL))
+ zbx_print_double(buffer, sizeof(buffer), result);
+ if (SUCCEED != zbx_is_double(buffer, NULL))
{
- zbx_set_json_strerror("invalid function result: %s", *output);
+ zbx_set_json_strerror("invalid function result: %s", buffer);
goto out;
}
- zbx_del_zeros(*output);
+
+ zbx_del_zeros(buffer);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
out:
- zbx_vector_json_clear_ext(&objects_tmp);
- zbx_vector_json_destroy(&objects_tmp);
+ zbx_vector_jsonobj_ref_clear_ext(&tmp);
+ zbx_vector_jsonobj_ref_destroy(&tmp);
return ret;
}
@@ -2239,58 +2687,47 @@ out:
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: jp_root - [IN] the document root *
- * objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * output - [OUT] the output value *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * path_depth - [IN] the jsonpath segment to match *
+ * definite_path - [IN/OUT] *
+ * out - [OUT] the result object *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const zbx_vector_json_t *objects,
- const zbx_jsonpath_t *jsonpath, int path_depth, char **output)
+static int jsonpath_apply_functions(zbx_jsonpath_context_t *ctx, int path_depth, int *definite_path,
+ zbx_vector_jsonobj_ref_t *out)
{
- int ret, definite_path;
- zbx_vector_json_t input;
- char *input_json = NULL;
+ int ret;
+ zbx_vector_jsonobj_ref_t in;
- zbx_vector_json_create(&input);
+ zbx_vector_jsonobj_ref_create(&in);
/* when functions are applied directly to the json document (at the start of the jsonpath ) */
/* it makes all document as input object */
if (0 == path_depth)
- zbx_vector_json_add_element(&input, "", jp_root->start);
+ zbx_vector_jsonobj_ref_add_object(&in, "", ctx->root);
else
- zbx_vector_json_copy(&input, objects);
-
- definite_path = jsonpath->definite;
+ zbx_vector_jsonobj_ref_copy(&in, &ctx->objects);
for (;;)
{
- ret = jsonpath_apply_function(&input, jsonpath->segments[path_depth++].data.function.type,
- definite_path, output);
+ ret = jsonpath_apply_function(&in, ctx->path->segments[path_depth++].data.function.type,
+ definite_path, out);
- zbx_vector_json_clear_ext(&input);
- zbx_free(input_json);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
- if (SUCCEED != ret || path_depth == jsonpath->segments_num)
+ if (SUCCEED != ret || path_depth == ctx->path->segments_num)
break;
- if (NULL != *output)
- {
- zbx_vector_json_add_element(&input, "", *output);
- input_json = *output;
- *output = NULL;
- }
-
- /* functions return single value, so for the next functions path becomes definite */
- definite_path = 1;
+ zbx_vector_jsonobj_ref_copy(&in, out);
+ zbx_vector_jsonobj_ref_clear_ext(out);
}
- zbx_vector_json_destroy(&input);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
+ zbx_vector_jsonobj_ref_destroy(&in);
return ret;
}
@@ -2299,49 +2736,37 @@ static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const
* *
* Purpose: format query result, depending on jsonpath type *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath used to acquire result *
- * output - [OUT] the output value *
+ * Parameters: objects - [IN] the matched json refs (name, value) *
+ * definite_path - [IN] the jsonpath definite flag *
+ * output - [OUT] the output value *
* *
* Return value: SUCCEED - the result was formatted successfully *
* FAIL - invalid result data (internal json error) *
* *
******************************************************************************/
-static int jsonpath_format_query_result(const zbx_vector_json_t *objects, zbx_jsonpath_t *jsonpath, char **output)
+static int jsonpath_format_query_result(const zbx_vector_jsonobj_ref_t *objects, int definite_path, char **output)
{
size_t output_offset = 0, output_alloc;
int i;
+ char delim;
if (0 == objects->values_num)
return SUCCEED;
- if (1 == jsonpath->definite)
- {
- return jsonpath_extract_element(objects->values[0].value, output);
- }
+ if (1 == definite_path)
+ return jsonpath_str_copy_value(output, &output_alloc, &output_offset, objects->values[0].value);
/* reserve 32 bytes per returned object plus array start/end [] and terminating zero */
- output_alloc = objects->values_num * 32 + 3;
+ output_alloc = (size_t)objects->values_num * 32 + 3;
*output = (char *)zbx_malloc(NULL, output_alloc);
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, '[');
+ delim = '[';
for (i = 0; i < objects->values_num; i++)
{
- struct zbx_json_parse jp;
-
- if (FAIL == jsonpath_pointer_to_jp(objects->values[i].value, &jp))
- {
- zbx_set_json_strerror("cannot format query result, unrecognized json part starting with: %s",
- objects->values[i].value);
- zbx_free(*output);
- return FAIL;
- }
-
- if (0 != i)
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ',');
-
- zbx_strncpy_alloc(output, &output_alloc, &output_offset, jp.start, jp.end - jp.start + 1);
+ zbx_chrcpy_alloc(output, &output_alloc, &output_offset, delim);
+ zbx_jsonobj_to_string(output, &output_alloc, &output_offset, objects->values[i].value);
+ delim = ',';
}
zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ']');
@@ -2364,7 +2789,7 @@ void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath)
* Purpose: compile jsonpath to be used in queries *
* *
* Parameters: path - [IN] the path to parse *
- * jsonpath - [IN/OUT] the compiled jsonpath *
+ * jsonpath - [IN/OUT] the compiled jsonpath *
* *
* Return value: SUCCEED - the segment was parsed successfully *
* FAIL - otherwise *
@@ -2386,6 +2811,7 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
memset(&jpquery, 0, sizeof(zbx_jsonpath_t));
jsonpath_reserve(&jpquery, 4);
jpquery.definite = 1;
+ jpquery.first_match = 0;
for (ptr++; '\0' != *ptr; ptr = next)
{
@@ -2453,7 +2879,10 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
ret = zbx_jsonpath_error(ptr);
if (SUCCEED == ret)
+ {
+ jpquery.first_match |= jpquery.definite;
*jsonpath = jpquery;
+ }
else
zbx_jsonpath_clear(&jpquery);
@@ -2472,37 +2901,89 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
* being counted as successful query) *
* FAIL - otherwise *
* *
+ * Comments: This function is for compatibility purposes. Where possible the *
+ * zbx_jsonobj_query() function must be used. *
+ * *
******************************************************************************/
int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output)
{
+ int ret;
+ zbx_jsonobj_t obj;
+
+ if (SUCCEED != zbx_jsonobj_open(jp->start, &obj))
+ return FAIL;
+
+ ret = zbx_jsonobj_query(&obj, path, output);
+
+ zbx_jsonobj_clear(&obj);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: perform jsonpath query on the specified json object *
+ * *
+ * Parameters: obj - [IN] the json object *
+ * path - [IN] the jsonpath *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the query was performed successfully (empty result *
+ * being counted as successful query) *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_query(zbx_jsonobj_t *obj, const char *path, char **output)
+{
+ zbx_jsonpath_context_t ctx;
zbx_jsonpath_t jsonpath;
- int path_depth = 0, ret = SUCCEED;
- zbx_vector_json_t objects;
+ int ret = SUCCEED;
if (FAIL == zbx_jsonpath_compile(path, &jsonpath))
return FAIL;
- zbx_vector_json_create(&objects);
+ ctx.found = 0;
+ ctx.root = obj;
+ ctx.path = &jsonpath;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if ('{' == *jp->start)
- ret = jsonpath_query_object(jp, jp, &jsonpath, path_depth, &objects);
- else if ('[' == *jp->start)
- ret = jsonpath_query_array(jp, jp, &jsonpath, path_depth, &objects);
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(&ctx, obj, 0);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(&ctx, obj, 0);
+ break;
+ default:
+ break;
+ }
if (SUCCEED == ret)
{
+ zbx_vector_jsonobj_ref_t out;
+ int definite_path = jsonpath.definite, path_depth;
+
+ zbx_vector_jsonobj_ref_create(&out);
+
path_depth = jsonpath.segments_num;
while (0 < path_depth && ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath.segments[path_depth - 1].type)
path_depth--;
if (path_depth < jsonpath.segments_num)
- ret = jsonpath_apply_functions(jp, &objects, &jsonpath, path_depth, output);
+ {
+ if (SUCCEED == (ret = jsonpath_apply_functions(&ctx, path_depth, &definite_path, &out)))
+ ret = jsonpath_format_query_result(&out, definite_path, output);
+ }
else
- ret = jsonpath_format_query_result(&objects, &jsonpath, output);
+ ret = jsonpath_format_query_result(&ctx.objects, definite_path, output);
+
+ zbx_vector_jsonobj_ref_clear_ext(&out);
+ zbx_vector_jsonobj_ref_destroy(&out);
}
- zbx_vector_json_clear_ext(&objects);
- zbx_vector_json_destroy(&objects);
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
zbx_jsonpath_clear(&jsonpath);
return ret;
diff --git a/src/libs/zbxjson/jsonpath.h b/src/libs/zbxjson/jsonpath.h
index 3a5be7c9413..644aef6aa4a 100644
--- a/src/libs/zbxjson/jsonpath.h
+++ b/src/libs/zbxjson/jsonpath.h
@@ -20,7 +20,9 @@
#ifndef ZABBIX_JSONPATH_H
#define ZABBIX_JSONPATH_H
-#include "zbxalgo.h"
+#include "zbxjson.h"
+
+typedef struct zbx_jsonpath_token zbx_jsonpath_token_t;
typedef enum
{
@@ -78,10 +80,19 @@ typedef struct
}
zbx_jsonpath_range_t;
+typedef enum
+{
+ ZBX_JSONPATH_EXPRESSION_INDEX_TRUE,
+ ZBX_JSONPATH_EXPRESSION_INDEX_FALSE,
+}
+zbx_json_path_expression_index_t;
+
/* expression tokens in postfix notation */
typedef struct
{
zbx_vector_ptr_t tokens;
+ zbx_jsonpath_token_t *index_token; /* relative path token that is used to index parent object */
+ zbx_jsonpath_token_t *value_token; /* the index value token */
}
zbx_jsonpath_expression_t;
@@ -150,11 +161,11 @@ typedef enum
}
zbx_jsonpath_token_type_t;
-typedef struct
+struct zbx_jsonpath_token
{
unsigned char type;
- char *data;
-}
-zbx_jsonpath_token_t;
+ char *text;
+ zbx_jsonpath_t *path;
+};
#endif
diff --git a/src/libs/zbxsysinfo/linux/diskio.c b/src/libs/zbxsysinfo/linux/diskio.c
index 4464a09c8d2..cc356549508 100644
--- a/src/libs/zbxsysinfo/linux/diskio.c
+++ b/src/libs/zbxsysinfo/linux/diskio.c
@@ -357,6 +357,8 @@ int vfs_dev_discovery(AGENT_REQUEST *request, AGENT_RESULT *result)
zbx_fclose(f);
}
+ else
+ continue;
if (0 == devtype_found)
{
diff --git a/src/libs/zbxsysinfo/linux/hardware.c b/src/libs/zbxsysinfo/linux/hardware.c
index d8eff864d47..8ebd7086a47 100644
--- a/src/libs/zbxsysinfo/linux/hardware.c
+++ b/src/libs/zbxsysinfo/linux/hardware.c
@@ -496,7 +496,12 @@ int system_hw_cpu(AGENT_REQUEST *request, AGENT_RESULT *result)
filter))
{
ret = SYSINFO_RET_OK;
- sscanf(tmp, ZBX_FS_UI64, &curfreq);
+ if (1 != sscanf(tmp, ZBX_FS_UI64, &curfreq))
+ {
+ zbx_fclose(f);
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain CPU frequency."));
+ return SYSINFO_RET_FAIL;
+ }
}
}
diff --git a/src/libs/zbxsysinfo/linux/proc.c b/src/libs/zbxsysinfo/linux/proc.c
index f2e80c49d09..01b602af9a2 100644
--- a/src/libs/zbxsysinfo/linux/proc.c
+++ b/src/libs/zbxsysinfo/linux/proc.c
@@ -1881,11 +1881,12 @@ int proc_get(AGENT_REQUEST *request, AGENT_RESULT *result)
if (SUCCEED != get_cmdline(f_cmd, &cmdline, &l))
continue;
- read_value_from_proc_file(f_status, 0, "Name", PROC_VAL_TYPE_TEXT, NULL, &prname);
+ if (SUCCEED != read_value_from_proc_file(f_status, 0, "Name", PROC_VAL_TYPE_TEXT, NULL, &prname))
+ continue;
if ('\0' != *cmdline)
{
- char *p, *pend, sep;
+ char *p, *pend, sep = 0;
size_t len;
if (NULL != (pend = strpbrk(cmdline, " :")))
diff --git a/src/libs/zbxsysinfo/sysinfo.h b/src/libs/zbxsysinfo/sysinfo.h
index ba6474293a9..384fbe09c93 100644
--- a/src/libs/zbxsysinfo/sysinfo.h
+++ b/src/libs/zbxsysinfo/sysinfo.h
@@ -176,10 +176,10 @@ int perf_counter(AGENT_REQUEST *request, AGENT_RESULT *result);
int perf_counter_en(AGENT_REQUEST *request, AGENT_RESULT *result);
int perf_instance_discovery(AGENT_REQUEST *request, AGENT_RESULT *result);
int perf_instance_discovery_en(AGENT_REQUEST *request, AGENT_RESULT *result);
-int service_discovery(AGENT_REQUEST *request, AGENT_RESULT *result);
-int service_info(AGENT_REQUEST *request, AGENT_RESULT *result);
-int service_state(AGENT_REQUEST *request, AGENT_RESULT *result);
-int services(AGENT_REQUEST *request, AGENT_RESULT *result);
+int discover_services(AGENT_REQUEST *request, AGENT_RESULT *result);
+int get_service_info(AGENT_REQUEST *request, AGENT_RESULT *result);
+int get_service_state(AGENT_REQUEST *request, AGENT_RESULT *result);
+int get_list_of_services(AGENT_REQUEST *request, AGENT_RESULT *result);
int proc_info(AGENT_REQUEST *request, AGENT_RESULT *result);
int net_if_list(AGENT_REQUEST *request, AGENT_RESULT *result);
int wmi_get(AGENT_REQUEST *request, AGENT_RESULT *result);
diff --git a/src/libs/zbxsysinfo/win32/proc.c b/src/libs/zbxsysinfo/win32/proc.c
index dedbea03361..ed7babb04d1 100644
--- a/src/libs/zbxsysinfo/win32/proc.c
+++ b/src/libs/zbxsysinfo/win32/proc.c
@@ -73,7 +73,10 @@ static int zbx_get_process_username(HANDLE hProcess, char *userName, char *sid)
int iUse, res = FAIL;
/* clean result; */
- *userName = *sid = '\0';
+ *userName = '\0';
+
+ if (NULL != sid)
+ *sid = '\0';
/* open the processes token */
if (0 == OpenProcessToken(hProcess, TOKEN_QUERY, &tok))
diff --git a/src/libs/zbxsysinfo/win32/services.c b/src/libs/zbxsysinfo/win32/services.c
index 05ed85f0ea4..c3a24fd0ec2 100644
--- a/src/libs/zbxsysinfo/win32/services.c
+++ b/src/libs/zbxsysinfo/win32/services.c
@@ -254,7 +254,7 @@ static zbx_startup_type_t get_service_startup_type(SC_HANDLE h_srv, QUERY_SERVIC
}
}
-int service_discovery(AGENT_REQUEST *request, AGENT_RESULT *result)
+int discover_services(AGENT_REQUEST *request, AGENT_RESULT *result)
{
ENUM_SERVICE_STATUS_PROCESS *ssp = NULL;
SC_HANDLE h_mgr;
@@ -391,7 +391,7 @@ next:
return SYSINFO_RET_OK;
}
-int service_info(AGENT_REQUEST *request, AGENT_RESULT *result)
+int get_service_info(AGENT_REQUEST *request, AGENT_RESULT *result)
{
#define ZBX_SRV_PARAM_STATE 0x01
#define ZBX_SRV_PARAM_DISPLAYNAME 0x02
@@ -550,7 +550,7 @@ int service_info(AGENT_REQUEST *request, AGENT_RESULT *result)
#undef ZBX_NON_EXISTING_SRV
}
-int service_state(AGENT_REQUEST *request, AGENT_RESULT *result)
+int get_service_state(AGENT_REQUEST *request, AGENT_RESULT *result)
{
SC_HANDLE mgr, service;
char *name;
@@ -657,7 +657,8 @@ static int check_service_starttype(SC_HANDLE h_srv, int start_type)
*/
#define ZBX_SRV_STATE_ALL 0x007f /* ZBX_SRV_STATE_STOPPED | ZBX_SRV_STATE_STARTED
*/
-static int check_service_state(SC_HANDLE h_srv, int service_state)
+
+static int get_service_state_local(SC_HANDLE h_srv, int service_state)
{
SERVICE_STATUS status;
@@ -699,7 +700,7 @@ static int check_service_state(SC_HANDLE h_srv, int service_state)
return FAIL;
}
-int services(AGENT_REQUEST *request, AGENT_RESULT *result)
+int get_list_of_services(AGENT_REQUEST *request, AGENT_RESULT *result)
{
int start_type, service_state;
char *type, *state, *exclude, *buf = NULL, *utf8;
@@ -776,7 +777,7 @@ int services(AGENT_REQUEST *request, AGENT_RESULT *result)
if (SUCCEED == check_service_starttype(h_srv, start_type))
{
- if (SUCCEED == check_service_state(h_srv, service_state))
+ if (SUCCEED == get_service_state_local(h_srv, service_state))
{
utf8 = zbx_unicode_to_utf8(ssp[i].lpServiceName);
diff --git a/src/libs/zbxsysinfo/win32/win32.c b/src/libs/zbxsysinfo/win32/win32.c
index 3357f46d566..65ec0854913 100644
--- a/src/libs/zbxsysinfo/win32/win32.c
+++ b/src/libs/zbxsysinfo/win32/win32.c
@@ -56,10 +56,10 @@ ZBX_METRIC parameters_specific[] =
{"system.uname", 0, system_uname, NULL},
- {"service.discovery", 0, service_discovery, NULL},
- {"service.info", CF_HAVEPARAMS, service_info, ZABBIX_SERVICE_NAME},
- {"service_state", CF_HAVEPARAMS, service_state, ZABBIX_SERVICE_NAME},
- {"services", CF_HAVEPARAMS, services, NULL},
+ {"service.discovery", 0, discover_services, NULL},
+ {"service.info", CF_HAVEPARAMS, get_service_info, ZABBIX_SERVICE_NAME},
+ {"service_state", CF_HAVEPARAMS, get_service_state, ZABBIX_SERVICE_NAME},
+ {"services", CF_HAVEPARAMS, get_list_of_services, NULL},
{"perf_counter", CF_HAVEPARAMS, perf_counter, "\\System\\Processes"},
{"perf_counter_en", CF_HAVEPARAMS, perf_counter_en, "\\System\\Processes"},
{"perf_instance.discovery", CF_HAVEPARAMS, perf_instance_discovery, "Processor"},
diff --git a/src/zabbix_agent/Makefile.am b/src/zabbix_agent/Makefile.am
index 7faa9ad9a17..39ce4441557 100644
--- a/src/zabbix_agent/Makefile.am
+++ b/src/zabbix_agent/Makefile.am
@@ -54,7 +54,6 @@ zabbix_agentd_LDADD = \
$(top_builddir)/src/libs/zbxsysinfo/alias/libalias.a \
$(top_builddir)/src/libs/zbxlog/libzbxlog.a \
$(top_builddir)/src/libs/zbxregexp/libzbxregexp.a \
- $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxthreads/libzbxthreads.a \
$(top_builddir)/src/libs/zbxmutexs/libzbxmutexs.a \
$(top_builddir)/src/libs/zbxnix/libzbxnix.a \
@@ -62,6 +61,7 @@ zabbix_agentd_LDADD = \
$(top_builddir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
$(top_builddir)/src/libs/zbxconf/libzbxconf.a \
$(top_builddir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxvariant/libzbxvariant.a \
$(top_builddir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_builddir)/src/libs/zbxgetopt/libzbxgetopt.a \
diff --git a/src/zabbix_server/Makefile.am b/src/zabbix_server/Makefile.am
index 4c4870298fe..9ed2104d3a3 100644
--- a/src/zabbix_server/Makefile.am
+++ b/src/zabbix_server/Makefile.am
@@ -106,7 +106,6 @@ zabbix_server_LDADD = \
$(top_builddir)/src/libs/zbxself/libzbxself.a \
$(top_builddir)/src/libs/zbxself/libzbxself_server.a \
$(top_builddir)/src/libs/zbxipcservice/libzbxipcservice.a \
- $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxthreads/libzbxthreads.a \
$(top_builddir)/src/libs/zbxmutexs/libzbxmutexs.a \
$(top_builddir)/src/libs/zbxconf/libzbxconf.a \
@@ -118,6 +117,7 @@ zabbix_server_LDADD = \
$(top_builddir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
$(top_builddir)/src/libs/zbxxml/libzbxxml.a \
$(top_builddir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxvault/libzbxvault.a \
$(top_builddir)/src/libs/zbxcyberark/libzbxcyberark.a \
$(top_builddir)/src/libs/zbxhashicorp/libzbxhashicorp.a \
diff --git a/src/zabbix_server/poller/checks_simple_vmware.c b/src/zabbix_server/poller/checks_simple_vmware.c
index f2bfbe6e618..14a13ba2872 100644
--- a/src/zabbix_server/poller/checks_simple_vmware.c
+++ b/src/zabbix_server/poller/checks_simple_vmware.c
@@ -4299,7 +4299,7 @@ int check_vcenter_vm_discovery(AGENT_REQUEST *request, const char *username, con
rpool_cmp.id = vm->props[ZBX_VMWARE_VMPROP_RESOURCEPOOL];
if (FAIL != (idx = zbx_vector_vmware_resourcepool_bsearch(&service->data->resourcepools,
- &rpool_cmp, vmware_resourcepool_compare_id)))
+ &rpool_cmp, ZBX_DEFAULT_STR_PTR_COMPARE_FUNC)))
{
zbx_json_addstring(&json_data, "{#VM.RPOOL.PATH}", ZBX_NULL2EMPTY_STR(
service->data->resourcepools.values[idx]->path),
@@ -5817,7 +5817,7 @@ static int check_vcenter_rp_common(const char *url, const char *username, const
rp_cmp.id = (char *)rpid;
if (FAIL == zbx_vector_vmware_resourcepool_bsearch(&service->data->resourcepools, &rp_cmp,
- vmware_resourcepool_compare_id))
+ ZBX_DEFAULT_STR_PTR_COMPARE_FUNC))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Unknown resource pool id."));
goto unlock;
diff --git a/src/zabbix_server/preprocessor/item_preproc.c b/src/zabbix_server/preprocessor/item_preproc.c
index 065eb31ae2e..ae511b94532 100644
--- a/src/zabbix_server/preprocessor/item_preproc.c
+++ b/src/zabbix_server/preprocessor/item_preproc.c
@@ -934,7 +934,8 @@ static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **
* *
* Purpose: execute jsonpath query *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -942,18 +943,59 @@ static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **
* FAIL - otherwise *
* *
******************************************************************************/
-static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, char **errmsg)
+static int item_preproc_jsonpath_op(zbx_preproc_cache_t *cache, zbx_variant_t *value, const char *params,
+ char **errmsg)
{
- struct zbx_json_parse jp;
- char *data = NULL;
+ char *data = NULL;
- if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
- return FAIL;
+ if (NULL == cache)
+ {
+ zbx_jsonobj_t obj;
+
+ if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
+ return FAIL;
- if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_jsonpath_query(&jp, params, &data))
+ if (FAIL == zbx_jsonobj_open(value->data.str, &obj))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
+
+ if (FAIL == zbx_jsonobj_query(&obj, params, &data))
+ {
+ zbx_jsonobj_clear(&obj);
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
+
+ zbx_jsonobj_clear(&obj);
+ }
+ else
{
- *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
- return FAIL;
+ zbx_jsonobj_t *obj;
+
+ if (NULL == (obj = (zbx_jsonobj_t *)zbx_preproc_cache_get(cache, ZBX_PREPROC_JSONPATH)))
+ {
+ if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
+ return FAIL;
+
+ obj = (zbx_jsonobj_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+
+ if (SUCCEED != zbx_jsonobj_open(value->data.str, obj))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ zbx_free(obj);
+ return FAIL;
+ }
+
+ zbx_preproc_cache_put(cache, ZBX_PREPROC_JSONPATH, obj);
+ }
+
+ if (FAIL == zbx_jsonobj_query(obj, params, &data))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
}
if (NULL == data)
@@ -972,7 +1014,8 @@ static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, ch
* *
* Purpose: execute jsonpath query *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -980,11 +1023,12 @@ static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, ch
* FAIL - otherwise *
* *
******************************************************************************/
-static int item_preproc_jsonpath(zbx_variant_t *value, const char *params, char **errmsg)
+static int item_preproc_jsonpath(zbx_preproc_cache_t *cache, zbx_variant_t *value, const char *params,
+ char **errmsg)
{
char *err = NULL;
- if (SUCCEED == item_preproc_jsonpath_op(value, params, &err))
+ if (SUCCEED == item_preproc_jsonpath_op(cache, value, params, &err))
return SUCCEED;
*errmsg = zbx_dsprintf(*errmsg, "cannot extract value from json by path \"%s\": %s", params, err);
@@ -1571,7 +1615,8 @@ fail:
* *
* Purpose: parse Prometheus format metrics *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -2148,7 +2193,7 @@ int zbx_item_preproc(zbx_preproc_cache_t *cache, unsigned char value_type, zbx_v
ret = item_preproc_xpath(value, op->params, error);
break;
case ZBX_PREPROC_JSONPATH:
- ret = item_preproc_jsonpath(value, op->params, error);
+ ret = item_preproc_jsonpath(cache, value, op->params, error);
break;
case ZBX_PREPROC_VALIDATE_RANGE:
ret = item_preproc_validate_range(value_type, value, op->params, error);
diff --git a/src/zabbix_server/preprocessor/preproc_cache.c b/src/zabbix_server/preprocessor/preproc_cache.c
index 9b7cff0731e..556f58e53e9 100644
--- a/src/zabbix_server/preprocessor/preproc_cache.c
+++ b/src/zabbix_server/preprocessor/preproc_cache.c
@@ -95,6 +95,11 @@ void zbx_preproc_cache_clear(zbx_preproc_cache_t *cache)
case ZBX_PREPROC_PROMETHEUS_PATTERN:
zbx_prometheus_clear((zbx_prometheus_t *)cache->refs.values[i].impl);
zbx_free(cache->refs.values[i].impl);
+ break;
+ case ZBX_PREPROC_JSONPATH:
+ zbx_jsonobj_clear((zbx_jsonobj_t *)cache->refs.values[i].impl);
+ zbx_free(cache->refs.values[i].impl);
+ break;
}
}
diff --git a/src/zabbix_server/vmware/vmware.c b/src/zabbix_server/vmware/vmware.c
index c945040cd45..d710e9e86f8 100644
--- a/src/zabbix_server/vmware/vmware.c
+++ b/src/zabbix_server/vmware/vmware.c
@@ -239,6 +239,21 @@ static zbx_hashset_t evt_msg_strpool;
static zbx_uint64_t evt_req_chunk_size;
+/* the vmware resource pool chunk */
+typedef struct
+{
+ char *id;
+ char *first_parentid;
+ char *name;
+ const char *path;
+ const char *parentid;
+ unsigned char parent_is_rp;
+}
+zbx_vmware_rpool_chunk_t;
+
+ZBX_PTR_VECTOR_DECL(vmware_rpool_chunk, zbx_vmware_rpool_chunk_t *)
+ZBX_PTR_VECTOR_IMPL(vmware_rpool_chunk, zbx_vmware_rpool_chunk_t *)
+
/*
* SOAP support
*/
@@ -500,17 +515,6 @@ static zbx_vmware_propmap_t vm_propmap[] = {
ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_FOLDER, "[text()='" id "']") "/" \
ZBX_XPATH_PROP_NAME_NODE("parent") "[@type='Folder']"
-#define ZBX_XPATH_GET_RESOURCEPOOL_NAME(id) \
- ZBX_XPATH_GET_OBJECT_NAME(ZBX_VMWARE_SOAP_RESOURCEPOOL, id)
-
-#define ZBX_XPATH_GET_RESOURCEPOOL_PARENTID(id) \
- ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_RESOURCEPOOL, "[text()='" id "']") "/" \
- ZBX_XPATH_PROP_NAME_NODE("parent") "[@type='ResourcePool']"
-
-#define ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID(id) \
- ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_RESOURCEPOOL, "[text()='" id "']") "/" \
- ZBX_XPATH_PROP_NAME_NODE("parent") "[@type!='ResourcePool']"
-
/* hypervisor hashset support */
static zbx_hash_t vmware_hv_hash(const void *data)
{
@@ -2375,6 +2379,22 @@ static void vmware_datacenter_free(zbx_vmware_datacenter_t *datacenter)
/******************************************************************************
* *
+ * Purpose: frees resources allocated to store rp_chunk data *
+ * *
+ * Parameters: rp_chunk - [IN] the resourcepool chunk *
+ * *
+ ******************************************************************************/
+static void vmware_rp_chunk_free(zbx_vmware_rpool_chunk_t *rp_chunk)
+{
+ zbx_free(rp_chunk->id);
+ zbx_free(rp_chunk->name);
+ zbx_free(rp_chunk->first_parentid);
+ /* path and parent are not cleared */
+ zbx_free(rp_chunk);
+}
+
+/******************************************************************************
+ * *
* Purpose: frees resources allocated to store resourcepool data *
* *
* Parameters: resourcepool - [IN] the resourcepool *
@@ -2864,14 +2884,15 @@ typedef struct
zbx_property_collection_iter;
static int zbx_property_collection_init(CURL *easyhandle, const char *property_collection_query,
- const char *property_collector, zbx_property_collection_iter **iter, xmlDoc **xdoc, char **error)
+ const char *property_collector, const char *fn_parent, zbx_property_collection_iter **iter,
+ xmlDoc **xdoc, char **error)
{
*iter = (zbx_property_collection_iter *)zbx_malloc(*iter, sizeof(zbx_property_collection_iter));
(*iter)->property_collector = property_collector;
(*iter)->easyhandle = easyhandle;
(*iter)->token = NULL;
- if (SUCCEED != zbx_soap_post(__func__, (*iter)->easyhandle, property_collection_query, xdoc, &(*iter)->token,
+ if (SUCCEED != zbx_soap_post(fn_parent, (*iter)->easyhandle, property_collection_query, xdoc, &(*iter)->token,
error))
{
return FAIL;
@@ -2880,7 +2901,8 @@ static int zbx_property_collection_init(CURL *easyhandle, const char *property_c
return SUCCEED;
}
-static int zbx_property_collection_next(zbx_property_collection_iter *iter, xmlDoc **xdoc, char **error)
+static int zbx_property_collection_next(const char *fn_parent, zbx_property_collection_iter *iter, xmlDoc **xdoc,
+ char **error)
{
# define ZBX_POST_CONTINUE_RETRIEVE_PROPERTIES \
ZBX_POST_VSPHERE_HEADER \
@@ -2904,7 +2926,7 @@ static int zbx_property_collection_next(zbx_property_collection_iter *iter, xmlD
zbx_snprintf(post, sizeof(post), ZBX_POST_CONTINUE_RETRIEVE_PROPERTIES, iter->property_collector, token_esc);
zbx_free(token_esc);
- if (SUCCEED != zbx_soap_post(__func__, iter->easyhandle, post, xdoc, NULL, error))
+ if (SUCCEED != zbx_soap_post(fn_parent, iter->easyhandle, post, xdoc, NULL, error))
return FAIL;
zbx_free(iter->token);
@@ -3989,83 +4011,6 @@ out:
/******************************************************************************
* *
- * Purpose: get resource pool parentid and path (chain of resource pool *
- * names divided by '/') *
- * *
- * Parameters: xdoc - [IN] the xml with all vm details *
- * r_id - [IN] the resource pool id *
- * parentid - [OUT] the resource pool parent id *
- * path - [OUT] the resource pool path *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-static int vmware_service_get_resourcepool_data(xmlDoc *xdoc, const char *r_id, char **parentid, char **path)
-{
- char tmp[MAX_STRING_LEN], *id, *name;
- int ret = SUCCEED;
-
- zabbix_log(LOG_LEVEL_DEBUG, "In %s() resource pool id:'%s'", __func__, r_id);
- id = zbx_strdup(NULL, r_id);
- *path = *parentid = NULL;
-
- do
- {
- char *id_esc;
-
- id_esc = zbx_xml_escape_dyn(id);
- zbx_free(id);
- zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_GET_RESOURCEPOOL_NAME("%s"), id_esc);
-
- if (NULL == (name = zbx_xml_doc_read_value(xdoc , tmp)))
- {
- zbx_free(*parentid);
- zbx_free(*path);
- zbx_free(id_esc);
- ret = FAIL;
- break;
- }
-
- zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_GET_RESOURCEPOOL_PARENTID("%s"), id_esc);
- id = zbx_xml_doc_read_value(xdoc , tmp);
-
- if (NULL != id) /* we do not include the last default 'ResourcePool' */
- {
- if (NULL == *path)
- {
- *path = name;
- name = NULL;
- }
- else
- *path = zbx_dsprintf(*path, "%s/%s", name, *path);
-
- }
- else
- zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID("%s"), id_esc);
-
- zbx_free(id_esc);
- zbx_free(name);
- }
- while (NULL != id);
-
- if (SUCCEED == ret)
- {
- if (NULL != *path && NULL == (*parentid = zbx_xml_doc_read_value(xdoc , tmp)))
- zbx_free(*path);
-
- if (NULL == *path)
- ret = FAIL;
- }
-
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s resource pool path: '%s', parentid: '%s'", __func__,
- zbx_result_string(ret), ZBX_NULL2EMPTY_STR(*path), ZBX_NULL2EMPTY_STR(*parentid));
-
- return ret;
-}
-
-/******************************************************************************
- * *
* Purpose: get alarm details *
* *
* Parameters: service - [IN] the vmware service *
@@ -4363,7 +4308,7 @@ static zbx_vmware_vm_t *vmware_service_create_vm(zbx_vmware_service_t *service,
rpool_cmp.id = vm->props[ZBX_VMWARE_VMPROP_RESOURCEPOOL];
if (FAIL != (i = zbx_vector_vmware_resourcepool_bsearch(rpools, &rpool_cmp,
- vmware_resourcepool_compare_id)))
+ ZBX_DEFAULT_STR_PTR_COMPARE_FUNC)))
{
rpools->values[i]->vm_num += 1;
}
@@ -5279,7 +5224,7 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
zbx_free(hvid_esc);
zbx_free(scsi_req);
- if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, &iter, &doc, error)))
+ if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, __func__, &iter, &doc, error)))
goto out;
updated += vmware_service_hv_disks_parse_info(doc, dss, disks_info);
@@ -5289,7 +5234,7 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
zbx_xml_free_doc(doc);
doc = NULL;
- if (SUCCEED != (ret = zbx_property_collection_next(iter, &doc, error)))
+ if (SUCCEED != (ret = zbx_property_collection_next(__func__, iter, &doc, error)))
goto out;
updated += vmware_service_hv_disks_parse_info(doc, dss, disks_info);
@@ -5306,7 +5251,8 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
"<ns0:pathSet>config.vsanHostConfig.storageInfo.diskMapping</ns0:pathSet>", hvid_esc);
zbx_free(hvid_esc);
- if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, &iter, &doc_dinfo, &err)))
+ if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, __func__, &iter, &doc_dinfo,
+ &err)))
{
zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot get vsan disk_info:%s", __func__, err);
zbx_str_free(err);
@@ -5320,7 +5266,7 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
zbx_xml_free_doc(doc_dinfo);
doc_dinfo = NULL;
- if (SUCCEED != (ret = zbx_property_collection_next(iter, &doc_dinfo, error)))
+ if (SUCCEED != (ret = zbx_property_collection_next(__func__, iter, &doc_dinfo, error)))
goto out;
updated_vsan += vmware_service_hv_vsan_parse_info(doc_dinfo, vsan_uuid, disks_info);
@@ -5862,7 +5808,7 @@ static int vmware_hv_ds_access_update(zbx_vmware_service_t *service, CURL *easyh
zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_HV_DS_ACCESS, pcollector, hvid_esc, hvid_esc, hvid_esc, hvid_esc);
zbx_free(hvid_esc);
- if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, &iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, __func__, &iter, &doc, error))
goto out;
updated += vmware_hv_ds_access_parse(doc, hv_dss, hv_uuid, hv_id, dss);
@@ -5872,7 +5818,7 @@ static int vmware_hv_ds_access_update(zbx_vmware_service_t *service, CURL *easyh
zbx_xml_free_doc(doc);
doc = NULL;
- if (SUCCEED != zbx_property_collection_next(iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_next(__func__, iter, &doc, error))
goto out;
updated += vmware_hv_ds_access_parse(doc, hv_dss, hv_uuid, hv_id, dss);
@@ -6007,19 +5953,6 @@ static const char *vmware_hv_vsan_uuid(zbx_vector_vmware_datastore_t *dss, zbx_v
/******************************************************************************
* *
- * Purpose: sorting function to sort Resource pool names vector by name *
- * *
- ******************************************************************************/
-int vmware_resourcepool_compare_id(const void *r1, const void *r2)
-{
- const zbx_vmware_resourcepool_t *rp1 = *(const zbx_vmware_resourcepool_t * const *)r1;
- const zbx_vmware_resourcepool_t *rp2 = *(const zbx_vmware_resourcepool_t * const *)r2;
-
- return strcmp(rp1->id, rp2->id);
-}
-
-/******************************************************************************
- * *
* Function: vmware_service_init_hv *
* *
* Purpose: initialize vmware hypervisor object *
@@ -6600,7 +6533,7 @@ static int vmware_service_get_hv_ds_dc_dvs_list(const zbx_vmware_service_t *serv
zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VCENTER_HV_DS_LIST, pcollector,
vmware_service_objects[service->type].root_folder);
- if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, &iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, __func__, &iter, &doc, error))
goto out;
if (ZBX_VMWARE_TYPE_VCENTER == service->type)
@@ -6625,7 +6558,7 @@ static int vmware_service_get_hv_ds_dc_dvs_list(const zbx_vmware_service_t *serv
zbx_xml_free_doc(doc);
doc = NULL;
- if (SUCCEED != zbx_property_collection_next(iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_next(__func__, iter, &doc, error))
goto out;
if (ZBX_VMWARE_TYPE_VCENTER == service->type)
@@ -7366,15 +7299,256 @@ out:
* *
* Purpose: retrieves a list of vmware service clusters and resource pools *
* *
+ * Parameters: service - [IN] the vmware service *
+ * easyhandle - [IN] the CURL handle *
+ * cluster_data - [OUT] a pointer to the output variable *
+ * clusters - [OUT] a pointer to the resulting clusters *
+ * vector *
+ * rp_chunks - [OUT] a pointer to the resulting resource pool *
+ * vector *
+ * alarms_data - [OUT] the vector with all alarms *
+ * error - [OUT] the error message in the case of failure *
+ * *
+ * Return value: SUCCEED - the operation has completed successfully *
+ * FAIL - the operation has failed *
+ * *
+ ******************************************************************************/
+static int vmware_service_process_cluster_data(zbx_vmware_service_t *service, CURL *easyhandle,
+ xmlDoc *cluster_data, zbx_vector_ptr_t *clusters, zbx_vector_vmware_rpool_chunk_t *rp_chunks,
+ zbx_vmware_alarms_data_t *alarms_data, char **error)
+{
+#define ZBX_XPATH_GET_RESOURCEPOOL_PARENTID \
+ ZBX_XPATH_PROP_NAME_NODE("parent") "[@type='ResourcePool']"
+#define ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID \
+ ZBX_XPATH_PROP_NAME_NODE("parent") "[@type!='ResourcePool']"
+
+ int ret, i;
+ char *id_esc, tmp[MAX_STRING_LEN * 2];
+ zbx_vmware_cluster_t *cluster;
+ zbx_vector_str_t rp_ids, ids;
+ xmlNode *node;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
+
+ zbx_vector_str_create(&ids);
+
+ zbx_xml_read_values(cluster_data, ZBX_XPATH_OBJS_BY_TYPE(ZBX_VMWARE_SOAP_CLUSTER), &ids);
+ zbx_vector_ptr_reserve(clusters, (size_t)(clusters->values_alloc + ids.values_num));
+
+ for (i = 0; i < ids.values_num; i++)
+ {
+ char *name;
+
+ id_esc = zbx_xml_escape_dyn(ids.values[i]);
+ zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_CLUSTER, "[text()='%s']"),
+ id_esc);
+ zbx_str_free(id_esc);
+
+ if (NULL == (node = zbx_xml_doc_get(cluster_data, tmp)) ||
+ NULL == (name = zbx_xml_node_read_value(cluster_data, node,
+ ZBX_XPATH_PROP_NAME_NODE("name"))))
+ {
+ continue;
+ }
+
+ cluster = (zbx_vmware_cluster_t *)zbx_malloc(NULL, sizeof(zbx_vmware_cluster_t));
+ cluster->id = zbx_strdup(NULL, ids.values[i]);
+ cluster->name = name;
+ cluster->status = NULL;
+ zbx_vector_str_create(&cluster->dss_uuid);
+ zbx_vector_str_create(&cluster->alarm_ids);
+
+ if (SUCCEED != vmware_service_get_alarms_data(__func__, service, easyhandle, cluster_data,
+ zbx_xml_node_get(cluster_data, node, ZBX_XPATH_PROP_NAME_NODE("triggeredAlarmState")),
+ &cluster->alarm_ids, alarms_data, error))
+ {
+ vmware_cluster_free(cluster);
+ ret = FAIL;
+ goto out;
+ }
+
+ zbx_vector_ptr_append(clusters, cluster);
+ }
+
+ zbx_vector_str_create(&rp_ids);
+ zbx_xml_read_values(cluster_data, ZBX_XPATH_OBJS_BY_TYPE(ZBX_VMWARE_SOAP_RESOURCEPOOL), &rp_ids);
+ zbx_vector_vmware_rpool_chunk_reserve(rp_chunks, (size_t)(rp_chunks->values_num + rp_ids.values_num));
+
+ for (i = 0; i < rp_ids.values_num; i++)
+ {
+ zbx_vmware_rpool_chunk_t *rp_chunk;
+
+ rp_chunk = (zbx_vmware_rpool_chunk_t *)zbx_malloc(NULL, sizeof(zbx_vmware_rpool_chunk_t));
+
+ id_esc = zbx_xml_escape_dyn(rp_ids.values[i]);
+ zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_RESOURCEPOOL, "[text()='%s']"),
+ id_esc);
+ zbx_str_free(id_esc);
+
+ if (NULL == (node = zbx_xml_doc_get(cluster_data, tmp)) || NULL == (
+ rp_chunk->name = zbx_xml_node_read_value(cluster_data, node,
+ ZBX_XPATH_PROP_NAME_NODE("name"))))
+ {
+ zbx_free(rp_chunk);
+ continue;
+ }
+
+ if (NULL == (rp_chunk->first_parentid = zbx_xml_node_read_value(cluster_data , node,
+ ZBX_XPATH_GET_RESOURCEPOOL_PARENTID)))
+ {
+ if (NULL == (rp_chunk->first_parentid = zbx_xml_node_read_value(cluster_data , node,
+ ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID)))
+ {
+ zbx_free(rp_chunk->name);
+ zbx_free(rp_chunk);
+ continue;
+ }
+
+ rp_chunk->parent_is_rp = 0;
+ }
+ else
+ rp_chunk->parent_is_rp = 1;
+
+ rp_chunk->id = zbx_strdup(NULL, rp_ids.values[i]);
+ rp_chunk->path = rp_chunk->parentid = NULL;
+ zbx_vector_vmware_rpool_chunk_append(rp_chunks, rp_chunk);
+ }
+
+ zbx_vector_str_clear_ext(&rp_ids, zbx_str_free);
+ zbx_vector_str_destroy(&rp_ids);
+
+ ret = SUCCEED;
+out:
+ zbx_vector_str_clear_ext(&ids, zbx_str_free);
+ zbx_vector_str_destroy(&ids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s cl:%d rp:%d", __func__, zbx_result_string(ret),
+ clusters->values_num, rp_chunks->values_num);
+
+ return ret;
+
+#undef ZBX_XPATH_GET_RESOURCEPOOL_PARENTID
+#undef ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID
+}
+
+/******************************************************************************
+ * *
+ * Purpose: retrieves status of the specified vmware cluster *
+ * *
* Parameters: easyhandle - [IN] the CURL handle *
- * data - [OUT] a pointer to the output variable *
+ * datastores - [IN] all available Datastores *
+ * cluster - [IN/OUT] the cluster *
+ * cq_values - [IN/OUT] the vector with custom query entries *
* error - [OUT] the error message in the case of failure *
* *
* Return value: SUCCEED - the operation has completed successfully *
* FAIL - the operation has failed *
* *
******************************************************************************/
-static int vmware_service_get_cluster_data(CURL *easyhandle, xmlDoc **data, char **error)
+static int vmware_service_get_cluster_state(CURL *easyhandle, const zbx_vector_vmware_datastore_t *datastores,
+ zbx_vmware_cluster_t *cluster, zbx_vector_cq_value_t *cq_values, char **error)
+{
+# define ZBX_POST_VMWARE_CLUSTER_STATUS \
+ ZBX_POST_VSPHERE_HEADER \
+ "<ns0:RetrievePropertiesEx>" \
+ "<ns0:_this type=\"PropertyCollector\">propertyCollector</ns0:_this>" \
+ "<ns0:specSet>" \
+ "<ns0:propSet>" \
+ "<ns0:type>ClusterComputeResource</ns0:type>" \
+ "<ns0:all>false</ns0:all>" \
+ "<ns0:pathSet>summary.overallStatus</ns0:pathSet>" \
+ "<ns0:pathSet>datastore</ns0:pathSet>" \
+ "%s" \
+ "</ns0:propSet>" \
+ "<ns0:objectSet>" \
+ "<ns0:obj type=\"ClusterComputeResource\">%s</ns0:obj>" \
+ "</ns0:objectSet>" \
+ "</ns0:specSet>" \
+ "<ns0:options></ns0:options>" \
+ "</ns0:RetrievePropertiesEx>" \
+ ZBX_POST_VSPHERE_FOOTER
+
+ char *tmp, *clusterid_esc, *cq_prop;
+ int i, ret;
+ xmlDoc *doc = NULL;
+ zbx_vector_cq_value_t cqvs;
+ zbx_vector_str_t ids;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s() clusterid:'%s'", __func__, cluster->id);
+
+ zbx_vector_str_create(&ids);
+ zbx_vector_cq_value_create(&cqvs);
+ clusterid_esc = zbx_xml_escape_dyn(cluster->id);
+ cq_prop = vmware_cq_prop_soap_request(cq_values, ZBX_VMWARE_SOAP_CLUSTER, cluster->id, &cqvs);
+
+ tmp = zbx_dsprintf(NULL, ZBX_POST_VMWARE_CLUSTER_STATUS, cq_prop, clusterid_esc);
+
+ zbx_str_free(cq_prop);
+ zbx_str_free(clusterid_esc);
+ ret = zbx_soap_post(__func__, easyhandle, tmp, &doc, NULL, error);
+ zbx_str_free(tmp);
+
+ if (FAIL == ret)
+ goto out;
+
+ cluster->status = zbx_xml_doc_read_value(doc, ZBX_XPATH_PROP_NAME("summary.overallStatus"));
+
+ if (0 != cqvs.values_num)
+ vmware_service_cq_prop_value(__func__, doc, &cqvs);
+
+ zbx_xml_read_values(doc, ZBX_XPATH_PROP_NAME("datastore") "/*", &ids);
+
+ for (i = 0; i < ids.values_num; i++)
+ {
+ int j;
+ zbx_vmware_datastore_t ds_cmp;
+
+ ds_cmp.id = ids.values[i];
+
+ if (FAIL == (j = zbx_vector_vmware_datastore_bsearch(datastores, &ds_cmp, vmware_ds_id_compare)))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s(): Datastore \"%s\" not found on cluster \"%s\".", __func__,
+ ds_cmp.id, cluster->id);
+ continue;
+ }
+
+ zbx_vector_str_append(&cluster->dss_uuid, zbx_strdup(NULL, datastores->values[j]->uuid));
+ }
+out:
+ zbx_vector_cq_value_destroy(&cqvs);
+ zbx_vector_str_clear_ext(&ids, zbx_str_free);
+ zbx_vector_str_destroy(&ids);
+ zbx_xml_free_doc(doc);
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
+
+ return ret;
+
+# undef ZBX_POST_VMWARE_CLUSTER_STATUS
+}
+
+/******************************************************************************
+ * *
+ * Purpose: creates lists of vmware cluster and resource pool objects *
+ * *
+ * Parameters: service - [IN] the vmware service *
+ * easyhandle - [IN] the CURL handle *
+ * datastores - [IN] all available Datastores *
+ * cq_values - [IN/OUT] the vector with custom query entries *
+ * clusters - [OUT] a pointer to the resulting clusters *
+ * vector *
+ * resourcepools - [OUT] a pointer to the resulting resource pool *
+ * vector *
+ * alarms_data - [OUT] the vector with all alarms *
+ * error - [OUT] the error message in the case of failure *
+ * *
+ * Return value: SUCCEED - the operation has completed successfully *
+ * FAIL - the operation has failed *
+ * *
+ ******************************************************************************/
+static int vmware_service_get_clusters_and_resourcepools(zbx_vmware_service_t *service, CURL *easyhandle,
+ const zbx_vector_vmware_datastore_t *datastores, zbx_vector_cq_value_t *cq_values,
+ zbx_vector_ptr_t *clusters, zbx_vector_vmware_resourcepool_t *resourcepools,
+ zbx_vmware_alarms_data_t *alarms_data, char **error)
{
# define ZBX_POST_VCENTER_CLUSTER \
ZBX_POST_VSPHERE_HEADER \
@@ -7384,15 +7558,9 @@ static int vmware_service_get_cluster_data(CURL *easyhandle, xmlDoc **data, char
"<ns0:propSet>" \
"<ns0:type>ClusterComputeResource</ns0:type>" \
"<ns0:pathSet>name</ns0:pathSet>" \
- "<ns0:pathSet>resourcePool</ns0:pathSet>" \
"<ns0:pathSet>triggeredAlarmState</ns0:pathSet>" \
"</ns0:propSet>" \
"<ns0:propSet>" \
- "<ns0:type>ComputeResource</ns0:type>" \
- "<ns0:pathSet>resourcePool</ns0:pathSet>" \
- "<ns0:pathSet>name</ns0:pathSet>" \
- "</ns0:propSet>" \
- "<ns0:propSet>" \
"<ns0:type>ResourcePool</ns0:type>" \
"<ns0:pathSet>resourcePool</ns0:pathSet>" \
"<ns0:pathSet>name</ns0:pathSet>" \
@@ -7521,243 +7689,113 @@ static int vmware_service_get_cluster_data(CURL *easyhandle, xmlDoc **data, char
"</ns0:RetrievePropertiesEx>" \
ZBX_POST_VSPHERE_FOOTER
- int ret = FAIL;
+ int i, ret = FAIL;
+ xmlDoc *cluster_data = NULL;
+ zbx_property_collection_iter *iter = NULL;
+ zbx_vector_vmware_rpool_chunk_t rp_chunks;
+ zbx_vector_ptr_t cl_chunks;
zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
- if (SUCCEED != zbx_soap_post(__func__, easyhandle, ZBX_POST_VCENTER_CLUSTER, data, NULL, error))
- goto out;
-
- ret = SUCCEED;
-out:
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
-
- return ret;
-
-# undef ZBX_POST_VCENTER_CLUSTER
-}
-
-/******************************************************************************
- * *
- * Purpose: retrieves status of the specified vmware cluster *
- * *
- * Parameters: easyhandle - [IN] the CURL handle *
- * clusterid - [IN] the cluster id *
- * datastores - [IN] all available Datastores *
- * cq_values - [IN/OUT] the vector with custom query entries *
- * status - [OUT] a pointer to the output variable *
- * dss - [OUT] a list of DS available for cluster *
- * error - [OUT] the error message in the case of failure *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-static int vmware_service_get_cluster_state(CURL *easyhandle, const char *clusterid,
- const zbx_vector_vmware_datastore_t *datastores, zbx_vector_cq_value_t *cq_values, char **status,
- zbx_vector_str_t *dss, char **error)
-{
-# define ZBX_POST_VMWARE_CLUSTER_STATUS \
- ZBX_POST_VSPHERE_HEADER \
- "<ns0:RetrievePropertiesEx>" \
- "<ns0:_this type=\"PropertyCollector\">propertyCollector</ns0:_this>" \
- "<ns0:specSet>" \
- "<ns0:propSet>" \
- "<ns0:type>ClusterComputeResource</ns0:type>" \
- "<ns0:all>false</ns0:all>" \
- "<ns0:pathSet>summary.overallStatus</ns0:pathSet>" \
- "<ns0:pathSet>datastore</ns0:pathSet>" \
- "%s" \
- "</ns0:propSet>" \
- "<ns0:objectSet>" \
- "<ns0:obj type=\"ClusterComputeResource\">%s</ns0:obj>" \
- "</ns0:objectSet>" \
- "</ns0:specSet>" \
- "<ns0:options></ns0:options>" \
- "</ns0:RetrievePropertiesEx>" \
- ZBX_POST_VSPHERE_FOOTER
-
- char *tmp, *clusterid_esc, *cq_prop;
- int i, ret = FAIL;
- xmlDoc *doc = NULL;
- zbx_vector_cq_value_t cqvs;
- zbx_vector_str_t ids;
-
- zabbix_log(LOG_LEVEL_DEBUG, "In %s() clusterid:'%s'", __func__, clusterid);
-
- zbx_vector_str_create(&ids);
- zbx_vector_cq_value_create(&cqvs);
- clusterid_esc = zbx_xml_escape_dyn(clusterid);
- cq_prop = vmware_cq_prop_soap_request(cq_values, ZBX_VMWARE_SOAP_CLUSTER, clusterid, &cqvs);
-
- tmp = zbx_dsprintf(NULL, ZBX_POST_VMWARE_CLUSTER_STATUS, cq_prop, clusterid_esc);
-
- zbx_str_free(cq_prop);
- zbx_str_free(clusterid_esc);
- ret = zbx_soap_post(__func__, easyhandle, tmp, &doc, NULL, error);
- zbx_str_free(tmp);
+ zbx_vector_vmware_rpool_chunk_create(&rp_chunks);
+ zbx_vector_ptr_create(&cl_chunks);
- if (FAIL == ret)
+ if (SUCCEED != zbx_property_collection_init(easyhandle, ZBX_POST_VCENTER_CLUSTER, "propertyCollector",
+ __func__, &iter, &cluster_data, error))
+ {
goto out;
+ }
- *status = zbx_xml_doc_read_value(doc, ZBX_XPATH_PROP_NAME("summary.overallStatus"));
-
- if (0 != cqvs.values_num)
- vmware_service_cq_prop_value(__func__, doc, &cqvs);
-
- zbx_xml_read_values(doc, ZBX_XPATH_PROP_NAME("datastore") "/*", &ids);
+ if (SUCCEED != vmware_service_process_cluster_data(service, easyhandle, cluster_data, &cl_chunks, &rp_chunks,
+ alarms_data, error))
+ {
+ goto out;
+ }
- for (i = 0; i < ids.values_num; i++)
+ while (NULL != iter->token)
{
- int j;
- zbx_vmware_datastore_t ds_cmp;
+ zbx_xml_free_doc(cluster_data);
+ cluster_data = NULL;
- ds_cmp.id = ids.values[i];
+ if (SUCCEED != zbx_property_collection_next(__func__, iter, &cluster_data, error))
+ goto out;
- if (FAIL == (j = zbx_vector_vmware_datastore_bsearch(datastores, &ds_cmp, vmware_ds_id_compare)))
+ if (SUCCEED != vmware_service_process_cluster_data(service, easyhandle, cluster_data, &cl_chunks,
+ &rp_chunks, alarms_data, error))
{
- zabbix_log(LOG_LEVEL_DEBUG, "%s(): Datastore \"%s\" not found on cluster \"%s\".", __func__,
- ds_cmp.id, clusterid);
- continue;
+ goto out;
}
-
- zbx_vector_str_append(dss, zbx_strdup(NULL, datastores->values[j]->uuid));
}
-out:
- zbx_vector_cq_value_destroy(&cqvs);
- zbx_vector_str_clear_ext(&ids, zbx_str_free);
- zbx_vector_str_destroy(&ids);
- zbx_xml_free_doc(doc);
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
-
- return ret;
-
-# undef ZBX_POST_VMWARE_CLUSTER_STATUS
-}
-/******************************************************************************
- * *
- * Purpose: creates lists of vmware cluster and resource pool objects *
- * *
- * Parameters: service - [IN] the vmware service *
- * easyhandle - [IN] the CURL handle *
- * datastores - [IN] all available Datastores *
- * cq_values - [IN/OUT] the vector with custom query entries *
- * clusters - [OUT] a pointer to the resulting clusters *
- * vector *
- * resourcepools - [OUT] a pointer to the resulting resource pool *
- * vector *
- * alarms_data - [OUT] the vector with all alarms *
- * error - [OUT] the error message in the case of failure *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-static int vmware_service_get_clusters_and_resourcepools(zbx_vmware_service_t *service, CURL *easyhandle,
- const zbx_vector_vmware_datastore_t *datastores, zbx_vector_cq_value_t *cq_values,
- zbx_vector_ptr_t *clusters, zbx_vector_vmware_resourcepool_t *resourcepools,
- zbx_vmware_alarms_data_t *alarms_data, char **error)
-{
- char xpath[MAX_STRING_LEN];
- int i, ret = FAIL;
- xmlDoc *cluster_data = NULL;
- zbx_vector_str_t ids, rpools_all, rpools_uniq, dss;
- zbx_vmware_cluster_t *cluster;
-
- zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
-
- zbx_vector_str_create(&ids);
- zbx_vector_str_create(&dss);
-
- if (SUCCEED != vmware_service_get_cluster_data(easyhandle, &cluster_data, error))
- goto out;
-
- zbx_xml_read_values(cluster_data, ZBX_XPATH_OBJS_BY_TYPE(ZBX_VMWARE_SOAP_CLUSTER), &ids);
- zbx_vector_ptr_reserve(clusters, (size_t)(ids.values_num + clusters->values_alloc));
+ zbx_property_collection_free(iter);
+ zbx_vector_vmware_rpool_chunk_sort(&rp_chunks, ZBX_DEFAULT_STR_PTR_COMPARE_FUNC);
- for (i = 0; i < ids.values_num; i++)
+ for (i = 0; i < rp_chunks.values_num; i++)
{
- char *status, *name;
-
- zbx_snprintf(xpath, sizeof(xpath), ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_CLUSTER, "[text()='%s']")
- "/" ZBX_XPATH_PROP_NAME_NODE("name"), ids.values[i]);
+ int k;
+ zbx_vmware_resourcepool_t *rpool;
+ zbx_vmware_rpool_chunk_t rp_parent, *rp_chunk = rp_chunks.values[i];
- if (NULL == (name = zbx_xml_doc_read_value(cluster_data, xpath)))
+ if (0 == rp_chunk->parent_is_rp) /* skipped the top (default) resource pool name */
continue;
- if (SUCCEED != vmware_service_get_cluster_state(easyhandle, ids.values[i], datastores, cq_values,
- &status, &dss, error))
- {
- zbx_free(name);
- goto out;
- }
+ rpool = (zbx_vmware_resourcepool_t*)zbx_malloc(NULL, sizeof(zbx_vmware_resourcepool_t));
+ rpool->id = zbx_strdup(NULL, rp_chunk->id);
+ rpool->path = zbx_strdup(NULL, rp_chunk->name);
+ rpool->vm_num = 0;
- cluster = (zbx_vmware_cluster_t *)zbx_malloc(NULL, sizeof(zbx_vmware_cluster_t));
- cluster->id = zbx_strdup(NULL, ids.values[i]);
- cluster->name = name;
- cluster->status = status;
- zbx_vector_str_create(&cluster->dss_uuid);
- zbx_vector_str_append_array(&cluster->dss_uuid, dss.values, dss.values_num);
- zbx_vector_str_clear(&dss);
- zbx_vector_str_create(&cluster->alarm_ids);
+ rp_parent.id = rp_chunk->first_parentid;
- if (FAIL == vmware_service_get_alarms_data(__func__, service, easyhandle, cluster_data, NULL,
- &cluster->alarm_ids, alarms_data, error))
+ while (FAIL != (k = zbx_vector_vmware_rpool_chunk_bsearch(&rp_chunks, &rp_parent,
+ ZBX_DEFAULT_STR_PTR_COMPARE_FUNC)))
{
- vmware_cluster_free(cluster);
- goto out;
- }
+ zbx_vmware_rpool_chunk_t *rp_next = rp_chunks.values[k];
- zbx_vector_ptr_append(clusters, cluster);
- }
+ if (NULL != rp_next->path)
+ rpool->path = zbx_dsprintf(rpool->path, "%s/%s", rp_next->path, rpool->path);
- /* Add resource pools */
+ if (0 == rp_next->parent_is_rp || NULL != rp_next->path)
+ {
+ rpool->parentid = zbx_strdup(NULL, 0 == rp_next->parent_is_rp ?
+ rp_next->first_parentid : rp_next->parentid);
+ zbx_vector_vmware_resourcepool_append(resourcepools, rpool);
+ rp_chunk->path = rpool->path;
+ rp_chunk->parentid = rpool->parentid;
+ break;
+ }
- zbx_vector_str_create(&rpools_all);
- zbx_vector_str_create(&rpools_uniq);
- zbx_xml_read_values(cluster_data, "//*[@type='ResourcePool']", &rpools_all);
- zbx_vector_str_sort(&rpools_all, ZBX_DEFAULT_STR_COMPARE_FUNC);
- zbx_vector_str_append_array(&rpools_uniq, rpools_all.values, rpools_all.values_num);
- zbx_vector_str_uniq(&rpools_uniq, ZBX_DEFAULT_STR_COMPARE_FUNC);
- zbx_vector_vmware_resourcepool_reserve(resourcepools, (size_t)rpools_all.values_num);
+ rpool->path = zbx_dsprintf(rpool->path, "%s/%s", rp_next->name, rpool->path);
+ rp_parent.id = rp_next->first_parentid;
+ }
+ }
- for (i = 0; i < rpools_uniq.values_num; i++)
+ zbx_vector_vmware_resourcepool_sort(resourcepools, ZBX_DEFAULT_STR_PTR_COMPARE_FUNC);
+ zbx_vector_ptr_reserve(clusters, (size_t)(clusters->values_alloc + cl_chunks.values_num));
+
+ for (i = cl_chunks.values_num - 1; i >= 0 ; i--)
{
- zbx_vmware_resourcepool_t *rpool;
- char *path, *parentid;
- const char *id = rpools_uniq.values[i];
+ zbx_vmware_cluster_t *cluster = (zbx_vmware_cluster_t*)(cl_chunks.values[i]);
- if (SUCCEED != vmware_service_get_resourcepool_data(cluster_data, id, &parentid, &path))
- {
- zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find resource pool name for id:%s", __func__, id);
- continue;
- }
+ if (SUCCEED != vmware_service_get_cluster_state(easyhandle, datastores, cluster, cq_values, error))
+ goto out;
- rpool = (zbx_vmware_resourcepool_t *)zbx_malloc(NULL, sizeof(zbx_vmware_resourcepool_t));
- rpool->id = zbx_strdup(NULL, id);
- rpool->path = path;
- rpool->parentid = parentid;
- rpool->vm_num = 0;
- zbx_vector_vmware_resourcepool_append(resourcepools, rpool);
+ zbx_vector_ptr_append(clusters, cluster);
+ zbx_vector_ptr_remove_noorder(&cl_chunks, i);
}
- zbx_vector_vmware_resourcepool_sort(resourcepools, vmware_resourcepool_compare_id);
- zbx_vector_str_clear_ext(&rpools_all, zbx_str_free);
- zbx_vector_str_destroy(&rpools_all);
- zbx_vector_str_destroy(&rpools_uniq);
-
ret = SUCCEED;
out:
zbx_xml_free_doc(cluster_data);
- zbx_vector_str_clear_ext(&ids, zbx_str_free);
- zbx_vector_str_destroy(&ids);
- zbx_vector_str_destroy(&dss);
+ zbx_vector_vmware_rpool_chunk_clear_ext(&rp_chunks, vmware_rp_chunk_free);
+ zbx_vector_vmware_rpool_chunk_destroy(&rp_chunks);
+ zbx_vector_ptr_clear_ext(&cl_chunks, (zbx_clean_func_t)vmware_cluster_free);
+ zbx_vector_ptr_destroy(&cl_chunks);
zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s found cl:%d rp:%d", __func__, zbx_result_string(ret),
clusters->values_num, resourcepools->values_num);
return ret;
+# undef ZBX_POST_VCENTER_CLUSTER
}
/******************************************************************************
diff --git a/src/zabbix_server/vmware/vmware.h b/src/zabbix_server/vmware/vmware.h
index 15adb060d09..68e95685654 100644
--- a/src/zabbix_server/vmware/vmware.h
+++ b/src/zabbix_server/vmware/vmware.h
@@ -341,7 +341,6 @@ typedef struct
}
zbx_vmware_resourcepool_t;
-int vmware_resourcepool_compare_id(const void *r1, const void *r2);
ZBX_PTR_VECTOR_DECL(vmware_resourcepool, zbx_vmware_resourcepool_t *)
/* the vmware eventlog state */
diff --git a/src/zabbix_server/vmware/vmware_rest.c b/src/zabbix_server/vmware/vmware_rest.c
index 19665791ae5..78245603fda 100644
--- a/src/zabbix_server/vmware/vmware_rest.c
+++ b/src/zabbix_server/vmware/vmware_rest.c
@@ -510,8 +510,8 @@ static void vmware_service_rest_logout(CURL *easyhandle, ZBX_HTTPPAGE *page)
zbx_snprintf(tmp, sizeof(tmp),"%s/session", page->url);
if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_URL, tmp)) ||
- CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_CUSTOMREQUEST, "DELETE")) ||
- CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POST, 0L)))
+ CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POST, 0L)) ||
+ CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_CUSTOMREQUEST, "DELETE")))
{
zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot set cURL option %d: %s.",
__func__, (int)opt, curl_easy_strerror(err));
diff --git a/templates/module/process/README.md b/templates/module/process/README.md
new file mode 100644
index 00000000000..5e93efb2585
--- /dev/null
+++ b/templates/module/process/README.md
@@ -0,0 +1,77 @@
+
+# OS processes by Zabbix agent
+
+## Overview
+
+For Zabbix version: 6.4 and higher.
+This template is designed to monitor processes by Zabbix that work without any external scripts.
+Most of the metrics are collected in one go, thanks to Zabbix bulk data collection.
+For example, by specifying "zabbix" as macro value, you can monitor all zabbix processes.
+
+
+
+This template was tested on:
+
+- CentOS, version CentOS Linux 8;
+- Ubuntu, version Ubuntu 22.04.1 LTS.
+
+## Setup
+
+> See [Zabbix template operation](https://www.zabbix.com/documentation/6.4/manual/config/templates_out_of_the_box/zabbix_agent) for basic instructions.
+
+Install and setup [Zabbix agent](https://www.zabbix.com/documentation/6.4/manual/installation/install_from_packages).
+
+Custom processes set in macros:
+
+- {$PROC.NAME.MATCHES}
+- {$PROC.NAME.NOT_MATCHES}
+
+
+## Zabbix configuration
+
+No specific Zabbix configuration is required.
+
+### Macros used
+
+|Name|Description|Default|
+|----|-----------|-------|
+|{$PROC.NAME.MATCHES} |<p>This macro is used in the discovery of processes. It can be overridden on a host-level or on a linked template-level.</p> |`<CHANGE VALUE>` |
+|{$PROC.NAME.NOT_MATCHES} |<p>This macro is used in the discovery of processes. It can be overridden on a host-level or on a linked template-level.</p> |`<CHANGE VALUE>` |
+
+## Template links
+
+There are no template links in this template.
+
+## Discovery rules
+
+|Name|Description|Type|Key and additional info|
+|----|-----------|----|----|
+|Processes discovery |<p>Discovery of OS summary processes.</p> |DEPENDENT |custom.proc.discovery<p>**Filter**:</p>AND <p>- {#VMEM} NOT_MATCHES_REGEX `-1`</p><p>- {#NAME} MATCHES_REGEX `{$PROC.NAME.MATCHES}`</p><p>- {#NAME} NOT_MATCHES_REGEX `{$PROC.NAME.NOT_MATCHES}`</p> |
+
+## Items collected
+
+|Group|Name|Description|Type|Key and additional info|
+|-----|----|-----------|----|---------------------|
+|OS |Process [{#NAME}]: Get data |<p>Summary metrics collected during the process {#NAME}.</p> |DEPENDENT |custom.proc.get[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.[?(@["name"]=="{#NAME}")].first()`</p><p>⛔️ON_FAIL: `CUSTOM_VALUE -> Failed to retrieve process {#NAME} data`</p> |
+|OS |Process [{#NAME}]: Memory usage (rss) |<p>The summary of Resident Set Size (RSS) memory used by the process {#NAME} in bytes.</p> |DEPENDENT |custom.proc.rss[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.rss`</p><p>⛔️ON_FAIL: `DISCARD_VALUE -> `</p> |
+|OS |Process [{#NAME}]: Memory usage (vsize) |<p>The summary of virtual memory used by process {#NAME} in bytes.</p> |DEPENDENT |custom.proc.vmem[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.vsize`</p><p>⛔️ON_FAIL: `DISCARD_VALUE -> `</p> |
+|OS |Process [{#NAME}]: Memory usage, % |<p>The percentage of real memory used by the process {#NAME}.</p> |DEPENDENT |custom.proc.pmem[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.pmem`</p><p>⛔️ON_FAIL: `DISCARD_VALUE -> `</p> |
+|OS |Process [{#NAME}]: Number of running processes |<p>The number of running processes {#NAME}.</p> |DEPENDENT |custom.proc.num[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.processes`</p><p>⛔️ON_FAIL: `CUSTOM_VALUE -> 0`</p><p>- DISCARD_UNCHANGED_HEARTBEAT: `1h`</p> |
+|OS |Process [{#NAME}]: Number of threads |<p>The number of threads {#NAME}.</p> |DEPENDENT |custom.proc.thread[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.threads`</p><p>⛔️ON_FAIL: `DISCARD_VALUE -> `</p> |
+|OS |Process [{#NAME}]: Number of page faults |<p>The number of page faults {#NAME}.</p> |DEPENDENT |custom.proc.page[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.page_faults`</p><p>⛔️ON_FAIL: `DISCARD_VALUE -> `</p> |
+|OS |Process [{#NAME}]: Size of locked memory |<p>The size of locked memory {#NAME}.</p> |DEPENDENT |custom.proc.mem.locked[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.lck`</p><p>⛔️ON_FAIL: `DISCARD_VALUE -> `</p> |
+|OS |Process [{#NAME}]: Swap space used |<p>The swap space used by {#NAME}.</p> |DEPENDENT |custom.proc.swap[{#NAME}]<p>**Preprocessing**:</p><p>- JSONPATH: `$.swap`</p><p>⛔️ON_FAIL: `DISCARD_VALUE -> `</p> |
+|Zabbix raw items |OS: Get process summary |<p>The summary of data metrics for all processes.</p> |ZABBIX_PASSIVE |proc.get[,,,summary] |
+
+## Triggers
+
+|Name|Description|Expression|Severity|Dependencies and additional info|
+|----|-----------|----|----|----|
+|Process [{#NAME}]: is not running |<p>-</p> |`last(/OS processes by Zabbix agent/custom.proc.num[{#NAME}])=0` |HIGH |<p>Manual close: YES</p> |
+
+## Feedback
+
+Please report any issues with the template at https://support.zabbix.com.
+
+You can also provide feedback, discuss the template, or ask for help at [ZABBIX forums](https://www.zabbix.com/forum/zabbix-suggestions-and-feedback).
+
diff --git a/templates/module/process/template_module_process.yaml b/templates/module/process/template_module_process.yaml
new file mode 100644
index 00000000000..04679ba623f
--- /dev/null
+++ b/templates/module/process/template_module_process.yaml
@@ -0,0 +1,332 @@
+zabbix_export:
+ version: '6.4'
+ date: '2022-10-28T08:41:56Z'
+ template_groups:
+ -
+ uuid: 57b7ae836ca64446ba2c296389c009b7
+ name: Templates/Modules
+ templates:
+ -
+ uuid: 0f6889282f6048e2b1370e569e578985
+ template: 'OS processes by Zabbix agent'
+ name: 'OS processes by Zabbix agent'
+ description: |
+ Get processes metrics using item proc.get by Zabbix agent.
+
+ You can discuss this template or leave feedback on our forum https://www.zabbix.com/forum/zabbix-suggestions-and-feedback
+
+ Template tooling version used: 0.42
+ groups:
+ -
+ name: Templates/Modules
+ items:
+ -
+ uuid: 803390429cf949d3b8439dd5dd71c706
+ name: 'OS: Get process summary'
+ key: 'proc.get[,,,summary]'
+ history: '0'
+ trends: '0'
+ value_type: TEXT
+ description: 'The summary of data metrics for all processes.'
+ tags:
+ -
+ tag: component
+ value: raw
+ discovery_rules:
+ -
+ uuid: 7c0e8b719d0e464f92ee42a3da75b682
+ name: 'Processes discovery'
+ type: DEPENDENT
+ key: custom.proc.discovery
+ delay: '0'
+ filter:
+ evaltype: AND
+ conditions:
+ -
+ macro: '{#VMEM}'
+ value: '-1'
+ operator: NOT_MATCHES_REGEX
+ formulaid: C
+ -
+ macro: '{#NAME}'
+ value: '{$PROC.NAME.MATCHES}'
+ formulaid: A
+ -
+ macro: '{#NAME}'
+ value: '{$PROC.NAME.NOT_MATCHES}'
+ operator: NOT_MATCHES_REGEX
+ formulaid: B
+ description: 'Discovery of OS summary processes.'
+ item_prototypes:
+ -
+ uuid: 2e9b31e2b47741f4b35c5d15f33378ea
+ name: 'Process [{#NAME}]: Get data'
+ type: DEPENDENT
+ key: 'custom.proc.get[{#NAME}]'
+ delay: '0'
+ history: 0d
+ trends: '0'
+ value_type: TEXT
+ description: 'Summary metrics collected during the process {#NAME}.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - '$.[?(@["name"]=="{#NAME}")].first()'
+ error_handler: CUSTOM_VALUE
+ error_handler_params: 'Failed to retrieve process {#NAME} data'
+ master_item:
+ key: 'proc.get[,,,summary]'
+ tags:
+ -
+ tag: component
+ value: raw
+ -
+ tag: process
+ value: '{#NAME}'
+ -
+ uuid: 822ffda22eb042b89fc50b212aab133f
+ name: 'Process [{#NAME}]: Size of locked memory'
+ type: DEPENDENT
+ key: 'custom.proc.mem.locked[{#NAME}]'
+ delay: '0'
+ history: 7d
+ value_type: FLOAT
+ units: B
+ description: 'The size of locked memory {#NAME}.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.lck
+ error_handler: DISCARD_VALUE
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: memory
+ -
+ tag: process
+ value: '{#NAME}'
+ -
+ uuid: 0bb7d924b8814c42a494d8a3baf48a59
+ name: 'Process [{#NAME}]: Number of running processes'
+ type: DEPENDENT
+ key: 'custom.proc.num[{#NAME}]'
+ delay: '0'
+ history: 7d
+ description: 'The number of running processes {#NAME}.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.processes
+ error_handler: CUSTOM_VALUE
+ error_handler_params: '0'
+ -
+ type: DISCARD_UNCHANGED_HEARTBEAT
+ parameters:
+ - 1h
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: system
+ -
+ tag: process
+ value: '{#NAME}'
+ trigger_prototypes:
+ -
+ uuid: 66294f983a134a1e81165878f30d3ebc
+ expression: 'last(/OS processes by Zabbix agent/custom.proc.num[{#NAME}])=0'
+ name: 'Process [{#NAME}]: is not running'
+ priority: HIGH
+ manual_close: 'YES'
+ tags:
+ -
+ tag: scope
+ value: availability
+ -
+ uuid: abccdac17c7e4b549fcfe70ceeedeb9b
+ name: 'Process [{#NAME}]: Number of page faults'
+ type: DEPENDENT
+ key: 'custom.proc.page[{#NAME}]'
+ delay: '0'
+ history: 7d
+ description: 'The number of page faults {#NAME}.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.page_faults
+ error_handler: DISCARD_VALUE
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: system
+ -
+ tag: process
+ value: '{#NAME}'
+ -
+ uuid: 4ffd202fb6044b819f6f28dc866ca8f1
+ name: 'Process [{#NAME}]: Memory usage, %'
+ type: DEPENDENT
+ key: 'custom.proc.pmem[{#NAME}]'
+ delay: '0'
+ history: 7d
+ value_type: FLOAT
+ units: '%'
+ description: 'The percentage of real memory used by the process {#NAME}.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.pmem
+ error_handler: DISCARD_VALUE
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: memory
+ -
+ tag: process
+ value: '{#NAME}'
+ -
+ uuid: 7e573e38bce04167bc37712c0a3e2194
+ name: 'Process [{#NAME}]: Memory usage (rss)'
+ type: DEPENDENT
+ key: 'custom.proc.rss[{#NAME}]'
+ delay: '0'
+ history: 7d
+ value_type: FLOAT
+ units: B
+ description: 'The summary of Resident Set Size (RSS) memory used by the process {#NAME} in bytes.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.rss
+ error_handler: DISCARD_VALUE
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: memory
+ -
+ tag: process
+ value: '{#NAME}'
+ -
+ uuid: 12370d3b25024d2189cddba8d3b23938
+ name: 'Process [{#NAME}]: Swap space used'
+ type: DEPENDENT
+ key: 'custom.proc.swap[{#NAME}]'
+ delay: '0'
+ history: 7d
+ value_type: FLOAT
+ units: B
+ description: 'The swap space used by {#NAME}.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.swap
+ error_handler: DISCARD_VALUE
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: memory
+ -
+ tag: process
+ value: '{#NAME}'
+ -
+ uuid: a7265ca1b1d2463294e26d80fe075639
+ name: 'Process [{#NAME}]: Number of threads'
+ type: DEPENDENT
+ key: 'custom.proc.thread[{#NAME}]'
+ delay: '0'
+ history: 7d
+ description: 'The number of threads {#NAME}.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.threads
+ error_handler: DISCARD_VALUE
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: system
+ -
+ tag: process
+ value: '{#NAME}'
+ -
+ uuid: c1b9b1d8f28947589e46041690899100
+ name: 'Process [{#NAME}]: Memory usage (vsize)'
+ type: DEPENDENT
+ key: 'custom.proc.vmem[{#NAME}]'
+ delay: '0'
+ history: 7d
+ value_type: FLOAT
+ units: B
+ description: 'The summary of virtual memory used by process {#NAME} in bytes.'
+ preprocessing:
+ -
+ type: JSONPATH
+ parameters:
+ - $.vsize
+ error_handler: DISCARD_VALUE
+ master_item:
+ key: 'custom.proc.get[{#NAME}]'
+ tags:
+ -
+ tag: component
+ value: memory
+ -
+ tag: process
+ value: '{#NAME}'
+ graph_prototypes:
+ -
+ uuid: b8f5b539152445fdbadbfba92adad1bf
+ name: 'Process [{#NAME}]: Memory usage[{#NAME}]'
+ graph_items:
+ -
+ drawtype: BOLD_LINE
+ color: 1A7C11
+ item:
+ host: 'OS processes by Zabbix agent'
+ key: 'custom.proc.vmem[{#NAME}]'
+ -
+ sortorder: '1'
+ drawtype: BOLD_LINE
+ color: 2774A4
+ item:
+ host: 'OS processes by Zabbix agent'
+ key: 'custom.proc.rss[{#NAME}]'
+ master_item:
+ key: 'proc.get[,,,summary]'
+ lld_macro_paths:
+ -
+ lld_macro: '{#NAME}'
+ path: $.name
+ -
+ lld_macro: '{#VMEM}'
+ path: $.vsize
+ macros:
+ -
+ macro: '{$PROC.NAME.MATCHES}'
+ value: '<CHANGE VALUE>'
+ description: 'This macro is used in the discovery of processes. It can be overridden on a host-level or on a linked template-level.'
+ -
+ macro: '{$PROC.NAME.NOT_MATCHES}'
+ value: '<CHANGE VALUE>'
+ description: 'This macro is used in the discovery of processes. It can be overridden on a host-level or on a linked template-level.'
diff --git a/tests/libs/zbxjson/Makefile.am b/tests/libs/zbxjson/Makefile.am
index d5190957c97..5f770afaf0f 100644
--- a/tests/libs/zbxjson/Makefile.am
+++ b/tests/libs/zbxjson/Makefile.am
@@ -3,7 +3,7 @@ noinst_PROGRAMS = \
zbx_json_decodevalue \
zbx_json_decodevalue_dyn \
zbx_jsonpath_compile \
- zbx_jsonpath_query
+ zbx_jsonobj_query
JSON_LIBS = \
$(top_srcdir)/tests/libzbxmocktest.a \
@@ -104,22 +104,22 @@ endif
zbx_jsonpath_compile_CFLAGS = -I@top_srcdir@/tests
-# zbx_jsonpath_query
+# zbx_jsonobj_query
-zbx_jsonpath_query_SOURCES = \
- zbx_jsonpath_query.c \
+zbx_jsonobj_query_SOURCES = \
+ zbx_jsonobj_query.c \
../../zbxmocktest.h
-zbx_jsonpath_query_LDADD = $(JSON_LIBS)
+zbx_jsonobj_query_LDADD = $(JSON_LIBS)
if SERVER
-zbx_jsonpath_query_LDADD += @SERVER_LIBS@
-zbx_jsonpath_query_LDFLAGS = @SERVER_LDFLAGS@
+zbx_jsonobj_query_LDADD += @SERVER_LIBS@
+zbx_jsonobj_query_LDFLAGS = @SERVER_LDFLAGS@
else
if PROXY
-zbx_jsonpath_query_LDADD += @PROXY_LIBS@
-zbx_jsonpath_query_LDFLAGS = @PROXY_LDFLAGS@
+zbx_jsonobj_query_LDADD += @PROXY_LIBS@
+zbx_jsonobj_query_LDFLAGS = @PROXY_LDFLAGS@
endif
endif
-zbx_jsonpath_query_CFLAGS = -I@top_srcdir@/tests
+zbx_jsonobj_query_CFLAGS = -I@top_srcdir@/tests
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.c b/tests/libs/zbxjson/zbx_jsonobj_query.c
index 6e560a6a494..25349d6932e 100644
--- a/tests/libs/zbxjson/zbx_jsonpath_query.c
+++ b/tests/libs/zbxjson/zbx_jsonobj_query.c
@@ -51,26 +51,13 @@ static void check_indefinite_path_result(zbx_mock_handle_t handle, const char *r
zbx_mock_assert_json_eq("Indefinite query result", expected_output, returned_output);
}
-void zbx_mock_test_entry(void **state)
+static void test_query(zbx_jsonobj_t *obj, const char *path, int expected_ret)
{
- const char *data, *path;
- struct zbx_json_parse jp;
char *output = NULL;
- int expected_ret, returned_ret;
+ int returned_ret;
zbx_mock_handle_t handle;
- ZBX_UNUSED(state);
-
- /* reset json error to check if compilation will set it */
- zbx_set_json_strerror("%s", "");
-
- data = zbx_mock_get_parameter_string("in.data");
- if (FAIL == zbx_json_open(data, &jp))
- fail_msg("Invalid json data: %s", zbx_json_strerror());
-
- path = zbx_mock_get_parameter_string("in.path");
- returned_ret = zbx_jsonpath_query(&jp, path, &output);
- expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return"));
+ returned_ret = zbx_jsonobj_query(obj, path, &output);
if (FAIL == returned_ret)
printf("\tzbx_jsonpath_query() failed with: %s\n", zbx_json_strerror());
@@ -97,4 +84,31 @@ void zbx_mock_test_entry(void **state)
zbx_mock_assert_str_ne("tzbx_jsonpath_query() error", "", zbx_json_strerror());
zbx_free(output);
+
+}
+
+void zbx_mock_test_entry(void **state)
+{
+ const char *data, *path;
+ int expected_ret;
+ zbx_jsonobj_t obj;
+
+ ZBX_UNUSED(state);
+
+ /* reset json error to check if compilation will set it */
+ zbx_set_json_strerror("%s", "");
+
+ data = zbx_mock_get_parameter_string("in.data");
+ if (FAIL == zbx_jsonobj_open(data, &obj))
+ fail_msg("Invalid json data: %s", zbx_json_strerror());
+
+ path = zbx_mock_get_parameter_string("in.path");
+ expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return"));
+
+ test_query(&obj, path, expected_ret);
+
+ /* query second time to check index reuse */
+ test_query(&obj, path, expected_ret);
+
+ zbx_jsonobj_clear(&obj);
}
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml b/tests/libs/zbxjson/zbx_jsonobj_query.inc.yaml
index 456f49ebe28..456f49ebe28 100644
--- a/tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml
+++ b/tests/libs/zbxjson/zbx_jsonobj_query.inc.yaml
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.yaml b/tests/libs/zbxjson/zbx_jsonobj_query.yaml
index a4b784b90d9..7e9aae0044d 100644
--- a/tests/libs/zbxjson/zbx_jsonpath_query.yaml
+++ b/tests/libs/zbxjson/zbx_jsonobj_query.yaml
@@ -37,7 +37,7 @@ out:
return: SUCCEED
---
test case: Query $.filters.price
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters.price
@@ -46,7 +46,7 @@ out:
value: 10
---
test case: Query $.filters.category
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters.category
@@ -55,7 +55,7 @@ out:
value: fiction
---
test case: Query $.filters.id
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters.id
@@ -63,7 +63,7 @@ out:
return: SUCCEED
---
test case: Query $.books[1].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[1].title
@@ -72,7 +72,7 @@ out:
value: Sword of Honour
---
test case: Query $['closed message']
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $['closed message']
@@ -81,7 +81,7 @@ out:
value: Store is closed
---
test case: Query $.books[-1].author
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[-1].author
@@ -90,7 +90,7 @@ out:
value: J. R. R. Tolkien
---
test case: Query $.filters
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters
@@ -104,7 +104,7 @@ out:
}
---
test case: Query $.books.length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books.length()
@@ -113,7 +113,7 @@ out:
value: 4
---
test case: Query $.tags[:]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:]
@@ -122,7 +122,7 @@ out:
value: '["a", "b", "c", "d", "e" ]'
---
test case: Query $.tags[2:]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[2:]
@@ -131,7 +131,7 @@ out:
value: '["c", "d", "e" ]'
---
test case: Query $.tags[:2]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:2]
@@ -140,7 +140,7 @@ out:
value: '["a", "b"]'
---
test case: Query $.tags[1:4]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[1:4]
@@ -149,7 +149,7 @@ out:
value: '["b", "c", "d"]'
---
test case: Query $.tags[-2:]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[-2:]
@@ -158,7 +158,7 @@ out:
value: '["d", "e"]'
---
test case: Query $.tags[:-3]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:-3]
@@ -167,7 +167,7 @@ out:
value: '["a", "b"]'
---
test case: Query $.tags[:-3].length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.tags[:-3].length()
@@ -176,25 +176,25 @@ out:
value: 2
---
test case: Query $.books[0, 2].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[0, 2].title
out:
return: SUCCEED
- value: '["Sayings of the Century", "Moby Dick"]'
+ value: '["Moby Dick", "Sayings of the Century"]'
---
test case: Query $.books[1]['author', "title"]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[1]['author', "title"]
out:
return: SUCCEED
- value: '["Evelyn Waugh", "Sword of Honour"]'
+ value: '["Sword of Honour", "Evelyn Waugh"]'
---
test case: Query $..id
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..id
@@ -203,16 +203,16 @@ out:
value: '[1, 2, 3, 4]'
---
test case: Query $.services..price
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services..price
out:
return: SUCCEED
- value: '[5, 154.99, 46, 24.5, 99.49]'
+ value: '[154.99, 5, 46, 24.5, 99.49]'
---
test case: Query $.books[?(@.id == 1 + 1)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 1 + 1)].title
@@ -221,7 +221,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 4 / 2)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 4 / 2)].title
@@ -230,7 +230,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 7 - 5)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 7 - 5)].title
@@ -239,7 +239,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 0.4 * 5)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 0.4 * 5)].title
@@ -248,7 +248,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 4 - 0.4 * 5)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 4 - 0.4 * 5)].title
@@ -257,7 +257,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == -0.4 * 5 + 4)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == -0.4 * 5 + 4)].title
@@ -266,7 +266,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 0.4 * (-5) + 4)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 0.4 * (-5) + 4)].title
@@ -275,7 +275,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 2 || @.id == 4)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2 || @.id == 4)].title
@@ -284,7 +284,7 @@ out:
value: '["Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.id == 2 && 2 * ((1 + 3) / 2 + 3) == 10)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2 && 2 * ((1 + 3) / 2 + 3) == 10)].title
@@ -293,7 +293,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.id == 2 == 1)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2 == 1)].title
@@ -302,7 +302,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(!(@.id == 2))].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(!(@.id == 2))].title
@@ -311,7 +311,7 @@ out:
value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.id != 2)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id != 2)].title
@@ -320,7 +320,7 @@ out:
value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.title =~ " of ")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.title =~ " of ")].title
@@ -329,7 +329,7 @@ out:
value: '["Sayings of the Century", "Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.price > 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price > 12.99)].title
@@ -338,7 +338,7 @@ out:
value: '["The Lord of the Rings"]'
---
test case: Query $.books[?(@.price >= 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price >= 12.99)].title
@@ -347,7 +347,7 @@ out:
value: '["Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.price < 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price < 12.99)].title
@@ -356,7 +356,7 @@ out:
value: '["Sayings of the Century", "Moby Dick"]'
---
test case: Query $.books[?(@.price <= 12.99)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price <= 12.99)].title
@@ -365,7 +365,7 @@ out:
value: '["Sayings of the Century", "Sword of Honour", "Moby Dick"]'
---
test case: Query $.books[?(@.author > "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author > "Herman Melville")].title
@@ -374,7 +374,7 @@ out:
value: '["Sayings of the Century", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.author >= "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author >= "Herman Melville")].title
@@ -383,7 +383,7 @@ out:
value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.author < "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author < "Herman Melville")].title
@@ -392,7 +392,7 @@ out:
value: '["Sword of Honour"]'
---
test case: Query $.books[?(@.author <= "Herman Melville")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.author <= "Herman Melville")].title
@@ -401,7 +401,7 @@ out:
value: '["Sword of Honour", "Moby Dick"]'
---
test case: Query $.books[?(@.price > $.filters.price)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price > $.filters.price)].title
@@ -410,7 +410,7 @@ out:
value: '["Sword of Honour", "The Lord of the Rings"]'
---
test case: Query $.books[?(@.category == $.filters.category)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category == $.filters.category)].title
@@ -419,7 +419,7 @@ out:
value: '["Sword of Honour","Moby Dick","The Lord of the Rings"]'
---
test case: Query $.books[?(@.category != $.filters.category)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category != $.filters.category)].title
@@ -428,7 +428,7 @@ out:
value: '["Sayings of the Century"]'
---
test case: Query $..[?(@.id)]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..[?(@.id)]
@@ -469,7 +469,7 @@ out:
]
---
test case: Query $.services..[?(@.price > 50)].description
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services..[?(@.price > 50)].description
@@ -478,7 +478,7 @@ out:
value: '["Printing and assembling book in A5 format", "Rebinding torn book"]'
---
test case: Query $..id.length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..id.length()
@@ -487,7 +487,7 @@ out:
value: 4
---
test case: Query $.books[?(@.price >= 12.99)].length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.price >= 12.99)].length()
@@ -496,7 +496,7 @@ out:
value: 2
---
test case: Query $.books[?(@.id == 2)].title.first()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.id == 2)].title.first()
@@ -505,7 +505,7 @@ out:
value: Sword of Honour
---
test case: Query $..tags.first().length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..tags.first().length()
@@ -514,7 +514,7 @@ out:
value: 5
---
test case: Query $.bad.path.first().length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.bad.path.first().length()
@@ -522,7 +522,7 @@ out:
return: FAIL
---
test case: Query $.[?(@.ElementName == "test")].values.first().length()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.[?(@.ElementName == "test")].values.first().length()
@@ -562,7 +562,7 @@ out:
value: a
---
test case: Query $.books[*].price.min()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[*].price.min()
@@ -571,7 +571,7 @@ out:
value: 8.95
---
test case: Query $..price.max()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..price.max()
@@ -580,7 +580,7 @@ out:
value: 154.99
---
test case: Query $.books[?(@.category == "fiction")].price.avg()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category == "fiction")].price.avg()
@@ -589,7 +589,7 @@ out:
value: 14.99
---
test case: Query $.books[?(@.category == $.filters.xyz)].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category == $.filters.xyz)].title
@@ -597,7 +597,7 @@ out:
return: SUCCEED
---
test case: Query $.filters['no filters']
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.filters['no filters']
@@ -606,16 +606,16 @@ out:
value: no "filters"
---
test case: Query $.services[?(@.active=="true")].servicegroup
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services[?(@.active=="true")].servicegroup
out:
return: SUCCEED
- value: '[1000,1001]'
+ value: '[1001,1000]'
---
test case: Query $.services[?(@.active=="false")].servicegroup
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services[?(@.active=="false")].servicegroup
@@ -624,7 +624,7 @@ out:
value: '[1002]'
---
test case: Query $.books[?(@.title =~ "[a-z")].title
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.title =~ "[a-z")].title
@@ -632,7 +632,7 @@ out:
return: FAIL
---
test case: $..books[?(!@.isbn)]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..books[?(!@.isbn)]
@@ -657,7 +657,7 @@ out:
]
---
test case: $..books[?(@.isbn)]
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $..books[?(@.isbn)]
@@ -684,7 +684,7 @@ out:
]
---
test case: Query $.books[*].price.sum()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[*].price.sum()
@@ -725,25 +725,25 @@ out:
values: '[2]'
---
test case: Query $.*~
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.*~
out:
return: SUCCEED
- value: '["books","services","filters","closed message","tags"]'
+ value: '["filters", "services", "tags", "books", "closed message"]'
---
test case: Query $.*~.first()
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.*~.first()
out:
return: SUCCEED
- value: 'books'
+ value: 'filters'
---
test case: Query $.services[?(@.servicegroup=="1002")]~
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.services[?(@.servicegroup=="1002")]~
@@ -752,11 +752,49 @@ out:
value: '["restoration"]'
---
test case: Query $.books[?(@.category=="fiction")]~
-include: &include zbx_jsonpath_query.inc.yaml
+include: &include zbx_jsonobj_query.inc.yaml
in:
data: *include
path: $.books[?(@.category=="fiction")]~
out:
return: SUCCEED
value: '["1","2","3"]'
+---
+test case: Query $.books[?(@.category=="reference")].price
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.category=="reference")].price
+out:
+ return: SUCCEED
+ value: '[8.95]'
+---
+test case: Query $.books[1,1].title
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1,1].title
+out:
+ return: SUCCEED
+ value: Sword of Honour
+---
+test case: Query $.books[1:2].title
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1:2].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[1]["title","title"]
+include: &include zbx_jsonobj_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1].["title","title"]
+out:
+ return: SUCCEED
+ value: Sword of Honour
...
+
+
diff --git a/tests/libs/zbxjson/zbx_jsonpath_compile.c b/tests/libs/zbxjson/zbx_jsonpath_compile.c
index e98a2c7827c..0caab92de81 100644
--- a/tests/libs/zbxjson/zbx_jsonpath_compile.c
+++ b/tests/libs/zbxjson/zbx_jsonpath_compile.c
@@ -54,7 +54,7 @@ static void jsonpath_token_print(char **data, size_t *data_alloc, size_t *data_o
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
case ZBX_JSONPATH_TOKEN_CONST_STR:
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- zbx_strcpy_alloc(data, data_alloc, data_offset, token->data);
+ zbx_strcpy_alloc(data, data_alloc, data_offset, token->text);
break;
case ZBX_JSONPATH_TOKEN_PAREN_LEFT:
zbx_strcpy_alloc(data, data_alloc, data_offset, "(");
diff --git a/tests/libs/zbxsysinfo/Makefile.am b/tests/libs/zbxsysinfo/Makefile.am
index 720ce4f31ff..670be6d8d55 100644
--- a/tests/libs/zbxsysinfo/Makefile.am
+++ b/tests/libs/zbxsysinfo/Makefile.am
@@ -119,11 +119,11 @@ check_service_test_LDADD = \
$(top_srcdir)/src/libs/zbxthreads/libzbxthreads.a \
$(top_srcdir)/src/libs/zbxhash/libzbxhash.a \
$(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
- $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
$(top_srcdir)/src/libs/zbxmutexs/libzbxmutexs.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
$(top_srcdir)/src/libs/zbxvariant/libzbxvariant.a \
$(top_srcdir)/src/libs/zbxhttp/libzbxhttp.a \
@@ -238,6 +238,7 @@ check_key_access_rules_SOURCES = \
check_key_access_rules_LDADD = $(COMMON_LIB_FILES) \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo_http.a \
$(top_srcdir)/src/libs/zbxhttp/libzbxhttp.a
diff --git a/tests/zabbix_server/poller/Makefile.am b/tests/zabbix_server/poller/Makefile.am
index 5531959151d..31f478fa1bb 100644
--- a/tests/zabbix_server/poller/Makefile.am
+++ b/tests/zabbix_server/poller/Makefile.am
@@ -10,7 +10,6 @@ POLLER_LIBS = \
$(top_srcdir)/tests/libzbxmocktest.a \
$(top_srcdir)/tests/libzbxmockdata.a \
$(top_srcdir)/src/libs/zbxsysinfo/libzbxserversysinfo.a \
- $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
$(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
$(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo.a \
@@ -24,6 +23,7 @@ POLLER_LIBS = \
$(top_srcdir)/src/libs/zbxmutexs/libzbxmutexs.a \
$(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_srcdir)/src/libs/zbxhash/libzbxhash.a \
$(top_srcdir)/src/libs/zbxhttp/libzbxhttp.a \
$(top_srcdir)/src/libs/zbxvariant/libzbxvariant.a \
diff --git a/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml b/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
index ef12178fa0a..640fcbef4b7 100644
--- a/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
+++ b/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
@@ -965,7 +965,7 @@ in:
out:
return: SUCCEED
value: |-
- {"b":[1, 2, 3]}
+ {"b":[1,2,3]}
---
test case: jsonpath5
in:
@@ -980,7 +980,7 @@ in:
out:
return: SUCCEED
value: |-
- [1, 2, 3]
+ [1,2,3]
---
test case: jsonpath6
in:
@@ -1008,7 +1008,7 @@ in:
params: $.a['b c']
out:
return: SUCCEED
- value: '["one", "two", "three"]'
+ value: '["one","two","three"]'
---
test case: jsonpath8
in:
diff --git a/ui/app/controllers/CControllerLatestView.php b/ui/app/controllers/CControllerLatestView.php
index d31f904b9a4..8c98c1b93df 100644
--- a/ui/app/controllers/CControllerLatestView.php
+++ b/ui/app/controllers/CControllerLatestView.php
@@ -200,6 +200,7 @@ class CControllerLatestView extends CControllerLatest {
'sort_order' => $sort_order,
'view_curl' => $view_url,
'paging' => $paging,
+ 'uncheck' => $this->hasInput('filter_reset'),
'config' => [
'hk_trends' => CHousekeepingHelper::get(CHousekeepingHelper::HK_TRENDS),
'hk_trends_global' => CHousekeepingHelper::get(CHousekeepingHelper::HK_TRENDS_GLOBAL),
diff --git a/ui/app/views/js/monitoring.latest.view.js.php b/ui/app/views/js/monitoring.latest.view.js.php
index e727894273d..0171c31ec34 100644
--- a/ui/app/views/js/monitoring.latest.view.js.php
+++ b/ui/app/views/js/monitoring.latest.view.js.php
@@ -71,11 +71,11 @@
this.filter.on(TABFILTER_EVENT_URLSET, () => {
this.reloadPartialAndTabCounters();
+ chkbxRange.clearSelectedOnFilterChange();
if (this.active_filter !== this.filter._active_item) {
this.active_filter = this.filter._active_item;
chkbxRange.checkObjectAll(chkbxRange.pageGoName, false);
- chkbxRange.clearSelectedOnFilterChange();
}
});
diff --git a/ui/app/views/js/monitoring.problem.view.js.php b/ui/app/views/js/monitoring.problem.view.js.php
index 931f317fb28..4f854d9976a 100644
--- a/ui/app/views/js/monitoring.problem.view.js.php
+++ b/ui/app/views/js/monitoring.problem.view.js.php
@@ -95,11 +95,11 @@
this.refreshResults();
this.refreshCounters();
+ chkbxRange.clearSelectedOnFilterChange();
if (this.active_filter !== this.filter._active_item) {
this.active_filter = this.filter._active_item;
chkbxRange.checkObjectAll(chkbxRange.pageGoName, false);
- chkbxRange.clearSelectedOnFilterChange();
}
});
diff --git a/ui/app/views/monitoring.latest.view.php b/ui/app/views/monitoring.latest.view.php
index 337ff26bf06..d95fdaf18a8 100644
--- a/ui/app/views/monitoring.latest.view.php
+++ b/ui/app/views/monitoring.latest.view.php
@@ -35,6 +35,10 @@ $this->includeJsFile('monitoring.latest.view.js.php');
$this->enableLayoutModes();
$web_layout_mode = $this->getLayoutMode();
+if ($data['uncheck']) {
+ uncheckTableRows('latest');
+}
+
$widget = (new CWidget())
->setTitle(_('Latest data'))
->setWebLayoutMode($web_layout_mode)
diff --git a/ui/js/widgets/class.widget.js b/ui/js/widgets/class.widget.js
index e366479402d..2b5456d2f41 100644
--- a/ui/js/widgets/class.widget.js
+++ b/ui/js/widgets/class.widget.js
@@ -122,6 +122,8 @@ class CWidget extends CBaseComponent {
this._update_retry_sec = 3;
this._show_preloader_asap = true;
this._resizable_handles = [];
+
+ this._hide_preloader_animation_frame = null;
}
// Logical state control methods.
@@ -816,15 +818,38 @@ class CWidget extends CBaseComponent {
}
_showPreloader() {
+ // Fixed Safari 16 bug: removing preloader classes on animation frame to ensure removal of icons.
+
+ if (this._hide_preloader_animation_frame !== null) {
+ cancelAnimationFrame(this._hide_preloader_animation_frame);
+ this._hide_preloader_animation_frame = null;
+ }
+
this._content_body.classList.add('is-loading');
this._content_body.classList.remove('is-loading-fadein', 'delayed-15s');
}
_hidePreloader() {
- this._content_body.classList.remove('is-loading', 'is-loading-fadein', 'delayed-15s');
+ // Fixed Safari 16 bug: removing preloader classes on animation frame to ensure removal of icons.
+
+ if (this._hide_preloader_animation_frame !== null) {
+ return;
+ }
+
+ this._hide_preloader_animation_frame = requestAnimationFrame(() => {
+ this._content_body.classList.remove('is-loading', 'is-loading-fadein', 'delayed-15s');
+ this._hide_preloader_animation_frame = null;
+ });
}
_schedulePreloader() {
+ // Fixed Safari 16 bug: removing preloader classes on animation frame to ensure removal of icons.
+
+ if (this._hide_preloader_animation_frame !== null) {
+ cancelAnimationFrame(this._hide_preloader_animation_frame);
+ this._hide_preloader_animation_frame = null;
+ }
+
this._content_body.classList.add('is-loading', 'is-loading-fadein', 'delayed-15s');
}
diff --git a/ui/tests/include/web/CPage.php b/ui/tests/include/web/CPage.php
index cc2abc0f9fa..eab84952c98 100644
--- a/ui/tests/include/web/CPage.php
+++ b/ui/tests/include/web/CPage.php
@@ -219,7 +219,6 @@ class CPage {
self::$cookie = [
'name' => 'zbx_session',
'value' => base64_encode(json_encode($data)),
- 'domain' => parse_url(PHPUNIT_URL, PHP_URL_HOST),
'path' => rtrim(substr($path, 0, strrpos($path, '/')), '/')
];
diff --git a/ui/tests/selenium/dashboard/testDashboardPages.php b/ui/tests/selenium/dashboard/testDashboardPages.php
index cc0165bec87..4ccbca0c1cb 100644
--- a/ui/tests/selenium/dashboard/testDashboardPages.php
+++ b/ui/tests/selenium/dashboard/testDashboardPages.php
@@ -456,6 +456,7 @@ class testDashboardPages extends CWebTest {
$dashboard->addPage();
$page_dialog = COverlayDialogElement::find()->waitUntilReady()->one();
$page_dialog->query('name:dashboard_page_properties_form')->asForm()->one()->fill($data['fields'])->submit();
+ $page_dialog->ensureNotPresent();
$dashboard->waitUntilReady();
$title = $data['fields']['Name'];
diff --git a/ui/tests/selenium/dashboard/testDashboardTriggerOverviewWidget.php b/ui/tests/selenium/dashboard/testDashboardTriggerOverviewWidget.php
index 6b424d030c1..658d2921f36 100644
--- a/ui/tests/selenium/dashboard/testDashboardTriggerOverviewWidget.php
+++ b/ui/tests/selenium/dashboard/testDashboardTriggerOverviewWidget.php
@@ -415,21 +415,6 @@ class testDashboardTriggerOverviewWidget extends CWebTest {
[
[
'fields' => [
- 'Name' => 'Filter triggers by tag with default operator'
- ],
- 'tags' => [
- ['name' => 'server', 'operator' => 'Contains', 'value' => 'sel']
- ],
- 'expected' => [
- 'Host for triggers filtering' => [
- 'Inheritance trigger with tags'
- ]
- ]
- ]
- ],
- [
- [
- 'fields' => [
'Name' => 'Filter triggers by 2 tags with Or operator',
'Tags' => 'Or'
],
@@ -795,7 +780,6 @@ class testDashboardTriggerOverviewWidget extends CWebTest {
$widget_name = (array_key_exists('fields', $data)) ? $data['fields']['Name'] : 'Trigger overview';
$widget = $dashboard->getWidget($widget_name);
- $widget->query('xpath://div[contains(@class, "is-loading")]')->waitUntilNotPresent();
$dashboard->save();
$this->assertMessage(TEST_GOOD, 'Dashboard updated');
diff --git a/ui/tests/selenium/testInheritanceHostPrototype.php b/ui/tests/selenium/testInheritanceHostPrototype.php
index 73a40bb3c99..57de3f86508 100644
--- a/ui/tests/selenium/testInheritanceHostPrototype.php
+++ b/ui/tests/selenium/testInheritanceHostPrototype.php
@@ -456,7 +456,7 @@ class testInheritanceHostPrototype extends CLegacyWebTest {
if (array_key_exists('template', $data)) {
$this->zbxTestClickButtonMultiselect('add_templates_');
$this->zbxTestLaunchOverlayDialog('Templates');
- COverlayDialogElement::find()->one()->setDataContext('Templates');
+ COverlayDialogElement::find()->waitUntilReady()->one()->setDataContext('Templates');
$this->zbxTestClickLinkTextWait($data['template']);
}